summaryrefslogtreecommitdiffstats
path: root/src/nativewindow/classes/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/nativewindow/classes/com')
-rw-r--r--src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java228
1 files changed, 198 insertions, 30 deletions
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 95fd6c72b..41ffccc42 100644
--- a/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java
+++ b/src/nativewindow/classes/com/jogamp/nativewindow/impl/x11/X11Util.java
@@ -34,6 +34,9 @@ package com.jogamp.nativewindow.impl.x11;
import java.util.HashMap;
import java.util.Map;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.Iterator;
import javax.media.nativewindow.*;
@@ -41,7 +44,7 @@ import com.jogamp.nativewindow.impl.*;
/**
* Contains a thread safe X11 utility to retrieve thread local display connection,<br>
- * as well as the static global discplay 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>
@@ -51,27 +54,98 @@ public class X11Util {
static {
NativeLibLoaderBase.loadNativeWindow("x11");
+ installIOErrorHandler();
}
private X11Util() {}
private static ThreadLocal currentDisplayMap = new ThreadLocal();
+ // not exactly thread safe, but good enough for our purpose,
+ // which is to tag a NamedDisplay uncloseable after creation.
+ private static Object globalLock = new Object();
+ private static Collection globalNamedDisplayActive = new ArrayList();
+ private static Collection globalNamedDisplayPassive = new ArrayList();
+
+ public static final String nullDeviceName = "nil" ;
+
public static class NamedDisplay implements Cloneable {
- private String name;
- private long handle;
+ String name;
+ long handle;
+ int refCount;
+ boolean unCloseable;
protected NamedDisplay(String name, long handle) {
this.name=name;
this.handle=handle;
+ this.refCount=1;
+ this.unCloseable=false;
}
- public String getName() { return name; }
- public long getHandle() { return handle; }
+ public final String getName() { return name; }
+ public final String getNameSafe() { return null == name ? nullDeviceName : name; }
+ public final long getHandle() { return handle; }
+ public final int getRefCount() { return refCount; }
+ public final boolean isUncloseable() { return unCloseable; }
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
+
+ public String toString() {
+ return "NamedX11Display["+name+", 0x"+Long.toHexString(handle)+", refCount "+refCount+", unCloseable "+unCloseable+"]";
+ }
+ }
+
+ /** Returns the number of unclosed X11 Displays.
+ * @param realXClosePendingDisplays if true, call XCloseDisplay on the remaining ones
+ */
+ public static int shutdown(boolean realXClosePendingDisplays, boolean verbose) {
+ int num=0;
+ String msg;
+ if(DEBUG||verbose) {
+ msg = "X11Util.Display: Shutdown (active: "+globalNamedDisplayActive.size()+
+ ", passive: "+globalNamedDisplayPassive.size() + ")";
+ if(DEBUG) {
+ Exception e = new Exception(msg);
+ e.printStackTrace();
+ } else if(verbose) {
+ System.err.println(msg);
+ }
+ }
+
+ msg = realXClosePendingDisplays ? "Close" : "Keep" ;
+
+ synchronized(globalLock) {
+ // for all passive displays ..
+ Collection namedDisplays = globalNamedDisplayPassive;
+ globalNamedDisplayPassive = new ArrayList();
+ for(Iterator iter=namedDisplays.iterator(); iter.hasNext(); ) {
+ NamedDisplay ndpy = (NamedDisplay)iter.next();
+ if(DEBUG||verbose) {
+ System.err.println(msg+" passive: "+ndpy);
+ }
+ if(realXClosePendingDisplays) {
+ X11Lib.XCloseDisplay(ndpy.getHandle());
+ }
+ num++;
+ }
+
+ // for all active displays ..
+ namedDisplays = globalNamedDisplayActive;
+ globalNamedDisplayActive = new ArrayList();
+ for(Iterator iter=namedDisplays.iterator(); iter.hasNext(); ) {
+ NamedDisplay ndpy = (NamedDisplay)iter.next();
+ if(DEBUG||verbose) {
+ System.err.println(msg+" active: "+ndpy);
+ }
+ if(realXClosePendingDisplays) {
+ X11Lib.XCloseDisplay(ndpy.getHandle());
+ }
+ num++;
+ }
+ }
+ return num;
}
/** Returns a clone of the thread local display map, you may {@link Object#wait()} on it */
@@ -79,48 +153,120 @@ public class X11Util {
return (Map) ((HashMap)getCurrentDisplayMapImpl()).clone();
}
- /** Returns this thread current default display. If it doesn not exist, it is being created */
- public static long getThreadLocalDefaultDisplay() {
- return getThreadLocalDisplay(null);
+ /** Returns this thread current default display. If it doesn not exist, it is being created, otherwise the reference count is increased */
+ public static long createThreadLocalDefaultDisplay() {
+ return createThreadLocalDisplay(null);
}
- /** Returns this thread named display. If it doesn not exist, it is being created */
- public static long getThreadLocalDisplay(String name) {
+ /** 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) {
NamedDisplay namedDpy = getCurrentDisplay(name);
if(null==namedDpy) {
+ synchronized(globalLock) {
+ namedDpy = getNamedDisplay(globalNamedDisplayPassive, name);
+ if(null != namedDpy) {
+ if(!globalNamedDisplayPassive.remove(namedDpy)) { throw new RuntimeException("Internal: "+namedDpy); }
+ globalNamedDisplayActive.add(namedDpy);
+ addCurrentDisplay( namedDpy );
+ }
+ }
+ }
+ if(null==namedDpy) {
long dpy = X11Lib.XOpenDisplay(name);
if(0==dpy) {
throw new NativeWindowException("X11Util.Display: Unable to create a display("+name+") connection in Thread "+Thread.currentThread().getName());
}
namedDpy = new NamedDisplay(name, dpy);
- setCurrentDisplay( namedDpy );
+ synchronized(globalLock) {
+ globalNamedDisplayActive.add(namedDpy);
+ addCurrentDisplay( namedDpy );
+ }
if(DEBUG) {
- Exception e = new Exception("X11Util.Display: Created new TLS display("+name+") connection 0x"+Long.toHexString(dpy)+" in thread "+Thread.currentThread().getName());
+ Exception e = new Exception("X11Util.Display: Created new TLS "+namedDpy+" in thread "+Thread.currentThread().getName());
+ e.printStackTrace();
+ }
+ } else {
+ namedDpy.refCount++;
+ if(DEBUG) {
+ Exception e = new Exception("X11Util.Display: Reused TLS "+namedDpy+" in thread "+Thread.currentThread().getName());
e.printStackTrace();
}
}
return namedDpy.getHandle();
}
- /** Closes this thread named display. It returns the handle of the closed display or 0, if it does not exist. */
+ /** 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) {
- NamedDisplay namedDpy = removeCurrentDisplay(name);
+ NamedDisplay namedDpy = getCurrentDisplay(name);
if(null==namedDpy) {
+ throw new RuntimeException("X11Util.Display: Display("+name+") with given handle 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());
+ }
+ long dpy = namedDpy.getHandle();
+ namedDpy.refCount--;
+ if(0==namedDpy.refCount) {
+ synchronized(globalLock) {
+ if(!globalNamedDisplayActive.remove(namedDpy)) { throw new RuntimeException("Internal: "+namedDpy); }
+ if(namedDpy.isUncloseable()) {
+ globalNamedDisplayPassive.add(namedDpy);
+ } else {
+ X11Lib.XCloseDisplay(dpy);
+ }
+ removeCurrentDisplay(namedDpy);
+ }
if(DEBUG) {
- Exception e = new Exception("X11Util.Display: Display("+name+") with given handle is not mapped to TLS in thread "+Thread.currentThread().getName());
+ String type = namedDpy.isUncloseable() ? "passive" : "real" ;
+ Exception e = new Exception("X11Util.Display: Closing ( "+type+" ) TLS "+namedDpy+" in thread "+Thread.currentThread().getName());
e.printStackTrace();
}
- return 0;
- }
- long dpy = namedDpy.getHandle();
- if(DEBUG) {
- Exception e = new Exception("X11Util.Display: Closing TLS Display("+name+") with handle 0x"+Long.toHexString(dpy)+" in thread "+Thread.currentThread().getName());
+ } else if(DEBUG) {
+ Exception e = new Exception("X11Util.Display: Keep TLS "+namedDpy+" in thread "+Thread.currentThread().getName());
e.printStackTrace();
}
- X11Lib.XCloseDisplay(dpy);
return dpy;
}
+ public static String getThreadLocalDisplayName(long handle) {
+ NamedDisplay ndpy = getNamedDisplay(getCurrentDisplayMapImpl().values(), handle);
+ return null != ndpy ? ndpy.getName() : null;
+ }
+
+ public static boolean markThreadLocalDisplayUndeletable(long handle) {
+ NamedDisplay ndpy = getNamedDisplay(getCurrentDisplayMapImpl().values(), handle);
+ if( null != ndpy ) {
+ ndpy.unCloseable=true;
+ return true;
+ }
+ return false;
+ }
+
+ public static String getGlobalDisplayName(long handle, boolean active) {
+ String name;
+ synchronized(globalLock) {
+ NamedDisplay ndpy = getNamedDisplay(active ? globalNamedDisplayActive : globalNamedDisplayPassive, handle);
+ name = null != ndpy ? ndpy.getName() : null;
+ }
+ return name;
+ }
+
+ public static boolean markGlobalDisplayUndeletable(long handle) {
+ boolean r=false;
+ synchronized(globalLock) {
+ NamedDisplay ndpy = getNamedDisplay(globalNamedDisplayActive, handle);
+ if( null != ndpy ) {
+ ndpy.unCloseable=true;
+ r=true;
+ }
+ }
+ return r;
+ }
+
private static Map getCurrentDisplayMapImpl() {
Map displayMap = (Map) currentDisplayMap.get();
if(null==displayMap) {
@@ -132,12 +278,11 @@ public class X11Util {
/** maps the given display to the thread local display map
* and notifies all threads synchronized to this display map. */
- private static NamedDisplay setCurrentDisplay(NamedDisplay newDisplay) {
+ private static NamedDisplay addCurrentDisplay(NamedDisplay newDisplay) {
Map displayMap = getCurrentDisplayMapImpl();
NamedDisplay oldDisplay = null;
synchronized(displayMap) {
- String name = (null==newDisplay.getName())?"nil":newDisplay.getName();
- oldDisplay = (NamedDisplay) displayMap.put(name, newDisplay);
+ oldDisplay = (NamedDisplay) displayMap.put(newDisplay.getNameSafe(), newDisplay);
displayMap.notifyAll();
}
return oldDisplay;
@@ -145,22 +290,45 @@ public class X11Util {
/** 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(String name) {
+ private static NamedDisplay removeCurrentDisplay(NamedDisplay ndpy) {
Map displayMap = getCurrentDisplayMapImpl();
- NamedDisplay oldDisplay = null;
synchronized(displayMap) {
- if(null==name) name="nil";
- oldDisplay = (NamedDisplay) displayMap.remove(name);
+ NamedDisplay ndpyDel = (NamedDisplay) displayMap.remove(ndpy.getNameSafe());
+ if(ndpyDel!=ndpy) {
+ throw new RuntimeException("Wrong mapping req: "+ndpy+", got "+ndpyDel);
+ }
displayMap.notifyAll();
}
- return oldDisplay;
+ return ndpy;
}
/** Returns the thread local display mapped to the given name */
private static NamedDisplay getCurrentDisplay(String name) {
- if(null==name) name="nil";
+ if(null==name) name=nullDeviceName;
Map displayMap = getCurrentDisplayMapImpl();
return (NamedDisplay) displayMap.get(name);
}
+ private static NamedDisplay getNamedDisplay(Collection namedDisplays, String name) {
+ if(null==name) name=nullDeviceName;
+ for(Iterator iter=namedDisplays.iterator(); iter.hasNext(); ) {
+ NamedDisplay ndpy = (NamedDisplay)iter.next();
+ if (ndpy.getNameSafe().equals(name)) {
+ return ndpy;
+ }
+ }
+ return null;
+ }
+
+ private static NamedDisplay getNamedDisplay(Collection namedDisplays, long handle) {
+ for(Iterator iter=namedDisplays.iterator(); iter.hasNext(); ) {
+ NamedDisplay ndpy = (NamedDisplay)iter.next();
+ if (ndpy.getHandle()==handle) {
+ return ndpy;
+ }
+ }
+ return null;
+ }
+
+ private static native void installIOErrorHandler();
}