aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java49
-rw-r--r--src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java36
-rw-r--r--src/nativewindow/native/x11/Xmisc.c69
-rw-r--r--src/newt/classes/jogamp/newt/x11/X11Display.java2
-rw-r--r--src/newt/native/X11Window.c61
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/UITestCase.java16
6 files changed, 153 insertions, 80 deletions
diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java
index 51f4568c8..64781e418 100644
--- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java
+++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java
@@ -91,6 +91,7 @@ public abstract class NativeWindowFactory {
private static Class x11ToolkitLockClass;
private static Constructor x11ToolkitLockConstructor;
private static boolean isFirstUIActionOnProcess;
+ private static boolean requiresToolkitLock;
/** Creates a new NativeWindowFactory instance. End users do not
need to call this method. */
@@ -124,6 +125,8 @@ public abstract class NativeWindowFactory {
static boolean initialized = false;
private static void initNativeImpl(final boolean firstUIActionOnProcess, final ClassLoader cl) {
+ isFirstUIActionOnProcess = firstUIActionOnProcess;
+
String clazzName = null;
if( TYPE_X11.equals(nativeWindowingTypePure) ) {
clazzName = X11UtilClassName;
@@ -134,6 +137,11 @@ public abstract class NativeWindowFactory {
ReflectionUtil.callStaticMethod(clazzName, "initSingleton",
new Class[] { boolean.class },
new Object[] { new Boolean(firstUIActionOnProcess) }, cl );
+
+ final Boolean res = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "requiresToolkitLock", null, null, cl);
+ requiresToolkitLock = res.booleanValue();
+ } else {
+ requiresToolkitLock = false;
}
}
@@ -176,9 +184,8 @@ public abstract class NativeWindowFactory {
if(firstUIActionOnProcess) {
// X11 initialization before possible AWT initialization
- initNativeImpl(firstUIActionOnProcess, cl);
+ initNativeImpl(true, cl);
}
- isFirstUIActionOnProcess = firstUIActionOnProcess;
isAWTAvailable = false; // may be set to true below
if( !Debug.getBooleanProperty("java.awt.headless", true, acc) &&
@@ -212,7 +219,7 @@ public abstract class NativeWindowFactory {
}
if(!firstUIActionOnProcess) {
// X11 initialization after possible AWT initialization
- initNativeImpl(firstUIActionOnProcess, cl);
+ initNativeImpl(false, cl);
}
registeredFactories = Collections.synchronizedMap(new HashMap());
@@ -239,6 +246,7 @@ public abstract class NativeWindowFactory {
if(DEBUG) {
System.err.println("NativeWindowFactory firstUIActionOnProcess "+firstUIActionOnProcess);
+ System.err.println("NativeWindowFactory requiresToolkitLock "+requiresToolkitLock);
System.err.println("NativeWindowFactory isAWTAvailable "+isAWTAvailable+", defaultFactory "+factory);
}
}
@@ -250,6 +258,11 @@ public abstract class NativeWindowFactory {
return isFirstUIActionOnProcess;
}
+ /** @return true if the underlying toolkit requires locking, otherwise false. */
+ public static boolean requiresToolkitLock() {
+ return requiresToolkitLock;
+ }
+
/** @return true if not headless, AWT Component and NativeWindow's AWT part available */
public static boolean isAWTAvailable() { return isAWTAvailable; }
@@ -318,7 +331,7 @@ public abstract class NativeWindowFactory {
* </ul>
*/
public static ToolkitLock getDefaultToolkitLock(String type) {
- if( !isFirstUIActionOnProcess() ) {
+ if( requiresToolkitLock() ) {
if( TYPE_X11 == type || TYPE_AWT == type && TYPE_X11 == getNativeWindowType(false) ) {
if( isAWTAvailable() ) {
return getAWTToolkitLock();
@@ -364,7 +377,7 @@ public abstract class NativeWindowFactory {
* </ul>
*/
public static ToolkitLock createDefaultToolkitLock(String type, long deviceHandle) {
- if( !isFirstUIActionOnProcess() ) {
+ if( requiresToolkitLock() ) {
if( TYPE_X11 == type ) {
if( 0== deviceHandle ) {
throw new RuntimeException("JAWTUtil.createDefaultToolkitLock() called with NULL device but on X11");
@@ -378,32 +391,6 @@ public abstract class NativeWindowFactory {
return NativeWindowFactoryImpl.getNullToolkitLock();
}
- /**
- * Creates the default {@link ToolkitLock} for <code>type</code> and <code>deviceHandle</code>.
- * <br>
- * <ul>
- * <li> If {@link #initSingleton(boolean) initSingleton( <b>firstUIActionOnProcess := false</b> )} </li>
- * <ul>
- * <li>If <b>X11 type</b> </li>
- * <ul>
- * <li> return {@link jogamp.nativewindow.x11.X11ToolkitLock} </li>
- * </ul>
- * </ul>
- * <li> Otherwise return {@link jogamp.nativewindow.NullToolkitLock} </li>
- * </ul>
- */
- public static ToolkitLock createDefaultToolkitLockNoAWT(String type, long deviceHandle) {
- if( !isFirstUIActionOnProcess() ) {
- if( TYPE_X11 == type ) {
- if( 0== deviceHandle ) {
- throw new RuntimeException("JAWTUtil.createDefaultToolkitLockNoAWT() called with NULL device but on X11");
- }
- return createX11ToolkitLock(deviceHandle);
- }
- }
- return NativeWindowFactoryImpl.getNullToolkitLock();
- }
-
protected static ToolkitLock createX11AWTToolkitLock(long deviceHandle) {
try {
return (ToolkitLock) x11JAWTToolkitLockConstructor.newInstance(new Object[]{new Long(deviceHandle)});
diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java
index 8a6869d91..117184a71 100644
--- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java
+++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java
@@ -51,19 +51,29 @@ import javax.media.nativewindow.util.Point;
* Contains a thread safe X11 utility to retrieve display connections.
*/
public class X11Util {
+ /**
+ * 2011/06/14 libX11 1.4.2 and libxcb 1.7 bug 20708 - Multithreading Issues w/ OpenGL, ..
+ * https://bugs.freedesktop.org/show_bug.cgi?id=20708
+ * https://jogamp.org/bugzilla/show_bug.cgi?id=502
+ * Affects: Ubuntu 11.04, OpenSuSE 11, ..
+ * If the property <b>nativewindow.x11.mt-bug</b> is set to true, extensive X11 locking
+ * is being applied, avoiding X11 multithreading capabilities.
+ */
+ public static final boolean MULTITHREADING_BUG = Debug.getBooleanProperty("nativewindow.x11.mt-bug", true, AccessController.getContext());
+ public static final boolean XINITTHREADS_ALWAYS_ENABLED = true;
+
private static final boolean DEBUG = Debug.debug("X11Util");
private static final boolean TRACE_DISPLAY_LIFECYCLE = Debug.getBooleanProperty("nativewindow.debug.X11Util.TraceDisplayLifecycle", true, AccessController.getContext());
private static volatile String nullDisplayName = null;
- private static boolean isFirstX11ActionOnProcess = false;
+ private static boolean requiresX11Lock = false;
private static boolean isInit = false;
private static int setX11ErrorHandlerRecCount = 0;
private static Object setX11ErrorHandlerLock = new Object();
- public static final boolean XINITTHREADS_ALWAYS_ENABLED = true;
- public static synchronized void initSingleton(boolean firstX11ActionOnProcess) {
+ public static synchronized void initSingleton(final boolean firstX11ActionOnProcess) {
if(!isInit) {
NWJNILibLoader.loadNativeWindow("x11");
@@ -73,10 +83,14 @@ public class X11Util {
* ie NEWT (jogamp.newt.x11.X11Display.createNativeImpl()) !!
*/
initialize0( XINITTHREADS_ALWAYS_ENABLED ? true : firstX11ActionOnProcess );
- isFirstX11ActionOnProcess = firstX11ActionOnProcess;
+ requiresX11Lock = !firstX11ActionOnProcess || MULTITHREADING_BUG;
+
if(DEBUG) {
- System.out.println("X11Util.isFirstX11ActionOnProcess: "+isFirstX11ActionOnProcess);
+ System.out.println("X11Util firstX11ActionOnProcess: "+firstX11ActionOnProcess+
+ ", XINITTHREADS_ALWAYS_ENABLED "+XINITTHREADS_ALWAYS_ENABLED+
+ ", MULTITHREADING_BUG "+MULTITHREADING_BUG+
+ ", requiresX11Lock "+requiresX11Lock);
}
isInit = true;
}
@@ -101,19 +115,19 @@ public class X11Util {
}
}
- public static boolean isFirstX11ActionOnProcess() {
- return isFirstX11ActionOnProcess;
+ public static boolean requiresToolkitLock() {
+ return requiresX11Lock;
}
public static void lockDefaultToolkit(long dpyHandle) {
NativeWindowFactory.getDefaultToolkitLock().lock();
- if(!isFirstX11ActionOnProcess) {
+ if(requiresX11Lock) {
X11Util.XLockDisplay(dpyHandle);
}
}
public static void unlockDefaultToolkit(long dpyHandle) {
- if(!isFirstX11ActionOnProcess) {
+ if(requiresX11Lock) {
X11Util.XUnlockDisplay(dpyHandle);
}
NativeWindowFactory.getDefaultToolkitLock().unlock();
@@ -124,11 +138,11 @@ public class X11Util {
synchronized(X11Util.class) {
if(null==nullDisplayName) {
NativeWindowFactory.getDefaultToolkitLock().lock();
+ long dpy = X11Lib.XOpenDisplay(null);
try {
- long dpy = X11Lib.XOpenDisplay(null);
nullDisplayName = X11Lib.XDisplayString(dpy);
- X11Lib.XCloseDisplay(dpy);
} finally {
+ X11Lib.XCloseDisplay(dpy);
NativeWindowFactory.getDefaultToolkitLock().unlock();
}
if(DEBUG) {
diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c
index 1ee0a645b..1258c9f8f 100644
--- a/src/nativewindow/native/x11/Xmisc.c
+++ b/src/nativewindow/native/x11/Xmisc.c
@@ -156,14 +156,12 @@ static void _initClazzAccess(JNIEnv *env) {
static JavaVM *jvmHandle = NULL;
static int jvmVersion = 0;
-static JNIEnv * jvmEnv = NULL;
static void setupJVMVars(JNIEnv * env) {
if(0 != (*env)->GetJavaVM(env, &jvmHandle)) {
jvmHandle = NULL;
}
jvmVersion = (*env)->GetVersion(env);
- jvmEnv = env;
}
static XErrorHandler origErrorHandler = NULL ;
@@ -173,15 +171,35 @@ static int errorHandlerQuiet = 0 ;
static int x11ErrorHandler(Display *dpy, XErrorEvent *e)
{
if(!errorHandlerQuiet) {
- fprintf(stderr, "Info: Nativewindow X11 Error: Display %p, Code 0x%X, errno %s\n", dpy, e->error_code, strerror(errno));
+ JNIEnv *curEnv = NULL;
+ JNIEnv *newEnv = NULL;
+ int envRes ;
+ const char * errStr = strerror(errno);
+
+ fprintf(stderr, "Info: Nativewindow X11 Error: Display %p, Code 0x%X, errno %s\n", dpy, e->error_code, errStr);
+
+ // retrieve this thread's JNIEnv curEnv - or detect it's detached
+ envRes = (*jvmHandle)->GetEnv(jvmHandle, (void **) &curEnv, jvmVersion) ;
+ if( JNI_EDETACHED == envRes ) {
+ // detached thread - attach to JVM
+ if( JNI_OK != ( envRes = (*jvmHandle)->AttachCurrentThread(jvmHandle, (void**) &newEnv, NULL) ) ) {
+ fprintf(stderr, "Nativewindow X11 Error: can't attach thread: %d\n", envRes);
+ return 0;
+ }
+ curEnv = newEnv;
+ } else if( JNI_OK != envRes ) {
+ // oops ..
+ fprintf(stderr, "Nativewindow X11 Error: can't GetEnv: %d\n", envRes);
+ return 0;
+ }
+ NativewindowCommon_throwNewRuntimeException(curEnv, "Info: Nativewindow X11 Error: Display %p, Code 0x%X, errno %s",
+ dpy, e->error_code, errStr);
+
+ if( NULL != newEnv ) {
+ // detached attached thread
+ (*jvmHandle)->DetachCurrentThread(jvmHandle);
+ }
}
-#if 0
- // Since the X11 Error may happen anytime, a exception could mess up the JVM completely.
- // Experienced this for remote displays issuing non supported commands, eg. glXCreateContextAttribsARB(..)
- //
- NativewindowCommon_throwNewRuntimeException(jvmEnv, "Info: Nativewindow X11 Error: Display %p, Code 0x%X, errno %s",
- dpy, e->error_code, strerror(errno));
-#endif
#if 0
if(NULL!=origErrorHandler) {
@@ -226,8 +244,35 @@ static XIOErrorHandler origIOErrorHandler = NULL;
static int x11IOErrorHandler(Display *dpy)
{
- fprintf(stderr, "Nativewindow X11 IOError: Display %p (%s): %s\n", dpy, XDisplayName(NULL), strerror(errno));
- // NativewindowCommon_FatalError(jvmEnv, "Nativewindow X11 IOError: Display %p (%s): %s", dpy, XDisplayName(NULL), strerror(errno));
+ JNIEnv *curEnv = NULL;
+ JNIEnv *newEnv = NULL;
+ int envRes ;
+ const char * dpyName = XDisplayName(NULL);
+ const char * errStr = strerror(errno);
+
+ fprintf(stderr, "Nativewindow X11 IOError: Display %p (%s): %s\n", dpy, dpyName, errStr);
+
+ // retrieve this thread's JNIEnv curEnv - or detect it's detached
+ envRes = (*jvmHandle)->GetEnv(jvmHandle, (void **) &curEnv, jvmVersion) ;
+ if( JNI_EDETACHED == envRes ) {
+ // detached thread - attach to JVM
+ if( JNI_OK != ( envRes = (*jvmHandle)->AttachCurrentThread(jvmHandle, (void**) &newEnv, NULL) ) ) {
+ fprintf(stderr, "Nativewindow X11 IOError: can't attach thread: %d\n", envRes);
+ return;
+ }
+ curEnv = newEnv;
+ } else if( JNI_OK != envRes ) {
+ // oops ..
+ fprintf(stderr, "Nativewindow X11 IOError: can't GetEnv: %d\n", envRes);
+ return;
+ }
+
+ NativewindowCommon_FatalError(curEnv, "Nativewindow X11 IOError: Display %p (%s): %s", dpy, dpyName, errStr);
+
+ if( NULL != newEnv ) {
+ // detached attached thread
+ (*jvmHandle)->DetachCurrentThread(jvmHandle);
+ }
if(NULL!=origIOErrorHandler) {
origIOErrorHandler(dpy);
}
diff --git a/src/newt/classes/jogamp/newt/x11/X11Display.java b/src/newt/classes/jogamp/newt/x11/X11Display.java
index 815395e2d..0804455d1 100644
--- a/src/newt/classes/jogamp/newt/x11/X11Display.java
+++ b/src/newt/classes/jogamp/newt/x11/X11Display.java
@@ -76,7 +76,7 @@ public class X11Display extends DisplayImpl {
throw e;
}
- if(X11Util.XINITTHREADS_ALWAYS_ENABLED) {
+ if(X11Util.XINITTHREADS_ALWAYS_ENABLED && !X11Util.MULTITHREADING_BUG) {
// Hack: Force non X11Display locking, even w/ AWT and w/o isFirstUIActionOnProcess()
aDevice = new X11GraphicsDevice(handle, AbstractGraphicsDevice.DEFAULT_UNIT, NativeWindowFactory.getNullToolkitLock());
} else {
diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c
index add9fa604..71a421656 100644
--- a/src/newt/native/X11Window.c
+++ b/src/newt/native/X11Window.c
@@ -187,14 +187,12 @@ static jmethodID displayCompletedID = NULL;
static JavaVM *jvmHandle = NULL;
static int jvmVersion = 0;
-static JNIEnv * jvmEnv = NULL;
static void setupJVMVars(JNIEnv * env) {
if(0 != (*env)->GetJavaVM(env, &jvmHandle)) {
jvmHandle = NULL;
}
jvmVersion = (*env)->GetVersion(env);
- jvmEnv = env;
}
static XErrorHandler origErrorHandler = NULL ;
@@ -208,8 +206,34 @@ static int displayDispatchErrorHandler(Display *dpy, XErrorEvent *e)
} else if (e->error_code == BadWindow) {
fprintf(stderr, " BadWindow (%p): Window probably already removed\n", (void*)e->resourceid);
} else {
- NewtCommon_throwNewRuntimeException(jvmEnv, "NEWT X11 Error: Display %p, Code 0x%X, errno %s",
- dpy, e->error_code, strerror(errno));
+ JNIEnv *curEnv = NULL;
+ JNIEnv *newEnv = NULL;
+ int envRes ;
+ const char * errStr = strerror(errno);
+
+ fprintf(stderr, "Info: NEWT X11 Error: Display %p, Code 0x%X, errno %s\n", dpy, e->error_code, errStr);
+
+ // retrieve this thread's JNIEnv curEnv - or detect it's detached
+ envRes = (*jvmHandle)->GetEnv(jvmHandle, (void **) &curEnv, jvmVersion) ;
+ if( JNI_EDETACHED == envRes ) {
+ // detached thread - attach to JVM
+ if( JNI_OK != ( envRes = (*jvmHandle)->AttachCurrentThread(jvmHandle, (void**) &newEnv, NULL) ) ) {
+ fprintf(stderr, "NEWT X11 Error: can't attach thread: %d\n", envRes);
+ return;
+ }
+ curEnv = newEnv;
+ } else if( JNI_OK != envRes ) {
+ // oops ..
+ fprintf(stderr, "NEWT X11 Error: can't GetEnv: %d\n", envRes);
+ return;
+ }
+ NewtCommon_throwNewRuntimeException(curEnv, "Info: NEWT X11 Error: Display %p, Code 0x%X, errno %s",
+ dpy, e->error_code, errStr);
+
+ if( NULL != newEnv ) {
+ // detached attached thread
+ (*jvmHandle)->DetachCurrentThread(jvmHandle);
+ }
}
return 0;
@@ -513,10 +537,11 @@ JNIEXPORT void JNICALL Java_jogamp_newt_x11_X11Display_DispatchMessages0
char keyChar = 0;
char text[255];
- // QueuedAlready : No I/O Flush or system call doesn't work on some cards (eg ATI) ?)
- // QueuedAfterFlush == XPending(): I/O Flush only if no already queued events are available
- // QueuedAfterReading : QueuedAlready + if queue==0, attempt to read more ..
- if ( 0 >= XEventsQueued(dpy, QueuedAfterFlush) ) {
+ // XEventsQueued(dpy, X):
+ // QueuedAlready : No I/O Flush or system call doesn't work on some cards (eg ATI) ?)
+ // QueuedAfterFlush == XPending(): I/O Flush only if no already queued events are available
+ // QueuedAfterReading : QueuedAlready + if queue==0, attempt to read more ..
+ if ( 0 >= XPending(dpy) ) {
// DBG_PRINT( "X11: DispatchMessages 0x%X - Leave 1\n", dpy);
return;
}
@@ -583,8 +608,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_x11_X11Display_DispatchMessages0
case ButtonPress:
(*env)->CallVoidMethod(env, jwindow, enqueueRequestFocusID, JNI_FALSE);
#ifdef USE_SENDIO_DIRECT
- (*env)->CallVoidMethod(env, jwindow, sendMouseEventID,
- (jint) EVENT_MOUSE_PRESSED,
+ (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED,
modifiers,
(jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/);
#else
@@ -1318,7 +1342,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_x11_X11Window_CreateWindow0
}
attrMask = ( CWBackingStore | CWBackingPlanes | CWBackingPixel | CWBackPixmap |
- CWBorderPixel | CWColormap | CWOverrideRedirect ) ;
+ CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask ) ;
memset(&xswa, 0, sizeof(xswa));
xswa.override_redirect = False; // use the window manager, always
@@ -1327,6 +1351,9 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_x11_X11Window_CreateWindow0
xswa.backing_store=NotUseful; /* NotUseful, WhenMapped, Always */
xswa.backing_planes=0; /* planes to be preserved if possible */
xswa.backing_pixel=0; /* value to use in restoring planes */
+ xswa.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask ;
+ xswa.event_mask |= KeyPressMask | KeyReleaseMask ;
+ xswa.event_mask |= FocusChangeMask | SubstructureNotifyMask | StructureNotifyMask | ExposureMask ;
xswa.colormap = XCreateColormap(dpy,
windowParent,
@@ -1354,18 +1381,6 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_x11_X11Window_CreateWindow0
setJavaWindowProperty(env, dpy, window, javaObjectAtom, (*env)->NewGlobalRef(env, obj));
- // XClearWindow(dpy, window);
- XSync(dpy, False);
-
- {
- long xevent_mask = 0;
- xevent_mask |= ButtonPressMask | ButtonReleaseMask | PointerMotionMask ;
- xevent_mask |= KeyPressMask | KeyReleaseMask ;
- xevent_mask |= FocusChangeMask | SubstructureNotifyMask | StructureNotifyMask | ExposureMask ;
-
- XSelectInput(dpy, window, xevent_mask);
- }
-
NewtWindows_setDecorations(dpy, window, ( JNI_TRUE == undecorated ) ? False : True );
XSync(dpy, False);
diff --git a/src/test/com/jogamp/opengl/test/junit/util/UITestCase.java b/src/test/com/jogamp/opengl/test/junit/util/UITestCase.java
index a25835596..9856616d1 100644
--- a/src/test/com/jogamp/opengl/test/junit/util/UITestCase.java
+++ b/src/test/com/jogamp/opengl/test/junit/util/UITestCase.java
@@ -59,6 +59,18 @@ public abstract class UITestCase {
}
}
+ public final String getTestMethodName() {
+ return _unitTestName.getMethodName();
+ }
+
+ public final String getSimpleTestName() {
+ return getClass().getSimpleName()+" - "+getTestMethodName();
+ }
+
+ public final String getFullTestName() {
+ return getClass().getName()+" - "+getTestMethodName();
+ }
+
@BeforeClass
public static void oneTimeSetUp() {
// one-time initialization code
@@ -74,12 +86,12 @@ public abstract class UITestCase {
@Before
public void setUp() {
initSingletonInstance();
- System.err.println("++++ UITestCase.setUp: "+getClass().getName()+" - "+_unitTestName.getMethodName());
+ System.err.println("++++ UITestCase.setUp: "+getFullTestName());
}
@After
public void tearDown() {
- System.err.println("++++ UITestCase.tearDown: "+getClass().getName()+" - "+_unitTestName.getMethodName());
+ System.err.println("++++ UITestCase.tearDown: "+getFullTestName());
}
}