diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java | 49 | ||||
-rw-r--r-- | src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java | 36 | ||||
-rw-r--r-- | src/nativewindow/native/x11/Xmisc.c | 69 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/x11/X11Display.java | 2 | ||||
-rw-r--r-- | src/newt/native/X11Window.c | 61 | ||||
-rw-r--r-- | src/test/com/jogamp/opengl/test/junit/util/UITestCase.java | 16 |
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()); } } |