diff options
author | Sven Gothel <[email protected]> | 2010-10-29 03:58:33 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2010-10-29 03:58:33 +0200 |
commit | 7e606ef39fa9d73cc7306cc0027989bc7704708d (patch) | |
tree | 9dad08525d8bc33195194a010dc31f3ea4a267c8 /src | |
parent | 27530775e22bd04242a91a8f12f8c6c930c398b9 (diff) |
Proper X11 Display Closing
X11Util:
Removed TLS semantics, since TLS name -> dpy mapping is erroneous at this point.
Added lists for open connections (for optional later shutdown).
AbstractGraphicsDevice interface and implementations:
Adding 'close()' method allowing native implementations the ability
to close the native resource, ie X11GraphicsDevice.
This becomes necessary for 'on the fly' created X11 Display connections,
ie in X11AWTGLXGraphicsConfigurationFactory, which enables closing.
Utilize 'close' call in use cases: GLCanvas, GLJPanel and AWTCanvas.
Remove active X11 Display creation in X11JAWTWindow,
as a last resort, use the X11SunJDKReflection method.
Used for reference only, not active rendering etc,
mostly for on the fly AWT parenting in NewtFactoryAWT.
However, these 'on the fly' references are erroneous and should be remodelled,
ie passice and active X11GraphicsDevice's ..
Diffstat (limited to 'src')
14 files changed, 271 insertions, 229 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXDrawableFactory.java index 82f57f33e..3d213c54b 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXDrawableFactory.java @@ -236,23 +236,9 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { System.err.println("!!! Screen : "+sharedScreen); } - // may cause JVM SIGSEGV ? - // X11Util.closePendingDisplayConnections(); - sharedResourcesRunner.releaseAndWait(); - if(X11Util.getOpenDisplayConnectionNumber() > 0) { - System.err.println("X11GLXDrawableFactory.shutdown(): Open (no close attempt) X11 Display Connection"); - X11Util.dumpOpenDisplayConnections(); - } - - if(X11Util.getPendingDisplayConnectionNumber()>0) { - System.err.println("X11GLXDrawableFactory.shutdown(): Pending X11 Display Connection"); - X11Util.dumpPendingDisplayConnections(); - } - - // don't close pending XDisplay, since this might be a different thread as the opener - X11Util.shutdown( false, DEBUG ); + X11Util.shutdown( true, DEBUG ); } protected GLDrawableImpl createOnscreenDrawableImpl(NativeSurface target) { diff --git a/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/awt/X11AWTGLXGraphicsConfigurationFactory.java b/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/awt/X11AWTGLXGraphicsConfigurationFactory.java index 225dc25a4..4b5b72cc6 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/awt/X11AWTGLXGraphicsConfigurationFactory.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/awt/X11AWTGLXGraphicsConfigurationFactory.java @@ -83,7 +83,7 @@ public class X11AWTGLXGraphicsConfigurationFactory extends GraphicsConfiguration long displayHandle = X11SunJDKReflection.graphicsDeviceGetDisplay(device); if(0==displayHandle) { - displayHandle = X11Util.createThreadLocalDisplay(null); + displayHandle = X11Util.createDisplay(null); if(DEBUG) { System.err.println("X11AWTGLXGraphicsConfigurationFactory: using a thread local X11 display"); } @@ -91,10 +91,12 @@ public class X11AWTGLXGraphicsConfigurationFactory extends GraphicsConfiguration if(DEBUG) { System.err.println("X11AWTGLXGraphicsConfigurationFactory: using AWT X11 display 0x"+Long.toHexString(displayHandle)); } + String name = X11Util.XDisplayString(displayHandle); + displayHandle = X11Util.createDisplay(name); } ((AWTGraphicsDevice)awtScreen.getDevice()).setSubType(NativeWindowFactory.TYPE_X11, displayHandle); X11GraphicsDevice x11Device = new X11GraphicsDevice(displayHandle); - + x11Device.setCloseDisplay(true); X11GraphicsScreen x11Screen = new X11GraphicsScreen(x11Device, awtScreen.getIndex()); if(DEBUG) { System.err.println("X11AWTGLXGraphicsConfigurationFactory: made "+x11Screen); diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index c165a4833..d2a20f467 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -49,6 +49,7 @@ import com.jogamp.opengl.impl.*; import java.awt.Canvas; import java.awt.Color; import java.awt.Component; +import java.awt.EventQueue; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.GraphicsConfiguration; @@ -328,6 +329,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { // Workaround for termination issues with applets -- // sun.applet.AppletPanel should probably be performing the // remove() call on the EDT rather than on its own thread + // Hint: User should run remove from EDT. if (ThreadingImpl.isAWTMode() && Thread.holdsLock(getTreeLock())) { // The user really should not be invoking remove() from this @@ -347,6 +349,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { animator.resume(); } } + if(!regenerate) { + disposeAbstractGraphicsDeviceAction.run(); + } if(DEBUG) { System.err.println("dispose("+regenerate+") - stop"); @@ -401,6 +406,10 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { <B>Overrides:</B> <DL><DD><CODE>addNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */ public void addNotify() { + if(DEBUG) { + Exception ex1 = new Exception(Thread.currentThread().getName()+" - Info: addNotify - start"); + ex1.printStackTrace(); + } super.addNotify(); if (!Beans.isDesignTime()) { disableBackgroundErase(); @@ -419,8 +428,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { try { awtConfig = chooseGraphicsConfiguration(capabilities, chooser, device); if(DEBUG) { - Exception e = new Exception("Info: Created Config: "+awtConfig); - e.printStackTrace(); + System.err.println(Thread.currentThread().getName()+" - Created Config: "+awtConfig); } if(null!=awtConfig) { // update .. @@ -444,21 +452,25 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { } if(DEBUG) { - System.err.println("Created Drawable: "+drawable); + System.err.println(Thread.currentThread().getName()+" - Created Drawable: "+drawable); } } + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - Info: addNotify - end"); + } } - /** Overridden to track when this component is removed from a + /** <p>Overridden to track when this component is removed from a container. Subclasses which override this method must call super.removeNotify() in their removeNotify() method in order to - function properly. <P> - + function properly. </p> + <p>User shall not call this method outside of EDT, read the AWT/Swing specs + about this.</p> <B>Overrides:</B> <DL><DD><CODE>removeNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */ public void removeNotify() { if(DEBUG) { - Exception ex1 = new Exception("Info: removeNotify - start"); + Exception ex1 = new Exception(Thread.currentThread().getName()+" - Info: removeNotify - start"); ex1.printStackTrace(); } @@ -473,7 +485,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { } } if(DEBUG) { - System.err.println("Info: removeNotify - end"); + System.err.println(Thread.currentThread().getName()+" - Info: removeNotify - end"); } } @@ -609,14 +621,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { } } - private boolean disposeRegenerate; - private DisposeAction disposeAction = new DisposeAction(this); - class DisposeAction implements Runnable { - private GLCanvas canvas; - public DisposeAction(GLCanvas canvas) { - this.canvas = canvas; - } public void run() { drawableHelper.dispose(GLCanvas.this); @@ -632,7 +637,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { if(disposeRegenerate) { // recreate GLDrawable to reflect it's new graphics configuration - drawable = GLDrawableFactory.getFactory(glProfile).createGLDrawable(NativeWindowFactory.getNativeWindow(canvas, awtConfig)); + drawable = GLDrawableFactory.getFactory(glProfile).createGLDrawable(NativeWindowFactory.getNativeWindow(GLCanvas.this, awtConfig)); if(DEBUG) { System.err.println("GLCanvas.dispose(true): new drawable: "+drawable); } @@ -643,6 +648,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { } } } + private boolean disposeRegenerate; + private DisposeAction disposeAction = new DisposeAction(); private DisposeOnEventDispatchThreadAction disposeOnEventDispatchThreadAction = new DisposeOnEventDispatchThreadAction(); @@ -653,6 +660,25 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { } } + class DisposeAbstractGraphicsDeviceAction implements Runnable { + public void run() { + AbstractGraphicsConfiguration aconfig = (null!=awtConfig) ? awtConfig.getNativeGraphicsConfiguration() : null; + AbstractGraphicsScreen ascreen = (null!=aconfig) ? aconfig.getScreen() : null; + AbstractGraphicsDevice adevice = (null!=ascreen) ? ascreen.getDevice() : null; + if(null!=adevice) { + String adeviceMsg=null; + if(DEBUG) { + adeviceMsg = adevice.toString(); + } + boolean closed = adevice.close(); + if(DEBUG) { + System.err.println("GLCanvas.dispose(false): closed GraphicsDevice: "+adeviceMsg+", result: "+closed); + } + } + } + } + DisposeAbstractGraphicsDeviceAction disposeAbstractGraphicsDeviceAction = new DisposeAbstractGraphicsDeviceAction(); + class InitAction implements Runnable { public void run() { drawableHelper.init(GLCanvas.this); diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index 10aeefaf5..b9bbf71c2 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -631,22 +631,34 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable { private DisposeAction disposeAction = new DisposeAction(); class DisposeAction implements Runnable { - public void run() { - updater.dispose(GLJPanel.this); + public void run() { + updater.dispose(GLJPanel.this); - if(null!=disposeContext) { - disposeContext.destroy(); - disposeContext=null; - } - if(null!=disposeDrawable) { - disposeDrawable.setRealized(false); - } - if(disposeRegenerate && null!=disposeDrawable) { - disposeDrawable.setRealized(true); - disposeContext = (GLContextImpl) disposeDrawable.createContext(shareWith); - disposeContext.setSynchronized(true); + if (null != disposeContext) { + disposeContext.destroy(); + disposeContext = null; + } + if (null != disposeDrawable) { + disposeDrawable.setRealized(false); + } + if (null != disposeDrawable) { + if (disposeRegenerate) { + disposeDrawable.setRealized(true); + disposeContext = (GLContextImpl) disposeDrawable.createContext(shareWith); + disposeContext.setSynchronized(true); + } else { + AbstractGraphicsDevice adevice = disposeDrawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration().getScreen().getDevice(); + String adeviceMsg=null; + if(DEBUG) { + adeviceMsg = adevice.toString(); + } + boolean closed = adevice.close(); + if (DEBUG) { + System.err.println("GLJPanel.dispose(false): closed GraphicsDevice: " + adeviceMsg + ", result: " + closed); + } + } + } } - } } private DisposeOnEventDispatchThreadAction disposeOnEventDispatchThreadAction = diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTWindow.java index 00d64b4e4..8ef2ba227 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/JAWTWindow.java @@ -37,12 +37,10 @@ package com.jogamp.nativewindow.impl.jawt; -import com.jogamp.nativewindow.impl.*; import com.jogamp.common.util.locks.RecursiveLock; import java.awt.Component; import java.awt.Window; -import java.awt.GraphicsEnvironment; import javax.media.nativewindow.*; import javax.media.nativewindow.util.Point; import javax.media.nativewindow.util.Rectangle; @@ -69,10 +67,10 @@ public abstract class JAWTWindow implements NativeWindow { protected void init(Component windowObject) throws NativeWindowException { invalidate(); this.component = windowObject; - initNative(); + validateNative(); } - protected abstract void initNative() throws NativeWindowException; + protected abstract void validateNative() throws NativeWindowException; protected synchronized void invalidate() { component = null; diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/macosx/MacOSXJAWTWindow.java index ed932ff91..bcaa66847 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/macosx/MacOSXJAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/macosx/MacOSXJAWTWindow.java @@ -54,7 +54,7 @@ public class MacOSXJAWTWindow extends JAWTWindow { super(comp, config); } - protected void initNative() throws NativeWindowException { + protected void validateNative() throws NativeWindowException { } protected int lockSurfaceImpl() throws NativeWindowException { diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/windows/WindowsJAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/windows/WindowsJAWTWindow.java index b6da7166d..d19a11f66 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/windows/WindowsJAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/windows/WindowsJAWTWindow.java @@ -54,7 +54,7 @@ public class WindowsJAWTWindow extends JAWTWindow { super(comp, config); } - protected void initNative() throws NativeWindowException { + protected void validateNative() throws NativeWindowException { } protected synchronized void invalidate() { diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/x11/X11JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/x11/X11JAWTWindow.java index 4a2c9ada3..a5d36b6dd 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/x11/X11JAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/jawt/x11/X11JAWTWindow.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -38,14 +39,10 @@ package com.jogamp.nativewindow.impl.jawt.x11; import javax.media.nativewindow.*; import javax.media.nativewindow.awt.*; -import javax.media.nativewindow.x11.*; import com.jogamp.nativewindow.impl.x11.*; import com.jogamp.nativewindow.impl.jawt.*; -import com.jogamp.nativewindow.impl.*; -import java.awt.GraphicsDevice; -import java.awt.GraphicsEnvironment; public class X11JAWTWindow extends JAWTWindow { @@ -53,15 +50,31 @@ public class X11JAWTWindow extends JAWTWindow { super(comp, config); } - protected void initNative() throws NativeWindowException { - if(0==config.getScreen().getDevice().getHandle()) { - AWTGraphicsDevice awtDevice = (AWTGraphicsDevice) config.getScreen().getDevice(); - long displayHandle = X11SunJDKReflection.graphicsDeviceGetDisplay(awtDevice.getGraphicsDevice()); - if(0==displayHandle) { - displayHandle = X11Util.createThreadLocalDisplay(null); - } - awtDevice.setSubType(NativeWindowFactory.TYPE_X11, displayHandle); + protected void validateNative() throws NativeWindowException { + AWTGraphicsDevice awtDevice = (AWTGraphicsDevice) config.getScreen().getDevice(); + + if(awtDevice.getHandle() != 0) { + // subtype and handle set already, done + return; + } + + long displayHandle = 0; + + // first try a pre-existing attached native configuration, ie native X11GraphicsDevice + AbstractGraphicsConfiguration aconfig = (null!=config) ? config.getNativeGraphicsConfiguration() : null; + AbstractGraphicsScreen ascreen = (null!=aconfig) ? aconfig.getScreen() : null; + AbstractGraphicsDevice adevice = (null!=ascreen) ? ascreen.getDevice() : null; // X11GraphicsDevice + if(null!=adevice) { + displayHandle = adevice.getHandle(); + } + + if(0 == displayHandle) { + displayHandle = X11SunJDKReflection.graphicsDeviceGetDisplay(awtDevice.getGraphicsDevice()); + } + if(0==displayHandle) { + throw new InternalError("X11JAWTWindow: No X11 Display handle available"); } + awtDevice.setSubType(NativeWindowFactory.TYPE_X11, displayHandle); } protected int lockSurfaceImpl() throws NativeWindowException { diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java b/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java index 14e285187..524b142ec 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -35,7 +36,6 @@ package com.jogamp.nativewindow.impl.x11; import java.util.HashMap; import java.util.Map; import com.jogamp.common.util.LongObjectHashMap; -import com.jogamp.common.util.locks.RecursiveLock; import javax.media.nativewindow.*; @@ -44,13 +44,11 @@ import java.nio.Buffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; import java.security.AccessController; +import java.util.ArrayList; +import java.util.List; /** - * Contains a thread safe X11 utility to retrieve thread local display connection,<br> - * as well as the static global display connection.<br> - * - * The TLS variant is thread safe per se, but be aware of the memory leak risk - * where an application heavily utilizing this class on temporary new threads.<br> + * Contains a thread safe X11 utility to retrieve display connections. */ public class X11Util { private static final boolean DEBUG = Debug.debug("X11Util"); @@ -123,29 +121,37 @@ public class X11Util { // which is to tag a NamedDisplay uncloseable after creation. private static Object globalLock = new Object(); private static LongObjectHashMap globalNamedDisplayMap = new LongObjectHashMap(); - - private static ThreadLocal currentDisplayMap = new ThreadLocal(); + private static List openDisplayList = new ArrayList(); + private static List pendingDisplayList = new ArrayList(); public static class NamedDisplay { String name; long handle; int refCount; boolean unCloseable; + Throwable creationStack; protected NamedDisplay(String name, long handle) { this.name=name; this.handle=handle; this.refCount=1; this.unCloseable=false; + if(DEBUG) { + this.creationStack=new Throwable("NamedDisplay Created at:"); + } else { + this.creationStack=null; + } } public final String getName() { return name; } public final long getHandle() { return handle; } public final int getRefCount() { return refCount; } - public void setUncloseable(boolean v) { unCloseable = v; } + public final void setUncloseable(boolean v) { unCloseable = v; } public final boolean isUncloseable() { return unCloseable; } + public final Throwable getCreationStack() { return creationStack; } + public Object clone() throws CloneNotSupportedException { return super.clone(); } @@ -156,116 +162,107 @@ public class X11Util { } /** Returns the number of unclosed X11 Displays. - * @param realXClosePendingDisplays if true, call XCloseDisplay on the remaining ones + * @param realXCloseAndPendingDisplays if true, {@link #closePendingDisplayConnections()} is called. */ - public static int shutdown(boolean realXClosePendingDisplays, boolean verbose) { + public static int shutdown(boolean realXCloseOpenAndPendingDisplays, boolean verbose) { int num=0; - if(DEBUG||verbose) { - String msg = "X11Util.Display: Shutdown (closePendingDisplays: "+realXClosePendingDisplays+ - ", global: "+globalNamedDisplayMap.size()+ ")" ; + if(DEBUG||verbose||pendingDisplayList.size() > 0) { + String msg = "X11Util.Display: Shutdown (close open / pending Displays: "+realXCloseOpenAndPendingDisplays+ + ", open (no close attempt): "+globalNamedDisplayMap.size()+"/"+openDisplayList.size()+ + ", open (no close attempt and uncloseable): "+pendingDisplayList.size()+")" ; if(DEBUG) { Exception e = new Exception(msg); e.printStackTrace(); - } else if(verbose) { + } else { System.err.println(msg); } + if( openDisplayList.size() > 0) { + X11Util.dumpOpenDisplayConnections(); + } + if( pendingDisplayList.size() > 0 ) { + X11Util.dumpPendingDisplayConnections(); + } } synchronized(globalLock) { + if(realXCloseOpenAndPendingDisplays) { + closePendingDisplayConnections(); + } + openDisplayList.clear(); + pendingDisplayList.clear(); globalNamedDisplayMap.clear(); } return num; } - /******************************* - ** - ** TLS Management - ** - *******************************/ - - /** Returns a clone of the thread local display map, you may {@link Object#wait()} on it */ - public static Map getCurrentDisplayMap() { - return (Map) ((HashMap)getCurrentDisplayMapImpl()).clone(); - } - - /** Returns this thread named display. If it doesn not exist, it is being created, otherwise the reference count is increased */ - public static long createThreadLocalDisplay(String name) { - name = validateDisplayName(name); - NamedDisplay namedDpy = getCurrentDisplay(name); - if(null==namedDpy) { - long dpy = XOpenDisplay(name); - if(0==dpy) { - throw new NativeWindowException("X11Util.Display: Unable to create a display("+name+") connection in Thread "+Thread.currentThread().getName()); - } - // if you like to debug and synchronize X11 commands .. - // setSynchronizeDisplay(dpy, true); - namedDpy = new NamedDisplay(name, dpy); - addCurrentDisplay( namedDpy ); - synchronized(globalLock) { - globalNamedDisplayMap.put(dpy, namedDpy); - } + /** + * Closing pending Display connections in reverse order. + * + * @return number of closed Display connections + */ + public static int closePendingDisplayConnections() { + int num=0; + synchronized(globalLock) { if(DEBUG) { - Exception e = new Exception("X11Util.Display: Created new TLS "+namedDpy+" in thread "+Thread.currentThread().getName()); - e.printStackTrace(); + System.err.println("X11Util: Closing Pending X11 Display Connections: "+pendingDisplayList.size()); } - } else { - namedDpy.refCount++; - if(DEBUG) { - Exception e = new Exception("X11Util.Display: Reused TLS "+namedDpy+" in thread "+Thread.currentThread().getName()); - e.printStackTrace(); + for(int i=pendingDisplayList.size()-1; i>=0; i--) { + NamedDisplay ndpy = (NamedDisplay) pendingDisplayList.get(i); + if(DEBUG) { + System.err.println("X11Util.closePendingDisplayConnections(): Closing ["+i+"]: "+ndpy); + } + XCloseDisplay(ndpy.getHandle()); + num++; } } - return namedDpy.getHandle(); + return num; } - /** Decrease the reference count of this thread named display. If it reaches 0, close it. - It returns the handle of the to be closed display. - It throws a RuntimeException in case the named display does not exist, - or the reference count goes below 0. - */ - public static long closeThreadLocalDisplay(String name) { - name = validateDisplayName(name); - NamedDisplay namedDpy = getCurrentDisplay(name); - if(null==namedDpy) { - throw new RuntimeException("X11Util.Display: Display("+name+") with given name is not mapped to TLS in thread "+Thread.currentThread().getName()); - } - if(0==namedDpy.refCount) { - throw new RuntimeException("X11Util.Display: "+namedDpy+" has refCount already 0 in thread "+Thread.currentThread().getName()); + public static int getOpenDisplayConnectionNumber() { + synchronized(globalLock) { + return openDisplayList.size(); } - long dpy = namedDpy.getHandle(); - namedDpy.refCount--; - if(0==namedDpy.refCount) { - if(DEBUG) { - String type = namedDpy.isUncloseable() ? "passive" : "real" ; - Exception e = new Exception("X11Util.Display: Closing ( "+type+" ) TLS "+namedDpy+" in thread "+Thread.currentThread().getName()); - e.printStackTrace(); - } - removeCurrentDisplay(namedDpy); - synchronized(globalLock) { - if(null==globalNamedDisplayMap.remove(dpy)) { throw new RuntimeException("Internal: "+namedDpy); } - } - if(!namedDpy.isUncloseable()) { - XCloseDisplay(dpy); + } + + public static void dumpOpenDisplayConnections() { + synchronized(globalLock) { + System.err.println("X11Util: Open X11 Display Connections: "+openDisplayList.size()); + for(int i=0; i<pendingDisplayList.size(); i++) { + NamedDisplay ndpy = (NamedDisplay) openDisplayList.get(i); + System.err.println("X11Util: ["+i+"]: "+ndpy); + if(null!=ndpy) { + Throwable t = ndpy.getCreationStack(); + if(null!=t) { + t.printStackTrace(); + } + } } - } else if(DEBUG) { - Exception e = new Exception("X11Util.Display: Keep TLS "+namedDpy+" in thread "+Thread.currentThread().getName()); - e.printStackTrace(); } - return dpy; } - public static long closeThreadLocalDisplay(long handle) { - NamedDisplay ndpy; + public static int getPendingDisplayConnectionNumber() { synchronized(globalLock) { - ndpy = (NamedDisplay) globalNamedDisplayMap.get(handle); + return pendingDisplayList.size(); } - if(null==ndpy) { - throw new RuntimeException("X11Util.Display: Display(0x"+Long.toHexString(handle)+") with given handle is not mapped, in thread "+Thread.currentThread().getName()); + } + + public static void dumpPendingDisplayConnections() { + synchronized(globalLock) { + System.err.println("X11Util: Pending X11 Display Connections: "+pendingDisplayList.size()); + for(int i=0; i<pendingDisplayList.size(); i++) { + NamedDisplay ndpy = (NamedDisplay) pendingDisplayList.get(i); + System.err.println("X11Util: ["+i+"]: "+ndpy); + if(null!=ndpy) { + Throwable t = ndpy.getCreationStack(); + if(null!=t) { + t.printStackTrace(); + } + } + } } - return closeThreadLocalDisplay(ndpy.getName()); } - public static boolean markThreadLocalDisplayUncloseable(long handle) { + public static boolean markDisplayUncloseable(long handle) { NamedDisplay ndpy; synchronized(globalLock) { ndpy = (NamedDisplay) globalNamedDisplayMap.get(handle); @@ -277,53 +274,6 @@ public class X11Util { return false; } - private static Map getCurrentDisplayMapImpl() { - Map displayMap = (Map) currentDisplayMap.get(); - if(null==displayMap) { - displayMap = new HashMap(); - currentDisplayMap.set( displayMap ); - } - return displayMap; - } - - /** maps the given display to the thread local display map - * and notifies all threads synchronized to this display map. */ - private static NamedDisplay addCurrentDisplay(NamedDisplay newDisplay) { - Map displayMap = getCurrentDisplayMapImpl(); - NamedDisplay oldDisplay = null; - synchronized(displayMap) { - oldDisplay = (NamedDisplay) displayMap.put(newDisplay.getName(), newDisplay); - displayMap.notifyAll(); - } - return oldDisplay; - } - - /** removes the mapping of the given name from the thread local display map - * and notifies all threads synchronized to this display map. */ - private static NamedDisplay removeCurrentDisplay(NamedDisplay ndpy) { - Map displayMap = getCurrentDisplayMapImpl(); - synchronized(displayMap) { - NamedDisplay ndpyDel = (NamedDisplay) displayMap.remove(ndpy.getName()); - if(ndpyDel!=ndpy) { - throw new RuntimeException("Wrong mapping req: "+ndpy+", got "+ndpyDel); - } - displayMap.notifyAll(); - } - return ndpy; - } - - /** Returns the thread local display mapped to the given name */ - private static NamedDisplay getCurrentDisplay(String name) { - Map displayMap = getCurrentDisplayMapImpl(); - return (NamedDisplay) displayMap.get(name); - } - - /******************************* - ** - ** Non TLS Functions - ** - *******************************/ - /** Returns this created named display. */ public static long createDisplay(String name) { name = validateDisplayName(name); @@ -336,6 +286,8 @@ public class X11Util { NamedDisplay namedDpy = new NamedDisplay(name, dpy); synchronized(globalLock) { globalNamedDisplayMap.put(dpy, namedDpy); + openDisplayList.add(namedDpy); + pendingDisplayList.add(namedDpy); } if(DEBUG) { Exception e = new Exception("X11Util.Display: Created new "+namedDpy+". Thread "+Thread.currentThread().getName()); @@ -349,11 +301,16 @@ public class X11Util { synchronized(globalLock) { namedDpy = (NamedDisplay) globalNamedDisplayMap.remove(handle); + if(namedDpy!=null) { + if(!openDisplayList.remove(namedDpy)) { throw new RuntimeException("Internal: "+namedDpy); } + } } if(null==namedDpy) { + X11Util.dumpPendingDisplayConnections(); throw new RuntimeException("X11Util.Display: Display(0x"+Long.toHexString(handle)+") with given handle is not mapped. Thread "+Thread.currentThread().getName()); } if(namedDpy.getHandle()!=handle) { + X11Util.dumpPendingDisplayConnections(); throw new RuntimeException("X11Util.Display: Display(0x"+Long.toHexString(handle)+") Mapping error: "+namedDpy+". Thread "+Thread.currentThread().getName()); } @@ -363,6 +320,9 @@ public class X11Util { } if(!namedDpy.isUncloseable()) { + synchronized(globalLock) { + if(!pendingDisplayList.remove(namedDpy)) { throw new RuntimeException("Internal: "+namedDpy); } + } XCloseDisplay(namedDpy.getHandle()); } } @@ -392,6 +352,7 @@ public class X11Util { ** Locked X11Lib wrapped functions ** *******************************/ + public static long XOpenDisplay(String arg0) { NativeWindowFactory.getDefaultToolkitLock().lock(); try { diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java index b003db8f5..581df5163 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java @@ -68,4 +68,16 @@ public interface AbstractGraphicsDevice extends Cloneable { * The lock implementation must be recursive. */ public void unlock(); + + /** + * Optionally closing the device.<br> + * The default implementation is a NOP operation, returning false.<br> + * The specific implementing, ie {@link javax.media.nativewindow.x11.X11GraphicsDevice}, + * shall have a enable/disable like {@link javax.media.nativewindow.x11.X11GraphicsDevice#setCloseDisplay(boolean, boolean)},<br> + * which shall be invoked at creation time to determine ownership/role of freeing the resource.<br> + * + * @return true if a specialized closing operation was successfully issued, otherwise false, + * ie no native closing operation was issued, which doesn't imply an error at all. + */ + public boolean close(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java index ca0f106f5..b67688116 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java @@ -91,26 +91,6 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice } /** - * Set the internal ToolkitLock, which is used within the - * {@link #lock()} and {@link #unlock()} implementation. - * - * @param locker the ToolkitLock, if null, {@link com.jogamp.nativewindow.impl.NullToolkitLock} is being used - */ - protected void setToolkitLock(ToolkitLock locker) { - this.toolkitLock = ( null == locker ) ? NativeWindowFactoryImpl.getNullToolkitLock() : locker ; - } - - /** - * @return the used ToolkitLock - * - * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long) - * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long, javax.media.nativewindow.ToolkitLock) - */ - public final ToolkitLock getToolkitLock() { - return toolkitLock; - } - - /** * No lock is performed on the graphics device per default, * instead the aggregated recursive {@link ToolkitLock#lock()} is invoked. * @@ -132,7 +112,31 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice toolkitLock.unlock(); } + public boolean close() { + return false; + } + public String toString() { return getClass().toString()+"[type "+getType()+", handle 0x"+Long.toHexString(getHandle())+"]"; } + + /** + * Set the internal ToolkitLock, which is used within the + * {@link #lock()} and {@link #unlock()} implementation. + * + * @param locker the ToolkitLock, if null, {@link com.jogamp.nativewindow.impl.NullToolkitLock} is being used + */ + protected void setToolkitLock(ToolkitLock locker) { + this.toolkitLock = ( null == locker ) ? NativeWindowFactoryImpl.getNullToolkitLock() : locker ; + } + + /** + * @return the used ToolkitLock + * + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long) + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long, javax.media.nativewindow.ToolkitLock) + */ + public final ToolkitLock getToolkitLock() { + return toolkitLock; + } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java index 31744702d..c60597661 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java @@ -32,12 +32,15 @@ package javax.media.nativewindow.x11; +import com.jogamp.nativewindow.impl.x11.X11Util; import javax.media.nativewindow.*; /** Encapsulates a graphics device on X11 platforms. */ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneable { + boolean closeDisplay = false; + /** Constructs a new X11GraphicsDevice corresponding to the given native display handle and default * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#createDefaultToolkitLock(java.lang.String, long)}. */ @@ -62,5 +65,17 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl public Object clone() { return super.clone(); } + + public void setCloseDisplay(boolean close) { + closeDisplay = close; + } + public boolean close() { + if(closeDisplay && 0 != handle) { + X11Util.closeDisplay(handle); + handle = 0; + return true; + } + return true; + } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java index 73af5f852..dca0d1de3 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java +++ b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java @@ -53,13 +53,6 @@ public class X11GraphicsScreen extends DefaultGraphicsScreen implements Cloneabl return new X11GraphicsScreen(new X11GraphicsDevice(display), screenIdx); } - /** Creates a new X11GraphicsScreen using a thread local display connection */ - public static AbstractGraphicsScreen createDefault() { - long display = X11Util.createThreadLocalDisplay(null); - int scrnIdx = X11Util.DefaultScreen(display); - return createScreenDevice(display, scrnIdx); - } - public long getDefaultVisualID() { // It still could be an AWT hold handle .. long display = getDevice().getHandle(); diff --git a/src/newt/classes/com/jogamp/newt/impl/awt/AWTCanvas.java b/src/newt/classes/com/jogamp/newt/impl/awt/AWTCanvas.java index bbf75798e..9b0ec6907 100644 --- a/src/newt/classes/com/jogamp/newt/impl/awt/AWTCanvas.java +++ b/src/newt/classes/com/jogamp/newt/impl/awt/AWTCanvas.java @@ -37,12 +37,10 @@ import com.jogamp.newt.Window; import java.awt.Canvas; import java.awt.GraphicsDevice; -import java.awt.GraphicsEnvironment; import java.awt.GraphicsConfiguration; import javax.media.nativewindow.*; import javax.media.nativewindow.awt.*; -import com.jogamp.newt.impl.Debug; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; @@ -102,6 +100,28 @@ public class AWTCanvas extends Canvas { } } + public void removeNotify() { + try { + dispose(); + } finally { + super.removeNotify(); + } + } + + private void dispose() { + if(null != awtConfig) { + AbstractGraphicsDevice adevice = awtConfig.getNativeGraphicsConfiguration().getScreen().getDevice(); + String adeviceMsg=null; + if(Window.DEBUG_IMPLEMENTATION) { + adeviceMsg = adevice.toString(); + } + boolean closed = adevice.close(); + if(Window.DEBUG_IMPLEMENTATION) { + System.err.println("AWTCanvas.dispose(): closed GraphicsDevice: "+adeviceMsg+", result: "+closed); + } + } + } + /** * Overridden to choose a GraphicsConfiguration on a parent container's * GraphicsDevice because both devices |