diff options
author | Sven Gothel <[email protected]> | 2012-07-05 14:32:00 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2012-07-05 14:32:00 +0200 |
commit | fd06292d4a208cbd613f4bdce7cae12e075e70ec (patch) | |
tree | 75bf50a19e631c22f575f516248c5681dab3eda9 | |
parent | 9b35c57425b0a5f6b789b9b43a62a8b64be51d86 (diff) |
NativeWindow/Newt X11ErrorHandler enhancement / unification - don't throw exceptions. Handles also XAWT BadMatch X_SetInputFocus.
X11ErrorHandler code now dumps proper information about the opcode and error message and the running Java thread.
Having propery "nativewindow.debug.X11Util.XErrorStackDump" or "nativewindow.debug=all' set,
a stack trace is dumped.
Since the X11ErrorHandler may catch an XAWT error: BadMatch X_SetInputFocus,
we cannot throw an exception and better keep running.
-rw-r--r-- | src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java | 23 | ||||
-rw-r--r-- | src/nativewindow/native/NativewindowCommon.c | 19 | ||||
-rw-r--r-- | src/nativewindow/native/NativewindowCommon.h | 1 | ||||
-rw-r--r-- | src/nativewindow/native/x11/Xmisc.c | 208 | ||||
-rw-r--r-- | src/nativewindow/native/x11/Xmisc.h | 44 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/x11/X11Display.java | 4 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/x11/X11Window.java | 3 | ||||
-rw-r--r-- | src/newt/native/NewtCommon.c | 19 | ||||
-rw-r--r-- | src/newt/native/NewtCommon.h | 1 | ||||
-rw-r--r-- | src/newt/native/X11Common.h | 2 | ||||
-rw-r--r-- | src/newt/native/X11Display.c | 81 | ||||
-rw-r--r-- | src/newt/native/X11Window.c | 12 |
12 files changed, 276 insertions, 141 deletions
diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java index 3c197062a..fcc374751 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java @@ -81,9 +81,10 @@ public class X11Util { /** Value is <code>true</code>, best 'stable' results if not using XLockDisplay/XUnlockDisplay at all. */ public static final boolean HAS_XLOCKDISPLAY_BUG = true; - private static final boolean DEBUG = Debug.debug("X11Util"); - private static final boolean TRACE_DISPLAY_LIFECYCLE = Debug.getBooleanProperty("nativewindow.debug.X11Util.TraceDisplayLifecycle", true); - + public static final boolean DEBUG = Debug.debug("X11Util"); + public static final boolean XSYNC_ENABLED = Debug.isPropertyDefined("nativewindow.debug.X11Util.XSync", true); + public static final boolean XERROR_STACKDUMP = DEBUG || Debug.isPropertyDefined("nativewindow.debug.X11Util.XErrorStackDump", true); + private static final boolean TRACE_DISPLAY_LIFECYCLE = Debug.isPropertyDefined("nativewindow.debug.X11Util.TraceDisplayLifecycle", true); private static String nullDisplayName = null; private static boolean isX11LockAvailable = false; private static boolean requiresX11Lock = true; @@ -105,11 +106,14 @@ public class X11Util { } final boolean callXInitThreads = XINITTHREADS_ALWAYS_ENABLED || firstX11ActionOnProcess; - final boolean isXInitThreadsOK = initialize0( XINITTHREADS_ALWAYS_ENABLED || firstX11ActionOnProcess ); + final boolean isXInitThreadsOK = initialize0( XINITTHREADS_ALWAYS_ENABLED || firstX11ActionOnProcess, XERROR_STACKDUMP); isX11LockAvailable = isXInitThreadsOK && !HAS_XLOCKDISPLAY_BUG ; final long dpy = X11Lib.XOpenDisplay(null); if(0 != dpy) { + if(XSYNC_ENABLED) { + X11Lib.XSynchronize(dpy, true); + } try { nullDisplayName = X11Lib.XDisplayString(dpy); } finally { @@ -124,7 +128,8 @@ public class X11Util { ", requiresX11Lock "+requiresX11Lock+ ", XInitThreads [called "+callXInitThreads+", OK "+isXInitThreadsOK+"]"+ ", isX11LockAvailable "+isX11LockAvailable+ - ", X11 Display(NULL) <"+nullDisplayName+">"); + ", X11 Display(NULL) <"+nullDisplayName+">"+ + ", XSynchronize Enabled: "+XSYNC_ENABLED); // Thread.dumpStack(); } } @@ -455,6 +460,9 @@ public class X11Util { NativeWindowFactory.getDefaultToolkitLock().lock(); try { long handle = X11Lib.XOpenDisplay(arg0); + if(XSYNC_ENABLED && 0 != handle) { + X11Lib.XSynchronize(handle, true); + } if(TRACE_DISPLAY_LIFECYCLE) { System.err.println(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle)); // Thread.dumpStack(); @@ -520,7 +528,10 @@ public class X11Util { return false; } - private static native boolean initialize0(boolean firstUIActionOnProcess); + private static final String getCurrentThreadName() { return Thread.currentThread().getName(); } // Callback for JNI + private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI + + private static native boolean initialize0(boolean firstUIActionOnProcess, boolean debug); private static native void shutdown0(); private static native void setX11ErrorHandler0(boolean onoff, boolean quiet); } diff --git a/src/nativewindow/native/NativewindowCommon.c b/src/nativewindow/native/NativewindowCommon.c index b866646a6..d2fdd5d69 100644 --- a/src/nativewindow/native/NativewindowCommon.c +++ b/src/nativewindow/native/NativewindowCommon.c @@ -1,5 +1,6 @@ #include "NativewindowCommon.h" +#include <string.h> static const char * const ClazzNameRuntimeException = "java/lang/RuntimeException"; static jclass runtimeExceptionClz=NULL; @@ -45,6 +46,24 @@ int NativewindowCommon_init(JNIEnv *env) { return 0; } +const char * NativewindowCommon_GetStaticStringMethod(JNIEnv *jniEnv, jclass clazz, jmethodID jGetStrID, char *dest, int destSize, const char *altText) { + if(NULL != jniEnv && NULL != clazz && NULL != jGetStrID) { + jstring jstr = (jstring) (*jniEnv)->CallStaticObjectMethod(jniEnv, clazz, jGetStrID); + if(NULL != jstr) { + const char * str = (*jniEnv)->GetStringUTFChars(jniEnv, jstr, NULL); + if( NULL != str) { + strncpy(dest, str, destSize-1); + dest[destSize-1] = 0; // EOS + (*jniEnv)->ReleaseStringUTFChars(jniEnv, jstr, str); + return dest; + } + } + } + strncpy(dest, altText, destSize-1); + dest[destSize-1] = 0; // EOS + return dest; +} + jchar* NativewindowCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) { jchar* strChars = NULL; diff --git a/src/nativewindow/native/NativewindowCommon.h b/src/nativewindow/native/NativewindowCommon.h index 41c4bd0eb..73b890c4f 100644 --- a/src/nativewindow/native/NativewindowCommon.h +++ b/src/nativewindow/native/NativewindowCommon.h @@ -7,6 +7,7 @@ int NativewindowCommon_init(JNIEnv *env); +const char * NativewindowCommon_GetStaticStringMethod(JNIEnv *jniEnv, jclass clazz, jmethodID jGetStrID, char *dest, int destSize, const char *altText); jchar* NativewindowCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str); void NativewindowCommon_FatalError(JNIEnv *env, const char* msg, ...); diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index 439d9b334..5cbf5c04a 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -26,15 +26,19 @@ * or implied, of JogAmp Community. */ +#include "NativewindowCommon.h" +#include "Xmisc.h" +#include "jogamp_nativewindow_x11_X11Lib.h" + +// #define VERBOSE_ON 1 + +#ifdef VERBOSE_ON + #define DBG_PRINT(args...) fprintf(stderr, args); +#else + #define DBG_PRINT(args...) +#endif + -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <unistd.h> -#include <errno.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> /* Linux headers don't work properly */ #define __USE_GNU #include <dlfcn.h> @@ -80,17 +84,6 @@ Bool XF86VidModeSetGammaRamp( #define RTLD_DEFAULT NULL #endif -#include "NativewindowCommon.h" -#include "jogamp_nativewindow_x11_X11Lib.h" - -// #define VERBOSE_ON 1 - -#ifdef VERBOSE_ON - #define DBG_PRINT(args...) fprintf(stderr, args); -#else - #define DBG_PRINT(args...) -#endif - static const char * const ClazzNameBuffers = "com/jogamp/common/nio/Buffers"; static const char * const ClazzNameBuffersStaticCstrName = "copyByteBuffer"; static const char * const ClazzNameBuffersStaticCstrSignature = "(Ljava/nio/ByteBuffer;)Ljava/nio/ByteBuffer;"; @@ -98,6 +91,9 @@ static const char * const ClazzNameByteBuffer = "java/nio/ByteBuffer"; static const char * const ClazzNamePoint = "javax/media/nativewindow/util/Point"; static const char * const ClazzAnyCstrName = "<init>"; static const char * const ClazzNamePointCstrSignature = "(II)V"; +static jclass X11UtilClazz = NULL; +static jmethodID getCurrentThreadNameID = NULL; +static jmethodID dumpStackID = NULL; static jclass clazzBuffers = NULL; static jmethodID cstrBuffers = NULL; static jclass clazzByteBuffer = NULL; @@ -109,6 +105,15 @@ static void _initClazzAccess(JNIEnv *env) { if(!NativewindowCommon_init(env)) return; + getCurrentThreadNameID = (*env)->GetStaticMethodID(env, X11UtilClazz, "getCurrentThreadName", "()Ljava/lang/String;"); + if(NULL==getCurrentThreadNameID) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't get method getCurrentThreadName"); + } + dumpStackID = (*env)->GetStaticMethodID(env, X11UtilClazz, "dumpStack", "()V"); + if(NULL==dumpStackID) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't get method dumpStack"); + } + c = (*env)->FindClass(env, ClazzNameBuffers); if(NULL==c) { NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNameBuffers); @@ -162,66 +167,71 @@ static void setupJVMVars(JNIEnv * env) { } static XErrorHandler origErrorHandler = NULL ; -static int errorHandlerBlocked = 0 ; static int errorHandlerQuiet = 0 ; +static int errorHandlerDebug = 0 ; +static int errorHandlerThrowException = 0; static int x11ErrorHandler(Display *dpy, XErrorEvent *e) { if(!errorHandlerQuiet) { - JNIEnv *curEnv = NULL; - JNIEnv *newEnv = NULL; - int envRes ; - const char * errStr = strerror(errno); + const char * errnoStr = strerror(errno); + char threadName[80]; + char errCodeStr[80]; + char reqCodeStr[80]; - fprintf(stderr, "Info: Nativewindow X11 Error: Display %p, Code 0x%X, errno %s\n", dpy, e->error_code, errStr); - fflush(stderr); + int shallBeDetached = 0; + JNIEnv *jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); - // 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; + (void) NativewindowCommon_GetStaticStringMethod(jniEnv, X11UtilClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); + snprintf(errCodeStr, sizeof(errCodeStr), "%d", e->request_code); + XGetErrorDatabaseText(dpy, "XRequest", errCodeStr, "Unknown", reqCodeStr, sizeof(reqCodeStr)); + XGetErrorText(dpy, e->error_code, errCodeStr, sizeof(errCodeStr)); + + fprintf(stderr, "Info: Nativewindow X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", + threadName, e->error_code, errCodeStr, e->display, e->resourceid, e->serial, + e->request_code, e->minor_code, reqCodeStr); + + if( errorHandlerDebug ) { + (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); + } + + if(errorHandlerThrowException) { + if(NULL != jniEnv) { + NativewindowCommon_throwNewRuntimeException(jniEnv, "Nativewindow X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", + threadName, e->error_code, errCodeStr, e->display, e->resourceid, e->serial, + e->request_code, e->minor_code, reqCodeStr); + } else { + fprintf(stderr, "Nativewindow X11 Error: null JNIEnv"); + #if 0 + if(NULL!=origErrorHandler) { + origErrorHandler(dpy, e); + } + #endif } - 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); + fflush(stderr); - if( NULL != newEnv ) { - // detached attached thread + if (NULL != jniEnv && shallBeDetached) { (*jvmHandle)->DetachCurrentThread(jvmHandle); } } -#if 0 - if(NULL!=origErrorHandler) { - origErrorHandler(dpy, e); - } -#endif - return 0; } -static void x11ErrorHandlerEnable(Display *dpy, int onoff, JNIEnv * env) { - if(errorHandlerBlocked) return; - +void NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync) { + errorHandlerQuiet = quiet; if(onoff) { if(NULL==origErrorHandler) { setupJVMVars(env); - if(NULL!=dpy) { + origErrorHandler = XSetErrorHandler(x11ErrorHandler); + if(sync && NULL!=dpy) { XSync(dpy, False); } - origErrorHandler = XSetErrorHandler(x11ErrorHandler); } } else { if(NULL!=origErrorHandler) { - if(NULL!=dpy) { + if(sync && NULL!=dpy) { XSync(dpy, False); } XSetErrorHandler(origErrorHandler); @@ -230,46 +240,27 @@ static void x11ErrorHandlerEnable(Display *dpy, int onoff, JNIEnv * env) { } } -static void x11ErrorHandlerEnableBlocking(JNIEnv * env, int onoff, int quiet) { - errorHandlerBlocked = 0 ; - x11ErrorHandlerEnable(NULL, onoff, env); - errorHandlerBlocked = onoff ; - errorHandlerQuiet = quiet; -} - - static XIOErrorHandler origIOErrorHandler = NULL; static int x11IOErrorHandler(Display *dpy) { - JNIEnv *curEnv = NULL; - JNIEnv *newEnv = NULL; - int envRes ; const char * dpyName = XDisplayName(NULL); - const char * errStr = strerror(errno); + const char * errnoStr = strerror(errno); + char threadName[80]; + int shallBeDetached = 0; + JNIEnv *jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); - fprintf(stderr, "Nativewindow X11 IOError: Display %p (%s): %s\n", dpy, dpyName, errStr); + (void) NativewindowCommon_GetStaticStringMethod(jniEnv, X11UtilClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); - // 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; - } + fprintf(stderr, "Nativewindow X11 IOError (Thread %s): Display %p (%s): %s\n", threadName, dpy, dpyName, errnoStr); + (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); - NativewindowCommon_FatalError(curEnv, "Nativewindow X11 IOError: Display %p (%s): %s", dpy, dpyName, errStr); + if (NULL != jniEnv) { + NativewindowCommon_FatalError(jniEnv, "Nativewindow X11 IOError (Thread %s): Display %p (%s): %s", threadName, dpy, dpyName, errnoStr); - if( NULL != newEnv ) { - // detached attached thread - (*jvmHandle)->DetachCurrentThread(jvmHandle); + if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } } if(NULL!=origIOErrorHandler) { origIOErrorHandler(dpy); @@ -293,22 +284,31 @@ static int _initialized=0; static jboolean _xinitThreadsOK=JNI_FALSE; JNIEXPORT jboolean JNICALL -Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass _unused, jboolean firstUIActionOnProcess) { +Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, jboolean firstUIActionOnProcess, jboolean debug) { if(0==_initialized) { + if(debug) { + errorHandlerDebug = 1; + } + X11UtilClazz = (jclass)(*env)->NewGlobalRef(env, clazz); if( JNI_TRUE == firstUIActionOnProcess ) { if( 0 == XInitThreads() ) { fprintf(stderr, "Warning: XInitThreads() failed\n"); } else { _xinitThreadsOK=JNI_TRUE; - DBG_PRINT( "X11: XInitThreads() called for concurrent Thread support\n"); + if(debug) { + fprintf(stderr, "X11: XInitThreads() called for concurrent Thread support\n"); + } } - } else { - DBG_PRINT( "X11: XInitThreads() _not_ called for concurrent Thread support\n"); + } else if(debug) { + fprintf(stderr, "X11: XInitThreads() _not_ called for concurrent Thread support\n"); } _initClazzAccess(env); x11IOErrorHandlerEnable(1, env); _initialized=1; + if(JNI_TRUE == debug) { + fprintf(stderr, "Info: NativeWindow native init passed\n"); + } } return _xinitThreadsOK; } @@ -320,7 +320,7 @@ Java_jogamp_nativewindow_x11_X11Util_shutdown0(JNIEnv *env, jclass _unused) { JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Util_setX11ErrorHandler0(JNIEnv *env, jclass _unused, jboolean onoff, jboolean quiet) { - x11ErrorHandlerEnableBlocking(env, ( JNI_TRUE == onoff ) ? 1 : 0, ( JNI_TRUE == quiet ) ? 1 : 0); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, onoff ? 1 : 0, quiet ? 1 : 0, 0 /* no dpy, no sync */); } /* Java->C glue code: @@ -345,9 +345,9 @@ Java_jogamp_nativewindow_x11_X11Lib_XGetVisualInfo1__JJLjava_nio_ByteBuffer_2Lja if (arg3 != NULL) { _ptr3 = (int *) (((char*) (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) + arg3_byte_offset); } - x11ErrorHandlerEnable((Display *) (intptr_t) arg0, 1, env); + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 1, 0, 0); _res = XGetVisualInfo((Display *) (intptr_t) arg0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3); - x11ErrorHandlerEnable((Display *) (intptr_t) arg0, 0, env); + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, 0); count = _ptr3[0]; if (arg3 != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0); @@ -368,9 +368,9 @@ Java_jogamp_nativewindow_x11_X11Lib_DefaultVisualID(JNIEnv *env, jclass _unused, if(0==display) { NativewindowCommon_FatalError(env, "invalid display connection.."); } - x11ErrorHandlerEnable((Display *) (intptr_t) display, 1, env); + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 1, 0, 0); r = (jlong) XVisualIDFromVisual( DefaultVisual( (Display*) (intptr_t) display, screen ) ); - x11ErrorHandlerEnable((Display *) (intptr_t) display, 0, env); + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, 0); return r; } @@ -411,9 +411,9 @@ Java_jogamp_nativewindow_x11_X11Lib_XCloseDisplay__J(JNIEnv *env, jclass _unused if(0==display) { NativewindowCommon_FatalError(env, "invalid display connection.."); } - x11ErrorHandlerEnable((Display *) (intptr_t) display, 1, env); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 0, 0); _res = XCloseDisplay((Display *) (intptr_t) display); - x11ErrorHandlerEnable(NULL, 0, env); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0); return _res; } @@ -451,7 +451,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow return 0; } - x11ErrorHandlerEnable(dpy, 1, env); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); scrn = ScreenOfDisplay(dpy, scrn_idx); @@ -471,7 +471,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow if (visual==NULL) { - x11ErrorHandlerEnable(dpy, 0, env); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); NativewindowCommon_throwNewRuntimeException(env, "could not query Visual by given VisualID, bail out!"); return 0; } @@ -511,13 +511,11 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow visual, attrMask, &xswa); - XSync(dpy, False); XSelectInput(dpy, window, 0); // no events - XSync(dpy, False); - x11ErrorHandlerEnable(dpy, 0, env); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); DBG_PRINT( "X11: [CreateWindow] created window %p on display %p\n", window, dpy); @@ -541,11 +539,11 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyDummyWindow return; } - x11ErrorHandlerEnable(dpy, 1, env); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); XUnmapWindow(dpy, w); XSync(dpy, False); XDestroyWindow(dpy, w); - x11ErrorHandlerEnable(dpy, 0, env); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); } /* @@ -569,11 +567,11 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_x11_X11Lib_GetRelativeLocatio if( 0 == jdest_win ) { dest_win = root; } if( 0 == jsrc_win ) { src_win = root; } - x11ErrorHandlerEnable(dpy, 1, env); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); res = XTranslateCoordinates(dpy, src_win, dest_win, src_x, src_y, &dest_x, &dest_y, &child); - x11ErrorHandlerEnable(dpy, 0, env); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0); DBG_PRINT( "X11: GetRelativeLocation0: %p %d/%d -> %p %d/%d - ok: %d\n", (void*)src_win, src_x, src_y, (void*)dest_win, dest_x, dest_y, (int)res); diff --git a/src/nativewindow/native/x11/Xmisc.h b/src/nativewindow/native/x11/Xmisc.h new file mode 100644 index 000000000..a44da950d --- /dev/null +++ b/src/nativewindow/native/x11/Xmisc.h @@ -0,0 +1,44 @@ +/** + * Copyright 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 met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#ifndef Xmisc_h +#define Xmisc_h + +#include <jni.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <unistd.h> +#include <errno.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +void NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync); + +#endif /* Xmisc_h */ diff --git a/src/newt/classes/jogamp/newt/driver/x11/X11Display.java b/src/newt/classes/jogamp/newt/driver/x11/X11Display.java index 9464b979b..8243fcf9d 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/X11Display.java +++ b/src/newt/classes/jogamp/newt/driver/x11/X11Display.java @@ -49,7 +49,7 @@ public class X11Display extends DisplayImpl { static { NEWTJNILibLoader.loadNEWT(); - if ( !initIDs0() ) { + if ( !initIDs0(X11Util.XERROR_STACKDUMP) ) { throw new NativeWindowException("Failed to initialize X11Display jmethodIDs"); } @@ -139,7 +139,7 @@ public class X11Display extends DisplayImpl { //---------------------------------------------------------------------- // Internals only // - private static native boolean initIDs0(); + private static native boolean initIDs0(boolean debug); private native void CompleteDisplay0(long handle); diff --git a/src/newt/classes/jogamp/newt/driver/x11/X11Window.java b/src/newt/classes/jogamp/newt/driver/x11/X11Window.java index 143b94a57..9a5074c29 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/X11Window.java +++ b/src/newt/classes/jogamp/newt/driver/x11/X11Window.java @@ -230,6 +230,9 @@ public class X11Window extends WindowImpl { // Internals only // + private static final String getCurrentThreadName() { return Thread.currentThread().getName(); } // Callback for JNI + private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI + private final long getDisplayEDTHandle() { return ((X11Display) getScreen().getDisplay()).getEDTHandle(); } diff --git a/src/newt/native/NewtCommon.c b/src/newt/native/NewtCommon.c index 3713cfd6c..7f070e7d3 100644 --- a/src/newt/native/NewtCommon.c +++ b/src/newt/native/NewtCommon.c @@ -1,5 +1,6 @@ #include "NewtCommon.h" +#include <string.h> static const char * const ClazzNameRuntimeException = "java/lang/RuntimeException"; static jclass runtimeExceptionClz=NULL; @@ -43,6 +44,24 @@ void NewtCommon_init(JNIEnv *env) { } } +const char * NewtCommon_GetStaticStringMethod(JNIEnv *jniEnv, jclass clazz, jmethodID jGetStrID, char *dest, int destSize, const char *altText) { + if(NULL != jniEnv && NULL != clazz && NULL != jGetStrID) { + jstring jstr = (jstring) (*jniEnv)->CallStaticObjectMethod(jniEnv, clazz, jGetStrID); + if(NULL != jstr) { + const char * str = (*jniEnv)->GetStringUTFChars(jniEnv, jstr, NULL); + if( NULL != str) { + strncpy(dest, str, destSize-1); + dest[destSize-1] = 0; // EOS + (*jniEnv)->ReleaseStringUTFChars(jniEnv, jstr, str); + return dest; + } + } + } + strncpy(dest, altText, destSize-1); + dest[destSize-1] = 0; // EOS + return dest; +} + jchar* NewtCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) { jchar* strChars = NULL; diff --git a/src/newt/native/NewtCommon.h b/src/newt/native/NewtCommon.h index f5ca73b74..9a4e5ac70 100644 --- a/src/newt/native/NewtCommon.h +++ b/src/newt/native/NewtCommon.h @@ -34,6 +34,7 @@ void NewtCommon_init(JNIEnv *env); +const char * NewtCommon_GetStaticStringMethod(JNIEnv *jniEnv, jclass clazz, jmethodID jGetStrID, char *dest, int destSize, const char *altText); jchar* NewtCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str); void NewtCommon_FatalError(JNIEnv *env, const char* msg, ...); diff --git a/src/newt/native/X11Common.h b/src/newt/native/X11Common.h index cefef690f..982255b8a 100644 --- a/src/newt/native/X11Common.h +++ b/src/newt/native/X11Common.h @@ -70,9 +70,9 @@ extern jclass X11NewtWindowClazz; extern jmethodID insetsChangedID; extern jmethodID visibleChangedID; +void NewtDisplay_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync); jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong javaObjectAtom, Bool showWarning); -void NewtDisplay_displayDispatchErrorHandlerEnable(int onoff, JNIEnv * env); Status NewtWindows_getRootAndParent (Display *dpy, Window w, Window * root_return, Window * parent_return); Status NewtWindows_updateInsets(JNIEnv *env, jobject jwindow, Display *dpy, Window window, int *left, int *right, int *top, int *bottom); diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c index 88ac0df7e..5e2dc7c61 100644 --- a/src/newt/native/X11Display.c +++ b/src/newt/native/X11Display.c @@ -38,6 +38,8 @@ static const char * const ClazzNameX11NewtWindow = "jogamp/newt/driver/x11/X11Wi static jmethodID displayCompletedID = NULL; +static jmethodID getCurrentThreadNameID = NULL; +static jmethodID dumpStackID = NULL; static jmethodID sizeChangedID = NULL; static jmethodID positionChangedID = NULL; static jmethodID focusChangedID = NULL; @@ -61,32 +63,51 @@ static void setupJVMVars(JNIEnv * env) { } static XErrorHandler origErrorHandler = NULL ; +static int errorHandlerQuiet = 0 ; +static int errorHandlerDebug = 0 ; +static int errorHandlerThrowException = 0; -static int displayDispatchErrorHandler(Display *dpy, XErrorEvent *e) +static int x11ErrorHandler(Display *dpy, XErrorEvent *e) { - fprintf(stderr, "Warning: NEWT X11 Error: DisplayDispatch %p, Code 0x%X, errno %s\n", dpy, e->error_code, strerror(errno)); - - if (e->error_code == BadAtom) { - fprintf(stderr, " BadAtom (%p): Atom probably already removed\n", (void*)e->resourceid); - } else if (e->error_code == BadWindow) { - fprintf(stderr, " BadWindow (%p): Window probably already removed\n", (void*)e->resourceid); - } else { + if(!errorHandlerQuiet) { + const char * errnoStr = strerror(errno); + char threadName[80]; + char errCodeStr[80]; + char reqCodeStr[80]; + int shallBeDetached = 0; - JNIEnv *jniEnv = NULL; - const char * errStr = strerror(errno); + JNIEnv *jniEnv = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); - fprintf(stderr, "Info: NEWT X11 Error: Display %p, Code 0x%X, errno %s\n", dpy, e->error_code, errStr); + (void) NewtCommon_GetStaticStringMethod(jniEnv, X11NewtWindowClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); + snprintf(errCodeStr, sizeof(errCodeStr), "%d", e->request_code); + XGetErrorDatabaseText(dpy, "XRequest", errCodeStr, "Unknown", reqCodeStr, sizeof(reqCodeStr)); + XGetErrorText(dpy, e->error_code, errCodeStr, sizeof(errCodeStr)); - jniEnv = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); - if(NULL==jniEnv) { - fprintf(stderr, "NEWT X11 Error: null JNIEnv"); - return; + fprintf(stderr, "Info: Newt X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", + threadName, e->error_code, errCodeStr, e->display, e->resourceid, e->serial, + e->request_code, e->minor_code, reqCodeStr); + + if( errorHandlerDebug ) { + (*jniEnv)->CallStaticVoidMethod(jniEnv, X11NewtWindowClazz, dumpStackID); } - NewtCommon_throwNewRuntimeException(jniEnv, "Info: NEWT X11 Error: Display %p, Code 0x%X, errno %s", - dpy, e->error_code, errStr); + if(errorHandlerThrowException) { + if(NULL != jniEnv) { + NewtCommon_throwNewRuntimeException(jniEnv, "Newt X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", + threadName, e->error_code, errCodeStr, e->display, e->resourceid, e->serial, + e->request_code, e->minor_code, reqCodeStr); + } else { + fprintf(stderr, "Nativewindow X11 Error: null JNIEnv"); + #if 0 + if(NULL!=origErrorHandler) { + origErrorHandler(dpy, e); + } + #endif + } + } + fflush(stderr); - if (shallBeDetached) { + if (NULL != jniEnv && shallBeDetached) { (*jvmHandle)->DetachCurrentThread(jvmHandle); } } @@ -94,14 +115,21 @@ static int displayDispatchErrorHandler(Display *dpy, XErrorEvent *e) return 0; } -void NewtDisplay_displayDispatchErrorHandlerEnable(int onoff, JNIEnv * env) { +void NewtDisplay_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync) { + errorHandlerQuiet = quiet; if(onoff) { if(NULL==origErrorHandler) { setupJVMVars(env); - origErrorHandler = XSetErrorHandler(displayDispatchErrorHandler); + origErrorHandler = XSetErrorHandler(x11ErrorHandler); + if(sync && NULL!=dpy) { + XSync(dpy, False); + } } } else { if(NULL!=origErrorHandler) { + if(sync && NULL!=dpy) { + XSync(dpy, False); + } XSetErrorHandler(origErrorHandler); origErrorHandler = NULL; } @@ -241,10 +269,13 @@ static jint X11InputState2NewtModifiers(unsigned int xstate) { * Signature: (Z)Z */ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Display_initIDs0 - (JNIEnv *env, jclass clazz) + (JNIEnv *env, jclass clazz, jboolean debug) { jclass c; + if(debug) { + errorHandlerDebug = 1 ; + } NewtCommon_init(env); if(NULL==X11NewtWindowClazz) { @@ -260,6 +291,8 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Display_initIDs0 } displayCompletedID = (*env)->GetMethodID(env, clazz, "displayCompleted", "(JJ)V"); + getCurrentThreadNameID = (*env)->GetStaticMethodID(env, X11NewtWindowClazz, "getCurrentThreadName", "()Ljava/lang/String;"); + dumpStackID = (*env)->GetStaticMethodID(env, X11NewtWindowClazz, "dumpStack", "()V"); insetsChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "insetsChanged", "(ZIIII)V"); sizeChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sizeChanged", "(ZIIZ)V"); positionChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "positionChanged", "(ZII)V"); @@ -275,6 +308,8 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Display_initIDs0 requestFocusID = (*env)->GetMethodID(env, X11NewtWindowClazz, "requestFocus", "(Z)V"); if (displayCompletedID == NULL || + getCurrentThreadNameID == NULL || + dumpStackID == NULL || insetsChangedID == NULL || sizeChangedID == NULL || positionChangedID == NULL || @@ -403,7 +438,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Display_DispatchMessages0 // DBG_PRINT( "X11: DispatchMessages dpy %p, win %p, Event %d\n", (void*)dpy, (void*)evt.xany.window, (int)evt.type); - NewtDisplay_displayDispatchErrorHandlerEnable(1, env); + NewtDisplay_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); jwindow = getJavaWindowProperty(env, dpy, evt.xany.window, javaObjectAtom, #ifdef VERBOSE_ON @@ -413,7 +448,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Display_DispatchMessages0 #endif ); - NewtDisplay_displayDispatchErrorHandlerEnable(0, env); + NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); if(NULL==jwindow) { fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d for X11 window %p\n", diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index 0f93b3e76..daf9f2b53 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -683,12 +683,16 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Window_CloseWindow0 DBG_PRINT( "X11: CloseWindow START dpy %p, win %p\n", (void*)dpy, (void*)w); + NewtDisplay_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); + jwindow = getJavaWindowProperty(env, dpy, w, javaObjectAtom, True); if(NULL==jwindow) { + NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); NewtCommon_throwNewRuntimeException(env, "could not fetch Java Window object, bail out!"); return; } if ( JNI_FALSE == (*env)->IsSameObject(env, jwindow, obj) ) { + NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); NewtCommon_throwNewRuntimeException(env, "Internal Error .. Window global ref not the same!"); return; } @@ -696,7 +700,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Window_CloseWindow0 XSync(dpy, False); XSelectInput(dpy, w, 0); XUnmapWindow(dpy, w); - XSync(dpy, False); + NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); // Drain all events related to this window .. Java_jogamp_newt_driver_x11_X11Display_DispatchMessages0(env, obj, display, javaObjectAtom, windowDeleteAtom); @@ -757,7 +761,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Window_reconfigureWindow0 fsEWMHFlags |= _NET_WM_ABOVE; // toggle above } - NewtDisplay_displayDispatchErrorHandlerEnable(1, env); + NewtDisplay_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); DBG_PRINT( "X11: reconfigureWindow0 dpy %p, scrn %d, parent %p/%p, win %p, %d/%d %dx%d, parentChange %d, hasParent %d, decorationChange %d, undecorated %d, fullscreenChange %d, fullscreen %d, alwaysOnTopChange %d, alwaysOnTop %d, visibleChange %d, visible %d, tempInvisible %d, fsEWMHFlags %d\n", (void*)dpy, screen_index, (void*) jparent, (void*)parent, (void*)w, @@ -775,7 +779,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Window_reconfigureWindow0 ( TST_FLAG_CHANGE_FULLSCREEN(flags) || TST_FLAG_CHANGE_ALWAYSONTOP(flags) ) ) { Bool enable = TST_FLAG_CHANGE_FULLSCREEN(flags) ? TST_FLAG_IS_FULLSCREEN(flags) : TST_FLAG_IS_ALWAYSONTOP(flags) ; if( NewtWindows_setFullscreenEWMH(dpy, root, w, fsEWMHFlags, isVisible, enable) ) { - NewtDisplay_displayDispatchErrorHandlerEnable(0, env); + NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); #ifdef FS_GRAB_KEYBOARD if(TST_FLAG_CHANGE_FULLSCREEN(flags)) { if(TST_FLAG_IS_FULLSCREEN(flags)) { @@ -859,7 +863,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Window_reconfigureWindow0 #endif } - NewtDisplay_displayDispatchErrorHandlerEnable(0, env); + NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); DBG_PRINT( "X11: reconfigureWindow0 X\n"); } |