diff options
Diffstat (limited to 'src/nativewindow/native')
-rw-r--r-- | src/nativewindow/native/JAWT_DrawingSurfaceInfo.c | 2 | ||||
-rw-r--r-- | src/nativewindow/native/NativewindowCommon.c | 117 | ||||
-rw-r--r-- | src/nativewindow/native/NativewindowCommon.h | 64 | ||||
-rw-r--r-- | src/nativewindow/native/macosx/NativeWindowProtocols.h | 58 | ||||
-rw-r--r-- | src/nativewindow/native/macosx/OSXmisc.m | 833 | ||||
-rw-r--r-- | src/nativewindow/native/win32/DeviceDriverQuery.txt | 41 | ||||
-rw-r--r-- | src/nativewindow/native/win32/GDImisc.c | 542 | ||||
-rw-r--r-- | src/nativewindow/native/win32/WindowsDWM.h | 2 | ||||
-rw-r--r-- | src/nativewindow/native/x11/Xmisc.c | 453 | ||||
-rw-r--r-- | src/nativewindow/native/x11/Xmisc.h | 2 |
10 files changed, 1707 insertions, 407 deletions
diff --git a/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c b/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c index 2a6651007..5c77b6d46 100644 --- a/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c +++ b/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c @@ -43,7 +43,7 @@ #define PLATFORM_DSI_SIZE sizeof(JAWT_Win32DrawingSurfaceInfo) #elif defined(linux) || defined(__sun) || defined(__FreeBSD__) || defined(_HPUX) #define PLATFORM_DSI_SIZE sizeof(JAWT_X11DrawingSurfaceInfo) -#elif defined(macosx) +#elif defined(__APPLE__) #define PLATFORM_DSI_SIZE sizeof(JAWT_MacOSXDrawingSurfaceInfo) #else ERROR: port JAWT_DrawingSurfaceInfo.c to your platform diff --git a/src/nativewindow/native/NativewindowCommon.c b/src/nativewindow/native/NativewindowCommon.c index d2fdd5d69..e65f87272 100644 --- a/src/nativewindow/native/NativewindowCommon.c +++ b/src/nativewindow/native/NativewindowCommon.c @@ -1,21 +1,57 @@ #include "NativewindowCommon.h" #include <string.h> +#include <sys/time.h> + +// #define STDERR_TO_FILE 1 static const char * const ClazzNameRuntimeException = "java/lang/RuntimeException"; static jclass runtimeExceptionClz=NULL; +static JavaVM *_jvmHandle = NULL; +static int _jvmVersion = 0; + +int NativewindowCommon_init(JNIEnv *env) { + if(NULL==_jvmHandle) { + if(0 != (*env)->GetJavaVM(env, &_jvmHandle)) { + NativewindowCommon_FatalError(env, "Nativewindow: Can't fetch JavaVM handle"); + } else { + _jvmVersion = (*env)->GetVersion(env); + } + jclass c = (*env)->FindClass(env, ClazzNameRuntimeException); + if(NULL==c) { + NativewindowCommon_FatalError(env, "Nativewindow: Can't find %s", ClazzNameRuntimeException); + } + runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==runtimeExceptionClz) { + NativewindowCommon_FatalError(env, "Nativewindow: Can't use %s", ClazzNameRuntimeException); + } + #ifdef STDERR_TO_FILE + FILE * old_stderr = stderr; + FILE * new_stderr = freopen("jogamp_stderr.log", "w", stderr); + fprintf(stderr, "STDERR_TO_FILE: %p -> %p\n", old_stderr, new_stderr); + #endif + return 1; + } + return 0; +} + void NativewindowCommon_FatalError(JNIEnv *env, const char* msg, ...) { char buffer[512]; va_list ap; - va_start(ap, msg); - vsnprintf(buffer, sizeof(buffer), msg, ap); - va_end(ap); + if( NULL != msg ) { + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); - fprintf(stderr, "%s\n", buffer); - (*env)->FatalError(env, buffer); + fprintf(stderr, "%s\n", buffer); + if(NULL != env) { + (*env)->FatalError(env, buffer); + } + } } void NativewindowCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...) @@ -23,27 +59,20 @@ void NativewindowCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, . char buffer[512]; va_list ap; - va_start(ap, msg); - vsnprintf(buffer, sizeof(buffer), msg, ap); - va_end(ap); + if(NULL==_jvmHandle) { + NativewindowCommon_FatalError(env, "Nativewindow: NULL JVM handle, call NativewindowCommon_init 1st\n"); + return; + } - (*env)->ThrowNew(env, runtimeExceptionClz, buffer); -} + if( NULL != msg ) { + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); -int NativewindowCommon_init(JNIEnv *env) { - if(NULL==runtimeExceptionClz) { - jclass c = (*env)->FindClass(env, ClazzNameRuntimeException); - if(NULL==c) { - NativewindowCommon_FatalError(env, "Nativewindow: can't find %s", ClazzNameRuntimeException); - } - runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==runtimeExceptionClz) { - NativewindowCommon_FatalError(env, "Nativewindow: can't use %s", ClazzNameRuntimeException); + if(NULL != env) { + (*env)->ThrowNew(env, runtimeExceptionClz, buffer); } - return 1; } - return 0; } const char * NativewindowCommon_GetStaticStringMethod(JNIEnv *jniEnv, jclass clazz, jmethodID jGetStrID, char *dest, int destSize, const char *altText) { @@ -67,37 +96,63 @@ const char * NativewindowCommon_GetStaticStringMethod(JNIEnv *jniEnv, jclass cla jchar* NativewindowCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) { jchar* strChars = NULL; - strChars = calloc((*env)->GetStringLength(env, str) + 1, sizeof(jchar)); - if (strChars != NULL) { - (*env)->GetStringRegion(env, str, 0, (*env)->GetStringLength(env, str), strChars); + if( NULL != env && 0 != str ) { + strChars = calloc((*env)->GetStringLength(env, str) + 1, sizeof(jchar)); + if (strChars != NULL) { + (*env)->GetStringRegion(env, str, 0, (*env)->GetStringLength(env, str), strChars); + } } return strChars; } -JNIEnv* NativewindowCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int * shallBeDetached) { +JNIEnv* NativewindowCommon_GetJNIEnv (int asDaemon, int * shallBeDetached) { JNIEnv* curEnv = NULL; JNIEnv* newEnv = NULL; int envRes; + if(NULL==_jvmHandle) { + fprintf(stderr, "Nativewindow GetJNIEnv: NULL JVM handle, call NativewindowCommon_init 1st\n"); + return NULL; + } + // retrieve this thread's JNIEnv curEnv - or detect it's detached - envRes = (*jvmHandle)->GetEnv(jvmHandle, (void **) &curEnv, jvmVersion) ; + 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, "JNIEnv: can't attach thread: %d\n", envRes); + if( asDaemon ) { + envRes = (*_jvmHandle)->AttachCurrentThreadAsDaemon(_jvmHandle, (void**) &newEnv, NULL); + } else { + envRes = (*_jvmHandle)->AttachCurrentThread(_jvmHandle, (void**) &newEnv, NULL); + } + if( JNI_OK != envRes ) { + fprintf(stderr, "Nativewindow GetJNIEnv: Can't attach thread: %d\n", envRes); return NULL; } curEnv = newEnv; } else if( JNI_OK != envRes ) { // oops .. - fprintf(stderr, "can't GetEnv: %d\n", envRes); + fprintf(stderr, "Nativewindow GetJNIEnv: Can't GetEnv: %d\n", envRes); return NULL; } if (curEnv==NULL) { - fprintf(stderr, "env is NULL\n"); + fprintf(stderr, "Nativewindow GetJNIEnv: env is NULL\n"); return NULL; } *shallBeDetached = NULL != newEnv; return curEnv; } +void NativewindowCommon_ReleaseJNIEnv (int shallBeDetached) { + if(NULL == _jvmHandle) { + fprintf(stderr, "Nativewindow ReleaseJNIEnv: No JavaVM handle registered, call NativewindowCommon_init(..) 1st"); + } else if(shallBeDetached) { + (*_jvmHandle)->DetachCurrentThread(_jvmHandle); + } +} + +int64_t NativewindowCommon_CurrentTimeMillis() { + struct timeval tv; + gettimeofday(&tv,NULL); + return (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + diff --git a/src/nativewindow/native/NativewindowCommon.h b/src/nativewindow/native/NativewindowCommon.h index 73b890c4f..f19552e33 100644 --- a/src/nativewindow/native/NativewindowCommon.h +++ b/src/nativewindow/native/NativewindowCommon.h @@ -1,9 +1,37 @@ +/** + * Copyright 2011 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 NATIVEWINDOW_COMMON_H #define NATIVEWINDOW_COMMON_H 1 #include <jni.h> #include <stdlib.h> +#include <gluegen_stdint.h> int NativewindowCommon_init(JNIEnv *env); @@ -13,6 +41,40 @@ jchar* NativewindowCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) void NativewindowCommon_FatalError(JNIEnv *env, const char* msg, ...); void NativewindowCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...); -JNIEnv* NativewindowCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int * shallBeDetached); +/** + * + * 1) Init static jvmHandle, jvmVersion and clazz references + * from an early initialization call w/ valid 'JNIEnv * env' + + NativewindowCommon_init(env); + + * + * 2) Use current thread JNIEnv or attach current thread to JVM, generating new JNIEnv + * + + int asDaemon = 0; + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(asDaemon, &shallBeDetached); + if(NULL==env) { + DBG_PRINT("drawRect: null JNIEnv\n"); + return; + } + + * + * 3) Use JNIEnv .. + * + .. your JNIEnv code here .. + + * + * 4) Detach thread from JVM if required, i.e. not attached as daemon! + * Not recommended for recurring _daemon_ threads (performance) + * + NewtCommon_ReleaseJNIEnv(shallBeDetached); + */ +JNIEnv* NativewindowCommon_GetJNIEnv (int asDaemon, int * shallBeDetached); + +void NativewindowCommon_ReleaseJNIEnv (int shallBeDetached); + +int64_t NativewindowCommon_CurrentTimeMillis(); #endif diff --git a/src/nativewindow/native/macosx/NativeWindowProtocols.h b/src/nativewindow/native/macosx/NativeWindowProtocols.h new file mode 100644 index 000000000..98e864f8b --- /dev/null +++ b/src/nativewindow/native/macosx/NativeWindowProtocols.h @@ -0,0 +1,58 @@ +/** + * Copyright 2013 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 NATIVEWINDOWPROTOCOLS_H +#define NATIVEWINDOWPROTOCOLS_H 1 + +/** + * CALayer size needs to be set using the AWT component size. + * See detailed description in JAWTUtil.java and sync w/ changed. + */ +#define NW_DEDICATEDFRAME_QUIRK_SIZE ( 1 << 0 ) + +/** + * CALayer position needs to be set to zero. + * See detailed description in JAWTUtil.java and sync w/ changed. + */ +#define NW_DEDICATEDFRAME_QUIRK_POSITION ( 1 << 1 ) + +/** + * CALayer position needs to be derived from AWT position. + * in relation to super CALayer. + * See detailed description in JAWTUtil.java and sync w/ changed. + */ +#define NW_DEDICATEDFRAME_QUIRK_LAYOUT ( 1 << 2 ) + +#import <Foundation/NSGeometry.h> + +@protocol NWDedicatedFrame +- (void)setDedicatedFrame:(CGRect)dFrame quirks:(int)quirks; +@end + +#endif /* NATIVEWINDOWPROTOCOLS_H_ */ + diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m index 1cf41fc9d..127b329d1 100644 --- a/src/nativewindow/native/macosx/OSXmisc.m +++ b/src/nativewindow/native/macosx/OSXmisc.m @@ -32,13 +32,14 @@ #include <stdarg.h> #include <unistd.h> #include <AppKit/AppKit.h> +#import <QuartzCore/QuartzCore.h> +#import "NativeWindowProtocols.h" #include "NativewindowCommon.h" #include "jogamp_nativewindow_macosx_OSXUtil.h" #include "jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow.h" #include <jawt_md.h> -#import <JavaNativeFoundation.h> // #define VERBOSE 1 // @@ -49,6 +50,16 @@ #define DBG_PRINT(...) #endif +// #define VERBOSE2 1 +// +#ifdef VERBOSE2 + #define DBG_PRINT2(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT2(...) +#endif + +// #define DBG_LIFECYCLE 1 + static const char * const ClazzNameRunnable = "java/lang/Runnable"; static jmethodID runnableRunID = NULL; @@ -64,11 +75,9 @@ static const char * const ClazzNameInsetsCstrSignature = "(IIII)V"; static jclass insetsClz = NULL; static jmethodID insetsCstr = NULL; -static int _initialized=0; - JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) { - if(0==_initialized) { + if( NativewindowCommon_init(env) ) { jclass c; c = (*env)->FindClass(env, ClazzNamePoint); if(NULL==c) { @@ -108,7 +117,6 @@ Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) { if(NULL==runnableRunID) { NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch %s.run()V", ClazzNameRunnable); } - _initialized=1; } return JNI_TRUE; } @@ -116,13 +124,25 @@ Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) { JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_isNSView0(JNIEnv *env, jclass _unused, jlong object) { NSObject *nsObj = (NSObject*) (intptr_t) object; - return [nsObj isMemberOfClass:[NSView class]]; + jboolean u = [nsObj isKindOfClass:[NSView class]]; + DBG_PRINT( "isNSView(obj: %p): %s -> %d\n", nsObj, [[nsObj description] UTF8String], u); + return u; } JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_isNSWindow0(JNIEnv *env, jclass _unused, jlong object) { NSObject *nsObj = (NSObject*) (intptr_t) object; - return [nsObj isMemberOfClass:[NSWindow class]]; + jboolean u = [nsObj isKindOfClass:[NSWindow class]]; + DBG_PRINT( "isNSWindow(obj: %p): %s -> %d\n", nsObj, [[nsObj description] UTF8String], u); + return u; +} + +static CGDirectDisplayID OSXUtil_getCGDirectDisplayIDByNSScreen(NSScreen *screen) { + // Mind: typedef uint32_t CGDirectDisplayID; - however, we assume it's 64bit on 64bit ?! + NSDictionary * dict = [screen deviceDescription]; + NSNumber * val = (NSNumber *) [dict objectForKey: @"NSScreenNumber"]; + // [NSNumber integerValue] returns NSInteger which is 32 or 64 bit native size + return (CGDirectDisplayID) [val integerValue]; } /* @@ -139,10 +159,6 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetLocationOnS * return location in 0/0 top-left space, * OSX is 0/0 bottom-left space naturally */ - NSRect r; - int dest_x=-1; - int dest_y=-1; - NSObject *nsObj = (NSObject*) (intptr_t) winOrView; NSWindow* win = NULL; NSView* view = NULL; @@ -154,27 +170,36 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetLocationOnS view = (NSView*) nsObj; win = [view window]; } else { - NativewindowCommon_throwNewRuntimeException(env, "neither win not view %p\n", nsObj); + NativewindowCommon_throwNewRuntimeException(env, "neither win nor view %p\n", nsObj); } - NSScreen* screen = [win screen]; - NSRect screenRect = [screen frame]; - NSRect winFrame = [win frame]; + NSRect viewFrame = [view frame]; + NSRect r; r.origin.x = src_x; - r.origin.y = winFrame.size.height - src_y; // y-flip for 0/0 top-left + r.origin.y = viewFrame.size.height - src_y; // y-flip for 0/0 top-left r.size.width = 0; r.size.height = 0; // NSRect rS = [win convertRectToScreen: r]; // 10.7 - NSPoint oS = [win convertBaseToScreen: r.origin]; - /** - NSLog(@"LOS.1: (bottom-left) %d/%d, screen-y[0: %d, h: %d], (top-left) %d/%d\n", - (int)oS.x, (int)oS.y, (int)screenRect.origin.y, (int) screenRect.size.height, - (int)oS.x, (int)(screenRect.origin.y + screenRect.size.height - oS.y)); */ + NSPoint oS = [win convertBaseToScreen: r.origin]; // BL-screen - dest_x = (int) oS.x; - dest_y = (int) screenRect.origin.y + screenRect.size.height - oS.y; + NSScreen* screen = [win screen]; + CGDirectDisplayID display = OSXUtil_getCGDirectDisplayIDByNSScreen(screen); + CGRect frameTL = CGDisplayBounds (display); // origin top-left + NSRect frameBL = [screen frame]; // origin bottom-left + oS.y = frameTL.origin.y + frameTL.size.height - ( oS.y - frameBL.origin.y ); // y-flip from BL-screen -> TL-screen - jobject res = (*env)->NewObject(env, pointClz, pointCstr, (jint)dest_x, (jint)dest_y); +#ifdef VERBOSE + NSRect winFrame = [win frame]; + DBG_PRINT( "GetLocationOnScreen0(window: %p):: point-in[%d/%d], winFrame[%d/%d %dx%d], viewFrame[%d/%d %dx%d], screen tl[%d/%d %dx%d] bl[%d/%d %dx%d] -> %d/%d\n", + win, (int)src_x, (int)src_y, + (int)winFrame.origin.x, (int)winFrame.origin.y, (int)winFrame.size.width, (int)winFrame.size.height, + (int)viewFrame.origin.x, (int)viewFrame.origin.y, (int)viewFrame.size.width, (int)viewFrame.size.height, + (int)frameTL.origin.x, (int)frameTL.origin.y, (int)frameTL.size.width, (int)frameTL.size.height, + (int)frameBL.origin.x, (int)frameBL.origin.y, (int)frameBL.size.width, (int)frameBL.size.height, + (int)oS.x, (int)oS.y); +#endif + + jobject res = (*env)->NewObject(env, pointClz, pointCstr, (jint)oS.x, (jint)oS.y); [pool release]; @@ -203,7 +228,7 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetInsets0 view = (NSView*) nsObj; win = [view window]; } else { - NativewindowCommon_throwNewRuntimeException(env, "neither win not view %p\n", nsObj); + NativewindowCommon_throwNewRuntimeException(env, "neither win nor view %p\n", nsObj); } NSRect frameRect = [win frame]; @@ -226,6 +251,75 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetInsets0 /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: GetPixelScale0 + * Signature: (I)D + */ +JNIEXPORT jdouble JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetPixelScale0 + (JNIEnv *env, jclass unused, jint screen_idx) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + CGFloat pixelScale; + NSScreen *screen; + NSArray *screens = [NSScreen screens]; + if( screen_idx<0 || screen_idx>=[screens count] ) { + screen = NULL; + pixelScale = 0.0; + } else { + screen = (NSScreen *) [screens objectAtIndex: screen_idx]; + pixelScale = 1.0; // default +NS_DURING + // Available >= 10.7 + pixelScale = [screen backingScaleFactor]; // HiDPI scaling +NS_HANDLER +NS_ENDHANDLER + } + [pool release]; + + return (jdouble)pixelScale; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: GetPixelScale1 + * Signature: (J)D + */ +JNIEXPORT jdouble JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetPixelScale1 + (JNIEnv *env, jclass unused, jlong winOrView) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + NSObject *nsObj = (NSObject*) (intptr_t) winOrView; + NSWindow* win = NULL; + NSView* view = NULL; + NSScreen *screen = NULL; + + if( [nsObj isKindOfClass:[NSWindow class]] ) { + win = (NSWindow*) nsObj; + view = [win contentView]; + screen = [win screen]; + } else if( nsObj != NULL && [nsObj isKindOfClass:[NSView class]] ) { + view = (NSView*) nsObj; + win = [view window]; + screen = [win screen]; + } else { + NativewindowCommon_throwNewRuntimeException(env, "neither win nor view %p\n", nsObj); + } + + CGFloat pixelScale = 1.0; // default +NS_DURING + // Available >= 10.7 + pixelScale = [screen backingScaleFactor]; // HiDPI scaling +NS_HANDLER +NS_ENDHANDLER + + [pool release]; + + return (jdouble)pixelScale; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil * Method: CreateNSWindow0 * Signature: (IIIIZ)J */ @@ -239,7 +333,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateNSWindow0 NSWindow* myWindow = [[NSWindow alloc] initWithContentRect: rect styleMask: NSBorderlessWindowMask backing: NSBackingStoreBuffered - defer: YES]; + defer: NO]; // Bug 1087: Set default framebuffer, hence enforce NSView realization [myWindow setReleasedWhenClosed: YES]; // default [myWindow setPreservesContentDuringLiveResize: YES]; // Remove animations @@ -255,6 +349,13 @@ NS_ENDHANDLER [myWindow setOpaque: NO]; [myWindow setBackgroundColor: [NSColor clearColor]]; + // Bug 1087: Set default framebuffer, hence enforce NSView realization + // However, using the NSWindow ctor w/ 'defer: NO' seems sufficient + // and we are invisible - no focus! + // NSView* myView = [myWindow contentView]; + // [myView lockFocus]; + // [myView unlockFocus]; + [pool release]; return (jlong) ((intptr_t) myWindow); @@ -313,38 +414,260 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetNSWindow0 return res; } +/** + * Track lifecycle via DBG_PRINT messages, if VERBOSE is enabled! + */ +@interface MyCALayer: CALayer +{ +@private + BOOL fixedFrameSet; + CGRect fixedFrame; + float visibleOpacity; + BOOL visibleOpacityZeroed; +} +- (id)init; +#ifdef DBG_LIFECYCLE +- (id)retain; +- (oneway void)release; +- (void)dealloc; +#endif +- (id<CAAction>)actionForKey:(NSString *)key ; +- (void)layoutSublayers; +- (void)setFrame:(CGRect) frame; +- (void)fixCALayerLayout: (CALayer*) subLayer visible:(BOOL)visible x:(jint)x y:(jint)y width:(jint)width height:(jint)height caLayerQuirks:(jint)caLayerQuirks force:(jboolean) force; + +@end + +@implementation MyCALayer + +- (id)init +{ + DBG_PRINT("MyCALayer::init.0\n"); + MyCALayer * o = [super init]; + o->fixedFrameSet = 0; + o->fixedFrame = CGRectMake(0, 0, 0, 0); + o->visibleOpacity = 1.0; + o->visibleOpacityZeroed = 0; + DBG_PRINT("MyCALayer::init.X: new %p\n", o); + return o; +} + +#ifdef DBG_LIFECYCLE + +- (id)retain +{ + DBG_PRINT("MyCALayer::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyCALayer::retain: %@",[NSThread callStackSymbols]); + id o = [super retain]; + DBG_PRINT("MyCALayer::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]); + return o; +} + +- (oneway void)release +{ + DBG_PRINT("MyCALayer::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyCALayer::release: %@",[NSThread callStackSymbols]); + [super release]; + // DBG_PRINT("MyCALayer::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]); +} + +- (void)dealloc +{ + DBG_PRINT("MyCALayer::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyCALayer::dealloc: %@",[NSThread callStackSymbols]); + [super dealloc]; + // DBG_PRINT("MyCALayer.dealloc.X: %p\n", self); +} + +#endif + +- (id<CAAction>)actionForKey:(NSString *)key +{ + DBG_PRINT("MyCALayer::actionForKey.0 %p key %s -> NIL\n", self, [key UTF8String]); + return nil; + // return [super actionForKey: key]; +} + +- (void)layoutSublayers +{ + if( fixedFrameSet ) { + NSArray* subs = [self sublayers]; + if( NULL != subs ) { + CGRect rFrame = [self frame]; + if( !CGRectEqualToRect(fixedFrame, rFrame) ) { + #ifdef VERBOSE + DBG_PRINT("CALayer::layoutSublayers.0: Root %p frame %lf/%lf %lfx%lf -> %lf/%lf %lfx%lf\n", + self, + rFrame.origin.x, rFrame.origin.y, rFrame.size.width, rFrame.size.height, + fixedFrame.origin.x, fixedFrame.origin.y, fixedFrame.size.width, fixedFrame.size.height); + #endif + [super setFrame: fixedFrame]; + } + NSUInteger i = 0; + for(i=0; i<[subs count]; i++) { + CALayer* sub = [subs objectAtIndex: i]; + CGRect sFrame = [sub frame]; + CGRect sFrame2 = CGRectMake(0, 0, fixedFrame.size.width, fixedFrame.size.height); + if( !CGRectEqualToRect(sFrame2, sFrame) ) { + #ifdef VERBOSE + DBG_PRINT("CALayer::layoutSublayers.1: Sub[%d] %p frame %lf/%lf %lfx%lf -> %lf/%lf %lfx%lf\n", + (int)i, sub, + sFrame.origin.x, sFrame.origin.y, sFrame.size.width, sFrame.size.height, + sFrame2.origin.x, sFrame2.origin.y, sFrame2.size.width, sFrame2.size.height); + #endif + [sub setFrame: sFrame2]; + } + #ifdef VERBOSE + DBG_PRINT("CALayer::layoutSublayers.X: Root %p . Sub[%d] %p : frame r: %lf/%lf %lfx%lf . s: %lf/%lf %lfx%lf\n", + self, (int)i, sub, + rFrame.origin.x, rFrame.origin.y, rFrame.size.width, rFrame.size.height, + sFrame.origin.x, sFrame.origin.y, sFrame.size.width, sFrame.size.height); + #endif + } + } + } else { + [super layoutSublayers]; + } +} + +- (void) setFrame:(CGRect) frame +{ + if( fixedFrameSet ) { + [super setFrame: fixedFrame]; + } else { + [super setFrame: frame]; + } +} + +- (void)fixCALayerLayout: (CALayer*) subLayer visible:(BOOL)visible x:(jint)x y:(jint)y width:(jint)width height:(jint)height caLayerQuirks:(jint)caLayerQuirks force:(jboolean) force +{ + int loutQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_LAYOUT & caLayerQuirks ); + { + CALayer* superLayer = [self superlayer]; + CGRect superFrame = [superLayer frame]; + CGRect lFrame = [self frame]; + if( visible ) { + // Opacity must be 0 to see through the disabled CALayer + [subLayer setOpacity: visibleOpacity]; + [self setOpacity: visibleOpacity]; + [self setHidden: NO]; + [subLayer setHidden: NO]; + visibleOpacityZeroed = 0; + } else { + [subLayer setHidden: YES]; + [self setHidden: YES]; + if( !visibleOpacityZeroed ) { + visibleOpacity = [self opacity]; + } + [subLayer setOpacity: 0.0]; + [self setOpacity: 0.0]; + visibleOpacityZeroed = 1; + } + int posQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_POSITION & caLayerQuirks ) && ( lFrame.origin.x!=0 || lFrame.origin.y!=0 ); + int sizeQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_SIZE & caLayerQuirks ) && ( lFrame.size.width!=width || lFrame.size.height!=height ); + if( !posQuirk || loutQuirk ) { + // Use root layer position, sub-layer will be on 0/0, + // Given AWT position is location on screen w/o insets and top/left origin! + fixedFrame.origin.x = x; + fixedFrame.origin.y = superFrame.size.height - height - y; // AWT's position top/left -> bottom/left + posQuirk |= 8; + } else { + // Buggy super layer position, always use 0/0 + fixedFrame.origin.x = 0; + fixedFrame.origin.y = 0; + } + if( !sizeQuirk ) { + fixedFrame.size.width = lFrame.size.width; + fixedFrame.size.height = lFrame.size.height; + } else { + fixedFrame.size.width = width; + fixedFrame.size.height = height; + } + DBG_PRINT("CALayer::FixCALayerLayout0.0: Visible %d, Quirks [%d, pos %d, size %d, lout %d, force %d], Super %p frame %lf/%lf %lfx%lf, Root %p frame %lf/%lf %lfx%lf, usr %d/%d %dx%d -> %lf/%lf %lfx%lf\n", + (int)visible, caLayerQuirks, posQuirk, sizeQuirk, loutQuirk, (int)force, + superLayer, superFrame.origin.x, superFrame.origin.y, superFrame.size.width, superFrame.size.height, + self, lFrame.origin.x, lFrame.origin.y, lFrame.size.width, lFrame.size.height, + x, y, width, height, fixedFrame.origin.x, fixedFrame.origin.y, fixedFrame.size.width, fixedFrame.size.height); + if( posQuirk || sizeQuirk || loutQuirk ) { + fixedFrameSet = 1; + [super setFrame: fixedFrame]; + } + } + if( NULL != subLayer ) { + CGRect lFrame = [subLayer frame]; + int sizeQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_SIZE & caLayerQuirks ) && ( lFrame.size.width!=width || lFrame.size.height!=height ); + CGFloat _x, _y, _w, _h; + int posQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_POSITION & caLayerQuirks ) && ( lFrame.origin.x!=0 || lFrame.origin.y!=0 ); + // Sub rel. to used root layer + _x = 0; + _y = 0; + posQuirk |= 8; + if( !sizeQuirk ) { + _w = lFrame.size.width; + _h = lFrame.size.height; + } else { + _w = width; + _h = height; + } + DBG_PRINT("CALayer::FixCALayerLayout1.0: Visible %d, Quirks [%d, pos %d, size %d, lout %d, force %d], SubL %p frame %lf/%lf %lfx%lf, usr %dx%d -> %lf/%lf %lfx%lf\n", + (int)visible, caLayerQuirks, posQuirk, sizeQuirk, loutQuirk, (int)force, + subLayer, lFrame.origin.x, lFrame.origin.y, lFrame.size.width, lFrame.size.height, + width, height, _x, _y, _w, _h); + if( force || posQuirk || sizeQuirk || loutQuirk ) { + lFrame.origin.x = _x; + lFrame.origin.y = _y; + lFrame.size.width = _w; + lFrame.size.height = _h; + if( [subLayer conformsToProtocol:@protocol(NWDedicatedFrame)] ) { + CALayer <NWDedicatedFrame> * subLayerDS = (CALayer <NWDedicatedFrame> *) subLayer; + [subLayerDS setDedicatedFrame: lFrame quirks: caLayerQuirks]; + } else { + [subLayer setFrame: lFrame]; + } + } + } +} + +@end + /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil * Method: CreateCALayer0 - * Signature: (IIII)J + * Signature: (IIF)J */ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateCALayer0 - (JNIEnv *env, jclass unused, jint x, jint y, jint width, jint height) + (JNIEnv *env, jclass unused, jint width, jint height, jfloat contentsScale) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - CALayer* layer = [[CALayer alloc] init]; - DBG_PRINT("CALayer::CreateCALayer.0: %p %d/%d %dx%d (refcnt %d)\n", layer, (int)x, (int)y, (int)width, (int)height, (int)[layer retainCount]); + MyCALayer* layer = [[MyCALayer alloc] init]; + DBG_PRINT("CALayer::CreateCALayer.0: root %p 0/0 %dx%d @ scale %lf (refcnt %d)\n", layer, (int)width, (int)height, (double)contentsScale, (int)[layer retainCount]); // avoid zero size if(0 == width) { width = 32; } if(0 == height) { height = 32; } +NS_DURING + // Available >= 10.7 + [layer setContentsScale: (CGFloat)contentsScale]; +NS_HANDLER +NS_ENDHANDLER + // initial dummy size ! - CGRect lRect = [layer frame]; - lRect.origin.x = x; - lRect.origin.y = y; - lRect.size.width = width; - lRect.size.height = height; - [layer setFrame: lRect]; + CGRect lFrame = [layer frame]; + lFrame.origin.x = 0; + lFrame.origin.y = 0; + lFrame.size.width = width; + lFrame.size.height = height; + [layer setFrame: lFrame]; // no animations for add/remove/swap sublayers etc // doesn't work: [layer removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition] [layer removeAllAnimations]; + // [layer addAnimation:nil forKey:kCATransition]; [layer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; [layer setNeedsDisplayOnBoundsChange: YES]; - DBG_PRINT("CALayer::CreateCALayer.1: %p %lf/%lf %lfx%lf\n", layer, lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height); - DBG_PRINT("CALayer::CreateCALayer.X: %p (refcnt %d)\n", layer, (int)[layer retainCount]); - + DBG_PRINT("CALayer::CreateCALayer.1: root %p %lf/%lf %lfx%lf\n", layer, lFrame.origin.x, lFrame.origin.y, lFrame.size.width, lFrame.size.height); [pool release]; + DBG_PRINT("CALayer::CreateCALayer.X: root %p (refcnt %d)\n", layer, (int)[layer retainCount]); return (jlong) ((intptr_t) layer); } @@ -352,46 +675,114 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateCALayer0 /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil * Method: AddCASublayer0 - * Signature: (JJ)V + * Signature: (JJIIIIIF)V */ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0 - (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer) + (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer, jint x, jint y, jint width, jint height, jfloat contentsScale, jint caLayerQuirks) { - JNF_COCOA_ENTER(env); - CALayer* rootLayer = (CALayer*) ((intptr_t) rootCALayer); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer); CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + [rootLayer retain]; // Pairs w/ RemoveCASublayer + [subLayer retain]; // Pairs w/ RemoveCASublayer + CGRect lRectRoot = [rootLayer frame]; - DBG_PRINT("CALayer::AddCASublayer0.0: Origin %p frame0: %lf/%lf %lfx%lf\n", - rootLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height); - if(lRectRoot.origin.x!=0 || lRectRoot.origin.y!=0) { - lRectRoot.origin.x = 0; - lRectRoot.origin.y = 0; - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - [rootLayer setFrame: lRectRoot]; - }]; - DBG_PRINT("CALayer::AddCASublayer0.1: Origin %p frame*: %lf/%lf %lfx%lf\n", - rootLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height); + + // Available >= 10.7 + DBG_PRINT("CALayer::AddCASublayer0.0: Quirks %d, Root %p (refcnt %d), Sub %p (refcnt %d), frame0: %lf/%lf %lfx%lf scale %lf\n", + caLayerQuirks, rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount], + lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height, (float)contentsScale); + +NS_DURING + [subLayer setContentsScale: (CGFloat)contentsScale]; +NS_HANDLER +NS_ENDHANDLER + + [subLayer setFrame:lRectRoot]; + [rootLayer addSublayer:subLayer]; + + // no animations for add/remove/swap sublayers etc + // doesn't work: [layer removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition] + [rootLayer removeAllAnimations]; + // [rootLayer addAnimation:nil forKey:kCATransition]; // JAU + [rootLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; + [rootLayer setNeedsDisplayOnBoundsChange: YES]; + [subLayer removeAllAnimations]; + // [subLayer addAnimation:nil forKey:kCATransition]; // JAU + [subLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; + [subLayer setNeedsDisplayOnBoundsChange: YES]; + + if( 0 != caLayerQuirks ) { + [rootLayer fixCALayerLayout: subLayer visible:1 x:x y:y width:width height:height caLayerQuirks:caLayerQuirks force:JNI_TRUE]; + } + + [CATransaction commit]; + + [pool release]; + DBG_PRINT("CALayer::AddCASublayer0.X: root %p (refcnt %d) .sub %p (refcnt %d)\n", + rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount]); +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: FixCALayerLayout0 + * Signature: (JJIII)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_FixCALayerLayout0 + (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer, jboolean visible, jint x, jint y, jint width, jint height, jint caLayerQuirks) +{ + if( 0 != caLayerQuirks ) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer); + if( NULL == rootLayer ) { + NativewindowCommon_throwNewRuntimeException(env, "Argument \"rootLayer\" is null"); + } + CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + [rootLayer fixCALayerLayout: subLayer visible:(BOOL)visible x:x y:y width:width height:height caLayerQuirks:caLayerQuirks force:JNI_FALSE]; + + [CATransaction commit]; + + [pool release]; } - DBG_PRINT("CALayer::AddCASublayer0.2: %p . %p %lf/%lf %lfx%lf (refcnt %d)\n", - rootLayer, subLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height, (int)[subLayer retainCount]); - - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - // simple 1:1 layout ! - [subLayer setFrame:lRectRoot]; - [rootLayer addSublayer:subLayer]; - - // no animations for add/remove/swap sublayers etc - // doesn't work: [layer removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition] - [rootLayer removeAllAnimations]; - [rootLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; - [rootLayer setNeedsDisplayOnBoundsChange: YES]; - [subLayer removeAllAnimations]; - [subLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; - [subLayer setNeedsDisplayOnBoundsChange: YES]; - }]; - DBG_PRINT("CALayer::AddCASublayer0.X: %p . %p (refcnt %d)\n", rootLayer, subLayer, (int)[subLayer retainCount]); - JNF_COCOA_EXIT(env); +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: SetCALayerPixelScale0 + * Signature: (JJF)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_SetCALayerPixelScale0 + (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer, jfloat contentsScale) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer); + if( NULL == rootLayer ) { + NativewindowCommon_throwNewRuntimeException(env, "Argument \"rootLayer\" is null"); + } + CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + +NS_DURING + [rootLayer setContentsScale: (CGFloat)contentsScale]; + if( NULL != subLayer ) { + [subLayer setContentsScale: (CGFloat)contentsScale]; + } +NS_HANDLER +NS_ENDHANDLER + + [CATransaction commit]; + + [pool release]; } /* @@ -402,18 +793,27 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RemoveCASublayer0 (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer) { - JNF_COCOA_ENTER(env); - CALayer* rootLayer = (CALayer*) ((intptr_t) rootCALayer); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer); CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); (void)rootLayer; // no warnings - DBG_PRINT("CALayer::RemoveCASublayer0.0: %p . %p (refcnt %d)\n", rootLayer, subLayer, (int)[subLayer retainCount]); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - [subLayer removeFromSuperlayer]; - }]; - DBG_PRINT("CALayer::RemoveCASublayer0.X: %p . %p\n", rootLayer, subLayer); - JNF_COCOA_EXIT(env); + DBG_PRINT("CALayer::RemoveCASublayer0.0: root %p (refcnt %d) .sub %p (refcnt %d)\n", + rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount]); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + [subLayer removeFromSuperlayer]; + [subLayer release]; // Pairs w/ AddCASublayer + [rootLayer release]; // Pairs w/ AddCASublayer + + [CATransaction commit]; + + [pool release]; + DBG_PRINT("CALayer::RemoveCASublayer0.X: root %p (refcnt %d) .sub %p (refcnt %d)\n", + rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount]); } /* @@ -424,93 +824,113 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RemoveCASublayer0 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyCALayer0 (JNIEnv *env, jclass unused, jlong caLayer) { - JNF_COCOA_ENTER(env); - CALayer* layer = (CALayer*) ((intptr_t) caLayer); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* layer = (MyCALayer*) ((intptr_t) caLayer); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + DBG_PRINT("CALayer::DestroyCALayer0.0: root %p (refcnt %d)\n", layer, (int)[layer retainCount]); + [layer release]; // Trigger release and dealloc of root CALayer, it's child etc .. + + [CATransaction commit]; - DBG_PRINT("CALayer::DestroyCALayer0.0: %p (refcnt %d)\n", layer, (int)[layer retainCount]); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - [layer release]; // performs release! - }]; - DBG_PRINT("CALayer::DestroyCALayer0.X: %p\n", layer); - JNF_COCOA_EXIT(env); + [pool release]; + DBG_PRINT("CALayer::DestroyCALayer0.X: root %p\n", layer); } /* * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow - * Method: SetJAWTRootSurfaceLayer0 - * Signature: (JJ)Z + * Method: GetJAWTSurfaceLayersHandle0 + * Signature: (J)J */ -JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_SetJAWTRootSurfaceLayer0 - (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer, jlong caLayer) +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_GetJAWTSurfaceLayersHandle0 + (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer) { - JNF_COCOA_ENTER(env); JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer); if (NULL == dsi) { NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer"); - return JNI_FALSE; + return 0; } - CALayer* layer = (CALayer*) (intptr_t) caLayer; - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; - DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.0: %p -> %p (refcnt %d)\n", surfaceLayers.layer, layer, (int)[layer retainCount]); - surfaceLayers.layer = layer; // already incr. retain count - DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.X: %p (refcnt %d)\n", layer, (int)[layer retainCount]); - }]; - JNF_COCOA_EXIT(env); - return JNI_TRUE; + id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; + return (jlong) ((intptr_t) surfaceLayers); +} + +/* + * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow + * Method: SetJAWTRootSurfaceLayer0 + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_SetJAWTRootSurfaceLayer0 + (JNIEnv *env, jclass unused, jlong jawtSurfaceLayersHandle, jlong caLayer) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)(intptr_t)jawtSurfaceLayersHandle; + MyCALayer* layer = (MyCALayer*) (intptr_t) caLayer; + DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.0: pre %p -> root %p (refcnt %d)\n", [surfaceLayers layer], layer, (int)[layer retainCount]); + [surfaceLayers setLayer: [layer retain]]; // Pairs w/ Unset + + [CATransaction commit]; + + [pool release]; + DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.X: root %p (refcnt %d)\n", layer, (int)[layer retainCount]); } /* * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow * Method: UnsetJAWTRootSurfaceLayer0 - * Signature: (JJ)Z -JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_UnsetJAWTRootSurfaceLayer0 - (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer, jlong caLayer) + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_UnsetJAWTRootSurfaceLayer0 + (JNIEnv *env, jclass unused, jlong jawtSurfaceLayersHandle, jlong caLayer) { - JNF_COCOA_ENTER(env); - JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer); - if (NULL == dsi) { - NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer"); - return JNI_FALSE; - } - CALayer* layer = (CALayer*) (intptr_t) caLayer; - { - id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; - if(layer != surfaceLayers.layer) { - NativewindowCommon_throwNewRuntimeException(env, "Attached layer %p doesn't match given layer %p\n", surfaceLayers.layer, layer); - return JNI_FALSE; - } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)(intptr_t)jawtSurfaceLayersHandle; + MyCALayer* layer = (MyCALayer*) (intptr_t) caLayer; + if(layer != [surfaceLayers layer]) { + NativewindowCommon_throwNewRuntimeException(env, "Attached layer %p doesn't match given layer %p\n", surfaceLayers.layer, layer); + return; } - // [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; - DBG_PRINT("CALayer::detachJAWTSurfaceLayer: (%p) %p -> NULL\n", layer, surfaceLayers.layer); - surfaceLayers.layer = NULL; - [layer release]; - // }]; - JNF_COCOA_EXIT(env); - return JNI_TRUE; + DBG_PRINT("CALayer::UnsetJAWTRootSurfaceLayer.0: root %p (refcnt %d) -> nil\n", layer, (int)[layer retainCount]); + [layer release]; // Pairs w/ Set + [surfaceLayers setLayer: NULL]; + + [CATransaction commit]; + + [pool release]; + DBG_PRINT("CALayer::UnsetJAWTRootSurfaceLayer.X: root %p (refcnt %d) -> nil\n", layer, (int)[layer retainCount]); } - */ @interface MainRunnable : NSObject { - JavaVM *jvmHandle; - int jvmVersion; jobject runnableObj; } -- (id) initWithRunnable: (jobject)runnable jvmHandle: (JavaVM*)jvm jvmVersion: (int)jvmVers; +- (id) initWithRunnable: (jobject)runnable; - (void) jRun; +#ifdef DBG_LIFECYCLE +- (id)retain; +- (oneway void)release; +- (void)dealloc; +#endif + + @end @implementation MainRunnable -- (id) initWithRunnable: (jobject)runnable jvmHandle: (JavaVM*)jvm jvmVersion: (int)jvmVers +- (id) initWithRunnable: (jobject)runnable { - jvmHandle = jvm; - jvmVersion = jvmVers; runnableObj = runnable; return [super init]; } @@ -518,59 +938,144 @@ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow - (void) jRun { int shallBeDetached = 0; - JNIEnv* env = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + JNIEnv* env = NativewindowCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + DBG_PRINT2("MainRunnable.1 env: %d\n", (int)(NULL!=env)); if(NULL!=env) { + DBG_PRINT2("MainRunnable.1.0\n"); (*env)->CallVoidMethod(env, runnableObj, runnableRunID); + DBG_PRINT2("MainRunnable.1.1\n"); + (*env)->DeleteGlobalRef(env, runnableObj); - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } + DBG_PRINT2("MainRunnable.1.3\n"); + // detaching thread not required - daemon + // NativewindowCommon_ReleaseJNIEnv(shallBeDetached); } + DBG_PRINT2("MainRunnable.X\n"); } -@end +#ifdef DBG_LIFECYCLE +- (id)retain +{ + DBG_PRINT2("MainRunnable::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + id o = [super retain]; + DBG_PRINT2("MainRunnable::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]); + return o; +} -/* - * Class: Java_jogamp_nativewindow_macosx_OSXUtil - * Method: RunOnMainThread0 - * Signature: (ZLjava/lang/Runnable;)V - */ -JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunOnMainThread0 - (JNIEnv *env, jclass unused, jboolean jwait, jobject runnable) +- (oneway void)release { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + DBG_PRINT2("MainRunnable::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + [super release]; + // DBG_PRINT2("MainRunnable::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]); +} - if ( NO == [NSThread isMainThread] ) { - jobject runnableGlob = (*env)->NewGlobalRef(env, runnable); +- (void)dealloc +{ + DBG_PRINT2("MainRunnable::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]); + [super dealloc]; + // DBG_PRINT2("MainRunnable.dealloc.X: %p\n", self); +} + +#endif + +@end + +static void RunOnThread (JNIEnv *env, jobject runnable, BOOL onMain, jint delayInMS) +{ + BOOL isMainThread = [NSThread isMainThread]; + BOOL forkOnMain = onMain && ( NO == isMainThread || 0 < delayInMS ); - BOOL wait = (JNI_TRUE == jwait) ? YES : NO; - JavaVM *jvmHandle = NULL; - int jvmVersion = 0; + DBG_PRINT2( "RunOnThread0: forkOnMain %d [onMain %d, delay %dms, isMainThread %d], NSApp %d, NSApp-isRunning %d\n", + (int)forkOnMain, (int)onMain, (int)delayInMS, (int)isMainThread, (int)(NULL!=NSApp), (int)([NSApp isRunning])); - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; + if ( forkOnMain ) { + jobject runnableObj = (*env)->NewGlobalRef(env, runnable); + + DBG_PRINT2( "RunOnThread.1.0\n"); + MainRunnable * mr = [[MainRunnable alloc] initWithRunnable: runnableObj]; + + if( onMain ) { + [mr performSelectorOnMainThread:@selector(jRun) withObject:nil waitUntilDone:NO]; } else { - jvmVersion = (*env)->GetVersion(env); + NSTimeInterval delay = (double)delayInMS/1000.0; + [mr performSelector:@selector(jRun) withObject:nil afterDelay:delay]; } + DBG_PRINT2( "RunOnThread.1.1\n"); - MainRunnable * mr = [[MainRunnable alloc] initWithRunnable: runnableGlob jvmHandle: jvmHandle jvmVersion: jvmVersion]; - [mr performSelectorOnMainThread:@selector(jRun) withObject:nil waitUntilDone:wait]; [mr release]; + DBG_PRINT2( "RunOnThread.1.2\n"); - (*env)->DeleteGlobalRef(env, runnableGlob); } else { + DBG_PRINT2( "RunOnThread.2\n"); (*env)->CallVoidMethod(env, runnable, runnableRunID); } + DBG_PRINT2( "RunOnThread.X\n"); +} + +static void OSXUtil_KickNSApp() { + NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined + location: NSMakePoint(0,0) + modifierFlags: 0 + timestamp: 0.0 + windowNumber: 0 + context: nil + subtype: 0 + data1: 0 + data2: 0]; + [NSApp postEvent: event atStart: true]; +} +/** + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: RunOnMainThread0 + * Signature: (ZLjava/lang/Runnable;)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunOnMainThread0 + (JNIEnv *env, jclass unused, jboolean kickNSApp, jobject runnable) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + RunOnThread (env, runnable, YES, 0); + if( kickNSApp ) { + OSXUtil_KickNSApp(); + } [pool release]; } /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil - * Method: RunOnMainThread0 + * Method: RunLater0 + * Signature: (ZZLjava/lang/Runnable;I)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunLater0 + (JNIEnv *env, jclass unused, jboolean onMain, jboolean kickNSApp, jobject runnable, jint delay) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + RunOnThread (env, runnable, onMain ? YES : NO, delay); + if( kickNSApp ) { + OSXUtil_KickNSApp(); + } + [pool release]; +} + +/** + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: KickNSApp0 * Signature: (V)V */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_KickNSApp0 + (JNIEnv *env, jclass unused) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + OSXUtil_KickNSApp(); + [pool release]; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: IsMainThread0 + * Signature: (V)Z + */ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_IsMainThread0 (JNIEnv *env, jclass unused) { @@ -614,13 +1119,12 @@ JNIEXPORT jint JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetScreenRefreshR (JNIEnv *env, jclass unused, jint scrn_idx) { int res = 0; - JNF_COCOA_ENTER(env); - // NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSScreen *screen = NewtScreen_getNSScreenByIndex((int)scrn_idx); DBG_PRINT("GetScreenRefreshRate.0: screen %p\n", (void *)screen); if(NULL != screen) { CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen); - DBG_PRINT("GetScreenRefreshRate.1: display %p\n", (void *)display); + DBG_PRINT("GetScreenRefreshRate.1: display %p\n", (void *)(intptr_t)display); if(0 != display) { CFDictionaryRef mode = CGDisplayCurrentMode(display); DBG_PRINT("GetScreenRefreshRate.2: mode %p\n", (void *)mode); @@ -633,9 +1137,8 @@ JNIEXPORT jint JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetScreenRefreshR if(0 == res) { res = 60; // default .. (experienced on OSX 10.6.8) } - DBG_PRINT(stderr, "GetScreenRefreshRate.X: %d\n", res); - // [pool release]; - JNF_COCOA_EXIT(env); + DBG_PRINT("GetScreenRefreshRate.X: %d\n", (int)res); + [pool release]; return res; } diff --git a/src/nativewindow/native/win32/DeviceDriverQuery.txt b/src/nativewindow/native/win32/DeviceDriverQuery.txt new file mode 100644 index 000000000..7401ed83b --- /dev/null +++ b/src/nativewindow/native/win32/DeviceDriverQuery.txt @@ -0,0 +1,41 @@ + + // INCOMPLETE ! + // + // See Bug 706 and Bug 520 + // https://jogamp.org/bugzilla/show_bug.cgi?id=520 + // https://jogamp.org/bugzilla/show_bug.cgi?id=706 + // + // Device Driver SDK + // http://msdn.microsoft.com/en-us/library/ff553567.aspx#ddk_setupdi_device_information_functions_dg + { + /** + System-Defined Device Setup Classes Available to Vendors (GUID) + + Display Adapters + Class = Display + ClassGuid = {4d36e968-e325-11ce-bfc1-08002be10318} + This class includes video adapters. Drivers for this class include display drivers and video miniport drivers. + + /opt-windows/mingw/include/devguid.h GUID_DEVCLASS_DISPLAY + GUID_DEVCLASS_DISPLAY + HDEVINFO SetupDiGetClassDevs( + _In_opt_ const GUID *ClassGuid, + _In_opt_ PCTSTR Enumerator, + _In_opt_ HWND hwndParent, + _In_ DWORD Flags + ); + + */ + const GUID devClassDisplay = GUID_DEVCLASS_DISPLAY; + // http://msdn.microsoft.com/en-us/library/ff551069.aspx + HDEVINFO DeviceInfoSet = SetupDiGetClassDevs(&GUID_DEVCLASS_DISPLAY, NULL /* bus */, NULL /* windows */, DIGCF_PRESENT | DIGCF_PROFILE /* flags */); + DWORD MemberIndex = 0; + SP_DEVINFO_DATA DeviceInfoData; + DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + while( TRUE == SetupDiEnumDeviceInfo(DeviceInfoSet, MemberIndex, &DeviceInfoData) ) { + SetupDiGetSelectedDevice(); + MemberIndex++; + } + SetupDiDestroyDeviceInfoList(hDevInfo); + } + diff --git a/src/nativewindow/native/win32/GDImisc.c b/src/nativewindow/native/win32/GDImisc.c index 3ab7f9859..76143c426 100644 --- a/src/nativewindow/native/win32/GDImisc.c +++ b/src/nativewindow/native/win32/GDImisc.c @@ -20,8 +20,10 @@ #ifdef VERBOSE_ON #define DBG_PRINT(args...) fprintf(stderr, args); + #define DBG_PRINT_FLUSH(args...) fprintf(stderr, args); fflush(stderr); #else #define DBG_PRINT(args...) + #define DBG_PRINT_FLUSH(args...) #endif static const char * const ClazzNamePoint = "javax/media/nativewindow/util/Point"; @@ -30,6 +32,162 @@ static const char * const ClazzNamePointCstrSignature = "(II)V"; static jclass pointClz = NULL; static jmethodID pointCstr = NULL; +static jmethodID dumpStackID = NULL; + +typedef struct { + HANDLE threadHandle; + DWORD threadId; + volatile BOOL threadReady; + volatile BOOL threadDead; +} DummyThreadContext; + +typedef struct { + HINSTANCE hInstance; + const TCHAR* wndClassName; + const TCHAR* wndName; + jint x; + jint y; + jint width; + jint height; + volatile HWND hWnd; + volatile BOOL threadReady; +} DummyThreadCommand; + +#define TM_OPENWIN WM_APP+1 +#define TM_CLOSEWIN WM_APP+2 +#define TM_STOP WM_APP+3 + +static const char * sTM_OPENWIN = "TM_OPENWIN"; +static const char * sTM_CLOSEWIN = "TM_CLOSEWIN"; +static const char * sTM_STOP = "TM_STOP"; + +/** 3s timeout */ +static const int64_t TIME_OUT = 3000000; + +static jboolean DDT_CheckAlive(JNIEnv *env, const char *msg, DummyThreadContext *ctx) { + if( ctx->threadDead ) { + NativewindowCommon_throwNewRuntimeException(env, "DDT is dead at %s", msg); + return JNI_FALSE; + } else { + DBG_PRINT_FLUSH("*** DDT-Check ALIVE @ %s\n", msg); + return JNI_TRUE; + } +} + +static jboolean DDT_WaitUntilCreated(JNIEnv *env, DummyThreadContext *ctx, BOOL created) { + const int64_t t0 = NativewindowCommon_CurrentTimeMillis(); + int64_t t1 = t0; + if( created ) { + while( !ctx->threadReady && t1-t0 < TIME_OUT ) { + t1 = NativewindowCommon_CurrentTimeMillis(); + } + if( !ctx->threadReady ) { + NativewindowCommon_throwNewRuntimeException(env, "TIMEOUT (%d ms) while waiting for DDT CREATED", (int)(t1-t0)); + return JNI_FALSE; + } + DBG_PRINT_FLUSH("*** DDT-Check CREATED\n"); + } else { + while( !ctx->threadDead && t1-t0 < TIME_OUT ) { + t1 = NativewindowCommon_CurrentTimeMillis(); + } + if( !ctx->threadDead ) { + NativewindowCommon_throwNewRuntimeException(env, "TIMEOUT (%d ms) while waiting for DDT DESTROYED", (int)(t1-t0)); + return JNI_FALSE; + } + DBG_PRINT_FLUSH("*** DDT-Check DEAD\n"); + } + return JNI_TRUE; +} + +static jboolean DDT_WaitUntilReady(JNIEnv *env, const char *msg, DummyThreadCommand *cmd) { + const int64_t t0 = NativewindowCommon_CurrentTimeMillis(); + int64_t t1 = t0; + while( !cmd->threadReady && t1-t0 < TIME_OUT ) { + t1 = NativewindowCommon_CurrentTimeMillis(); + } + if( !cmd->threadReady ) { + NativewindowCommon_throwNewRuntimeException(env, "TIMEOUT (%d ms) while waiting for DDT %s", (int)(t1-t0), msg); + return JNI_FALSE; + } + DBG_PRINT_FLUSH("*** DDT-Check READY @ %s\n", msg); + return JNI_TRUE; +} + +static HWND DummyWindowCreate + (HINSTANCE hInstance, const TCHAR* wndClassName, const TCHAR* wndName, jint x, jint y, jint width, jint height) +{ + DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + DWORD dwStyle = WS_OVERLAPPEDWINDOW; + HWND hWnd = CreateWindowEx( dwExStyle, + wndClassName, + wndName, + dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + x, y, width, height, + NULL, NULL, hInstance, NULL ); + return hWnd; +} + +static DWORD WINAPI DummyDispatchThreadFunc(LPVOID param) +{ + MSG msg; + BOOL bRet; + BOOL bEOL=FALSE; + DummyThreadContext *threadContext = (DummyThreadContext*)param; + + /* there can not be any messages for us now, as the creator waits for + threadReady before continuing, but we must use this PeekMessage() to + create the thread message queue */ + PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); + + /* now we can safely say: we have a qeue and are ready to receive messages */ + // threadContext->threadId = GetCurrentThreadId(); + threadContext->threadDead = FALSE; + threadContext->threadReady = TRUE; + + while( !bEOL && (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0 ) { + if ( -1 == bRet ) { + fprintf(stderr, "DummyDispatchThread (id %d): GetMessage Error %d, werr %d\n", + (int)threadContext->threadId, (int)bRet, (int)GetLastError()); + fflush(stderr); + bEOL = TRUE; + break; // EOL + } else { + switch(msg.message) { + case TM_OPENWIN: { + DummyThreadCommand *tParam = (DummyThreadCommand*)msg.wParam; + DBG_PRINT_FLUSH("*** DDT-Dispatch OPENWIN\n"); + tParam->hWnd = DummyWindowCreate(tParam->hInstance, tParam->wndClassName, tParam->wndName, tParam->x, tParam->y, tParam->width, tParam->height); + tParam->threadReady = TRUE; + } + break; + case TM_CLOSEWIN: { + DummyThreadCommand *tParam = (DummyThreadCommand*)msg.wParam; + DBG_PRINT_FLUSH("*** DDT-Dispatch CLOSEWIN\n"); + DestroyWindow(tParam->hWnd); + tParam->threadReady = TRUE; + } + break; + case TM_STOP: { + DummyThreadCommand *tParam = (DummyThreadCommand*)msg.wParam; + DBG_PRINT_FLUSH("*** DDT-Dispatch STOP -> DEAD\n"); + tParam->threadReady = TRUE; + bEOL = TRUE; + } + break; // EOL + default: + TranslateMessage(&msg); + DispatchMessage(&msg); + break; + } + } + } + /* dead */ + DBG_PRINT_FLUSH("*** DDT-Dispatch DEAD\n"); + threadContext->threadDead = TRUE; + ExitThread(0); + return 0; +} + HINSTANCE GetApplicationHandle() { return GetModuleHandle(NULL); @@ -37,16 +195,54 @@ HINSTANCE GetApplicationHandle() { /* Java->C glue code: * Java package: jogamp.nativewindow.windows.GDIUtil - * Java method: boolean CreateWindowClass(long hInstance, java.lang.String clazzName, long wndProc) - * C function: BOOL CreateWindowClass(HANDLE hInstance, LPCSTR clazzName, HANDLE wndProc); + * Java method: long CreateDummyDispatchThread0() + */ +JNIEXPORT jlong JNICALL +Java_jogamp_nativewindow_windows_GDIUtil_CreateDummyDispatchThread0 + (JNIEnv *env, jclass _unused) +{ + DWORD threadId = 0; + DummyThreadContext * dispThreadCtx = calloc(1, sizeof(DummyThreadContext)); + + dispThreadCtx->threadHandle = CreateThread(NULL, 0, DummyDispatchThreadFunc, (LPVOID)dispThreadCtx, 0, &threadId); + if( NULL == dispThreadCtx->threadHandle || 0 == threadId ) { + const HANDLE threadHandle = dispThreadCtx->threadHandle; + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + NativewindowCommon_throwNewRuntimeException(env, "DDT CREATE failed handle %p, id %d, werr %d", + (void*)threadHandle, (int)threadId, (int)GetLastError()); + return (jlong)0; + } + if( JNI_FALSE == DDT_WaitUntilCreated(env, dispThreadCtx, TRUE) ) { + const HANDLE threadHandle = dispThreadCtx->threadHandle; + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + NativewindowCommon_throwNewRuntimeException(env, "DDT CREATE (ack) failed handle %p, id %d, werr %d", + (void*)threadHandle, (int)threadId, (int)GetLastError()); + return (jlong)0; + } + DBG_PRINT_FLUSH("*** DDT Created %d\n", (int)threadId); + dispThreadCtx->threadId = threadId; + return (jlong) (intptr_t) dispThreadCtx; +} + +/* Java->C glue code: + * Java package: jogamp.nativewindow.windows.GDIUtil + * Java method: boolean CreateWindowClass0(long hInstance, java.lang.String clazzName, long wndProc) + * C function: BOOL CreateWindowClass0(HANDLE hInstance, LPCSTR clazzName, HANDLE wndProc); */ JNIEXPORT jboolean JNICALL -Java_jogamp_nativewindow_windows_GDIUtil_CreateWindowClass - (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jClazzName, jlong wndProc) +Java_jogamp_nativewindow_windows_GDIUtil_CreateWindowClass0 + (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jClazzName, jlong wndProc, + jlong iconSmallHandle, jlong iconBigHandle) { HINSTANCE hInstance = (HINSTANCE) (intptr_t) jHInstance; const TCHAR* clazzName = NULL; - WNDCLASS wc; + WNDCLASSEX wc; jboolean res; #ifdef UNICODE @@ -56,23 +252,25 @@ Java_jogamp_nativewindow_windows_GDIUtil_CreateWindowClass #endif ZeroMemory( &wc, sizeof( wc ) ); - if( GetClassInfo( hInstance, clazzName, &wc ) ) { + if( GetClassInfoEx( hInstance, clazzName, &wc ) ) { // registered already res = JNI_TRUE; } else { // register now ZeroMemory( &wc, sizeof( wc ) ); + wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW ; wc.lpfnWndProc = (WNDPROC) (intptr_t) wndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; - wc.hIcon = NULL; - wc.hCursor = LoadCursor( NULL, IDC_ARROW); + wc.hIcon = (HICON) (intptr_t) iconBigHandle; + wc.hCursor = NULL; wc.hbrBackground = NULL; // no background paint - GetStockObject(BLACK_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = clazzName; - res = ( 0 != RegisterClass( &wc ) ) ? JNI_TRUE : JNI_FALSE ; + wc.hIconSm = (HICON) (intptr_t) iconSmallHandle; + res = ( 0 != RegisterClassEx( &wc ) ) ? JNI_TRUE : JNI_FALSE ; } #ifdef UNICODE @@ -86,15 +284,15 @@ Java_jogamp_nativewindow_windows_GDIUtil_CreateWindowClass /* Java->C glue code: * Java package: jogamp.nativewindow.windows.GDIUtil - * Java method: boolean DestroyWindowClass(long hInstance, java.lang.String className) - * C function: BOOL DestroyWindowClass(HANDLE hInstance, LPCSTR className); + * Java method: boolean DestroyWindowClass0(long hInstance, java.lang.String className, long dispThreadCtx) */ JNIEXPORT jboolean JNICALL -Java_jogamp_nativewindow_windows_GDIUtil_DestroyWindowClass - (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jClazzName) +Java_jogamp_nativewindow_windows_GDIUtil_DestroyWindowClass0 + (JNIEnv *env, jclass gdiClazz, jlong jHInstance, jstring jClazzName, jlong jDispThreadCtx) { HINSTANCE hInstance = (HINSTANCE) (intptr_t) jHInstance; const TCHAR* clazzName = NULL; + DummyThreadContext * dispThreadCtx = (DummyThreadContext *) (intptr_t) jDispThreadCtx; jboolean res; #ifdef UNICODE @@ -111,55 +309,175 @@ Java_jogamp_nativewindow_windows_GDIUtil_DestroyWindowClass (*env)->ReleaseStringUTFChars(env, jClazzName, clazzName); #endif + if( NULL != dispThreadCtx) { + const HANDLE threadHandle = dispThreadCtx->threadHandle; + const DWORD threadId = dispThreadCtx->threadId; + DummyThreadCommand tParam = {0}; + tParam.threadReady = FALSE; + DBG_PRINT_FLUSH("*** DDT Destroy %d\n", (int)threadId); +#ifdef VERBOSE_ON + (*env)->CallStaticVoidMethod(env, gdiClazz, dumpStackID); +#endif + + if( JNI_FALSE == DDT_CheckAlive(env, sTM_STOP, dispThreadCtx) ) { + free(dispThreadCtx); + NativewindowCommon_throwNewRuntimeException(env, "DDT %s (alive) failed handle %p, id %d, werr %d", + sTM_STOP, (void*)threadHandle, (int)threadId, (int)GetLastError()); + return JNI_FALSE; + } + if ( 0 != PostThreadMessage(dispThreadCtx->threadId, TM_STOP, (WPARAM)&tParam, 0) ) { + if( JNI_FALSE == DDT_WaitUntilReady(env, sTM_STOP, &tParam) ) { + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + NativewindowCommon_throwNewRuntimeException(env, "DDT Post %s (ack) failed handle %p, id %d, werr %d", + sTM_STOP, (void*)threadHandle, (int)threadId, (int)GetLastError()); + return JNI_FALSE; + } + if( JNI_FALSE == DDT_WaitUntilCreated(env, dispThreadCtx, FALSE) ) { + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + NativewindowCommon_throwNewRuntimeException(env, "DDT KILL %s (ack) failed handle %p, id %d, werr %d", + sTM_STOP, (void*)threadHandle, (int)threadId, (int)GetLastError()); + return JNI_FALSE; + } + free(dispThreadCtx); // free after proper DDT shutdown! + } else { + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + NativewindowCommon_throwNewRuntimeException(env, "DDT Post %s failed handle %p, id %d, werr %d", + sTM_STOP, (void*)threadHandle, (int)threadId, (int)GetLastError()); + return JNI_FALSE; + } + } + return res; } - /* Java->C glue code: * Java package: jogamp.nativewindow.windows.GDIUtil - * Java method: long CreateDummyWindow0(long hInstance, java.lang.String className, java.lang.String windowName, int x, int y, int width, int height) - * C function: HANDLE CreateDummyWindow0(HANDLE hInstance, LPCSTR className, LPCSTR windowName, int x, int y, int width, int height); + * Java method: long CreateDummyWindow0(long hInstance, java.lang.String className, jlong dispThreadCtx, java.lang.String windowName, int x, int y, int width, int height) */ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_windows_GDIUtil_CreateDummyWindow0 - (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jWndClassName, jstring jWndName, jint x, jint y, jint width, jint height) + (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jWndClassName, jlong jDispThreadCtx, jstring jWndName, jint x, jint y, jint width, jint height) { - HINSTANCE hInstance = (HINSTANCE) (intptr_t) jHInstance; - const TCHAR* wndClassName = NULL; - const TCHAR* wndName = NULL; - DWORD dwExStyle; - DWORD dwStyle; - HWND hWnd; + DummyThreadContext * dispThreadCtx = (DummyThreadContext *) (intptr_t) jDispThreadCtx; + DummyThreadCommand tParam = {0}; + + tParam.hInstance = (HINSTANCE) (intptr_t) jHInstance; + tParam.x = x; + tParam.y = y; + tParam.width = width; + tParam.height = height; + tParam.hWnd = 0; + tParam.threadReady = FALSE; #ifdef UNICODE - wndClassName = NewtCommon_GetNullTerminatedStringChars(env, jWndClassName); - wndName = NewtCommon_GetNullTerminatedStringChars(env, jWndName); + tParam.wndClassName = NewtCommon_GetNullTerminatedStringChars(env, jWndClassName); + tParam.wndName = NewtCommon_GetNullTerminatedStringChars(env, jWndName); #else - wndClassName = (*env)->GetStringUTFChars(env, jWndClassName, NULL); - wndName = (*env)->GetStringUTFChars(env, jWndName, NULL); + tParam.wndClassName = (*env)->GetStringUTFChars(env, jWndClassName, NULL); + tParam.wndName = (*env)->GetStringUTFChars(env, jWndName, NULL); #endif - dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - dwStyle = WS_OVERLAPPEDWINDOW; - - hWnd = CreateWindowEx( dwExStyle, - wndClassName, - wndName, - dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, - x, y, width, height, - NULL, NULL, hInstance, NULL ); + if( NULL == dispThreadCtx ) { + tParam.hWnd = DummyWindowCreate(tParam.hInstance, tParam.wndClassName, tParam.wndName, tParam.x, tParam.y, tParam.width, tParam.height); + } else { + const HANDLE threadHandle = dispThreadCtx->threadHandle; + const DWORD threadId = dispThreadCtx->threadId; + if( JNI_FALSE == DDT_CheckAlive(env, sTM_OPENWIN, dispThreadCtx) ) { + free(dispThreadCtx); + NativewindowCommon_throwNewRuntimeException(env, "DDT %s (alive) failed handle %p, id %d, werr %d", + sTM_OPENWIN, (void*)threadHandle, (int)threadId, (int)GetLastError()); + } else { + if( 0 != PostThreadMessage(dispThreadCtx->threadId, TM_OPENWIN, (WPARAM)&tParam, 0) ) { + if( JNI_FALSE == DDT_WaitUntilReady(env, sTM_OPENWIN, &tParam) ) { + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + tParam.hWnd = 0; + NativewindowCommon_throwNewRuntimeException(env, "DDT Post %s (ack) failed handle %p, id %d, werr %d", + sTM_OPENWIN, (void*)threadHandle, (int)threadId, (int)GetLastError()); + } + } else { + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + tParam.hWnd = 0; + NativewindowCommon_throwNewRuntimeException(env, "DDT Post %s to handle %p, id %d failed, werr %d", + sTM_OPENWIN, (void*)threadHandle, (int)threadId, (int)GetLastError()); + } + } + } #ifdef UNICODE - free((void*) wndClassName); - free((void*) wndName); + free((void*) tParam.wndClassName); + free((void*) tParam.wndName); #else - (*env)->ReleaseStringUTFChars(env, jWndClassName, wndClassName); - (*env)->ReleaseStringUTFChars(env, jWndName, wndName); + (*env)->ReleaseStringUTFChars(env, jWndClassName, tParam.wndClassName); + (*env)->ReleaseStringUTFChars(env, jWndName, tParam.wndName); #endif - return (jlong) (intptr_t) hWnd; + return (jlong) (intptr_t) tParam.hWnd; } +/* + * Class: jogamp_nativewindow_windows_GDIUtil + * Method: DestroyWindow0 + */ +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDIUtil_DestroyWindow0 +(JNIEnv *env, jclass unused, jlong jDispThreadCtx, jlong jwin) +{ + jboolean res = JNI_TRUE; + DummyThreadContext * dispThreadCtx = (DummyThreadContext *) (intptr_t) jDispThreadCtx; + HWND hWnd = (HWND) (intptr_t) jwin; + if( NULL == dispThreadCtx ) { + DestroyWindow(hWnd); + } else { + const HANDLE threadHandle = dispThreadCtx->threadHandle; + const DWORD threadId = dispThreadCtx->threadId; + DummyThreadCommand tParam = {0}; + + tParam.hWnd = hWnd; + tParam.threadReady = FALSE; + + if( JNI_FALSE == DDT_CheckAlive(env, sTM_CLOSEWIN, dispThreadCtx) ) { + free(dispThreadCtx); + res = JNI_FALSE; + NativewindowCommon_throwNewRuntimeException(env, "DDT %s (alive) failed handle %p, id %d, werr %d", + sTM_CLOSEWIN, (void*)threadHandle, (int)threadId, (int)GetLastError()); + } else { + if ( 0 != PostThreadMessage(dispThreadCtx->threadId, TM_CLOSEWIN, (WPARAM)&tParam, 0) ) { + if( JNI_FALSE == DDT_WaitUntilReady(env, sTM_CLOSEWIN, &tParam) ) { + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + res = JNI_FALSE; + NativewindowCommon_throwNewRuntimeException(env, "DDT Post %s (ack) failed handle %p, id %d, werr %d", + sTM_CLOSEWIN, (void*)threadHandle, (int)threadId, (int)GetLastError()); + } + } else { + if( NULL != threadHandle ) { + TerminateThread(threadHandle, 0); + } + free(dispThreadCtx); + res = JNI_FALSE; + NativewindowCommon_throwNewRuntimeException(env, "DDT Post %s to handle %p, id %d failed, werr %d", + sTM_CLOSEWIN, (void*)threadHandle, (int)threadId, (int)GetLastError()); + } + } + } + return res; +} /* * Class: jogamp_nativewindow_windows_GDIUtil @@ -167,9 +485,9 @@ Java_jogamp_nativewindow_windows_GDIUtil_CreateDummyWindow0 * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDIUtil_initIDs0 - (JNIEnv *env, jclass clazz) + (JNIEnv *env, jclass gdiClazz) { - if(NativewindowCommon_init(env)) { + if( NativewindowCommon_init(env) ) { jclass c = (*env)->FindClass(env, ClazzNamePoint); if(NULL==c) { NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDIUtil: can't find %s", ClazzNamePoint); @@ -184,12 +502,16 @@ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDIUtil_initIDs0 NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDIUtil: can't fetch %s.%s %s", ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); } + dumpStackID = (*env)->GetStaticMethodID(env, gdiClazz, "dumpStack", "()V"); + if(NULL==dumpStackID) { + NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDIUtil: can't get method dumpStack"); + } } return JNI_TRUE; } -LRESULT CALLBACK DummyWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - return DefWindowProc(hWnd,uMsg,wParam,lParam); +static LRESULT CALLBACK DummyWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + return DefWindowProc(hWnd,uMsg,wParam,lParam); } /* @@ -224,3 +546,133 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_windows_GDIUtil_GetRelativeLo return (*env)->NewObject(env, pointClz, pointCstr, (jint)dest.x, (jint)dest.y); } +/* + * Class: jogamp_nativewindow_windows_GDIUtil + * Method: IsChild0 + */ +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDIUtil_IsChild0 + (JNIEnv *env, jclass unused, jlong jwin) +{ + HWND hWnd = (HWND) (intptr_t) jwin; + LONG style = GetWindowLong(hWnd, GWL_STYLE); + BOOL bIsChild = 0 != (style & WS_CHILD) ; + return bIsChild ? JNI_TRUE : JNI_FALSE; +} + +/* + * Class: jogamp_nativewindow_windows_GDIUtil + * Method: IsUndecorated0 + */ +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDIUtil_IsUndecorated0 + (JNIEnv *env, jclass unused, jlong jwin) +{ + HWND hWnd = (HWND) (intptr_t) jwin; + LONG style = GetWindowLong(hWnd, GWL_STYLE); + BOOL bIsUndecorated = 0 != (style & (WS_CHILD|WS_POPUP)) ; + return bIsUndecorated ? JNI_TRUE : JNI_FALSE; +} + +#if 0 + +#include <tlhelp32.h> +#include <tchar.h> + +static void printError( TCHAR* msg ) +{ + DWORD eNum; + TCHAR sysMsg[256]; + TCHAR* p; + + eNum = GetLastError( ); + FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, eNum, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + sysMsg, 256, NULL ); + + // Trim the end of the line and terminate it with a null + p = sysMsg; + while( ( *p > 31 ) || ( *p == 9 ) ) + ++p; + do { *p-- = 0; } while( ( p >= sysMsg ) && + ( ( *p == '.' ) || ( *p < 33 ) ) ); + + // Display the message + _ftprintf(stderr, TEXT("\n WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg ); +} + +static BOOL SetProcessThreadsAffinityMask( DWORD dwOwnerPID, DWORD_PTR newTAffinity, BOOL verbose ) +{ + HANDLE hThreadSnap = INVALID_HANDLE_VALUE; + THREADENTRY32 te32; + DWORD_PTR preTAffinity; + HANDLE threadHandle; + + // Take a snapshot of all running threads + hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); + if( hThreadSnap == INVALID_HANDLE_VALUE ) + return( FALSE ); + + // Fill in the size of the structure before using it. + te32.dwSize = sizeof(THREADENTRY32 ); + + // Retrieve information about the first thread, + // and exit if unsuccessful + if( !Thread32First( hThreadSnap, &te32 ) ) + { + if( verbose ) { + printError( TEXT("Thread32First") ); // Show cause of failure + } + CloseHandle( hThreadSnap ); // Must clean up the snapshot object! + return( FALSE ); + } + + // Now walk the thread list of the system, + // and display information about each thread + // associated with the specified process + do + { + if( te32.th32OwnerProcessID == dwOwnerPID ) + { + if( verbose ) { + _ftprintf(stderr, TEXT("\n THREAD ID = 0x%08X, %d"), te32.th32ThreadID, te32.th32ThreadID); + _ftprintf(stderr, TEXT("\n base priority = %d"), te32.tpBasePri ); + _ftprintf(stderr, TEXT("\n delta priority = %d"), te32.tpDeltaPri ); + } + threadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID); + if( NULL != threadHandle ) { + preTAffinity = SetThreadAffinityMask(threadHandle, newTAffinity); + CloseHandle(threadHandle); + if( verbose ) { + _ftprintf(stderr, TEXT("\n affinity %p -> %p"), preTAffinity, newTAffinity); + } + } else { + if( verbose ) { + _ftprintf(stderr, TEXT("\n OpenThread failed %d"), (int)GetLastError()); + } + } + } + } while( Thread32Next(hThreadSnap, &te32 ) ); + + if( verbose ) { + _ftprintf(stderr, TEXT("\n")); + } + +// Don't forget to clean up the snapshot object. + CloseHandle( hThreadSnap ); + return( TRUE ); +} + +JNIEXPORT void JNICALL Java_jogamp_nativewindow_windows_GDIUtil_SetProcessThreadsAffinityMask0 + (JNIEnv *env, jclass unused, jlong affinityMask, jboolean verbose) +{ + SetProcessThreadsAffinityMask( GetCurrentProcessId(), (DWORD_PTR)(intptr_t)affinityMask, (BOOL)verbose ); +} + +#else + +JNIEXPORT void JNICALL Java_jogamp_nativewindow_windows_GDIUtil_SetProcessThreadsAffinityMask0 + (JNIEnv *env, jclass unused, jlong affinityMask, jboolean verbose) +{ +} + +#endif diff --git a/src/nativewindow/native/win32/WindowsDWM.h b/src/nativewindow/native/win32/WindowsDWM.h index 36f82fc94..6e5160fa4 100644 --- a/src/nativewindow/native/win32/WindowsDWM.h +++ b/src/nativewindow/native/win32/WindowsDWM.h @@ -4,6 +4,8 @@ #include <windows.h> #define DWM_BB_ENABLE 0x00000001 // fEnable has been specified + #define DWM_BB_BLURREGION 0x00000002 + #define DWM_BB_TRANSITIONONMAXIMIZED 0x00000004 #define DWM_EC_DISABLECOMPOSITION 0 #define DWM_EC_ENABLECOMPOSITION 1 diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index fcba8580c..247dc1311 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -29,6 +29,14 @@ #include "NativewindowCommon.h" #include "Xmisc.h" #include "jogamp_nativewindow_x11_X11Lib.h" +#include "jogamp_nativewindow_x11_X11Util.h" + +#include <X11/Xatom.h> + +#include <X11/extensions/Xrender.h> + +/** Remove memcpy GLIBC > 2.4 dependencies */ +#include <glibc-compat-symbols.h> // #define VERBOSE_ON 1 @@ -84,6 +92,8 @@ Bool XF86VidModeSetGammaRamp( #define RTLD_DEFAULT NULL #endif +#define X11_MOUSE_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask) + 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;"; @@ -103,128 +113,116 @@ static jmethodID pointCstr = NULL; static void _initClazzAccess(JNIEnv *env) { jclass c; - 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); - } - clazzBuffers = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==clazzBuffers) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNameBuffers); - } - c = (*env)->FindClass(env, ClazzNameByteBuffer); - if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNameByteBuffer); - } - clazzByteBuffer = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNameByteBuffer); - } - - cstrBuffers = (*env)->GetStaticMethodID(env, clazzBuffers, - ClazzNameBuffersStaticCstrName, ClazzNameBuffersStaticCstrSignature); - if(NULL==cstrBuffers) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't create %s.%s %s", - ClazzNameBuffers, ClazzNameBuffersStaticCstrName, ClazzNameBuffersStaticCstrSignature); - } + if( NativewindowCommon_init(env) ) { + 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, ClazzNamePoint); - if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNamePoint); - } - pointClz = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==pointClz) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNamePoint); - } - pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature); - if(NULL==pointCstr) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't fetch %s.%s %s", - ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); - } -} + c = (*env)->FindClass(env, ClazzNameBuffers); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNameBuffers); + } + clazzBuffers = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==clazzBuffers) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNameBuffers); + } + c = (*env)->FindClass(env, ClazzNameByteBuffer); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNameByteBuffer); + } + clazzByteBuffer = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNameByteBuffer); + } -static JavaVM *jvmHandle = NULL; -static int jvmVersion = 0; + cstrBuffers = (*env)->GetStaticMethodID(env, clazzBuffers, + ClazzNameBuffersStaticCstrName, ClazzNameBuffersStaticCstrSignature); + if(NULL==cstrBuffers) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't create %s.%s %s", + ClazzNameBuffers, ClazzNameBuffersStaticCstrName, ClazzNameBuffersStaticCstrSignature); + } -static void setupJVMVars(JNIEnv * env) { - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; + c = (*env)->FindClass(env, ClazzNamePoint); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't find %s", ClazzNamePoint); + } + pointClz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==pointClz) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't use %s", ClazzNamePoint); + } + pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature); + if(NULL==pointCstr) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_x11_X11Lib: can't fetch %s.%s %s", + ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); + } } - jvmVersion = (*env)->GetVersion(env); } static XErrorHandler origErrorHandler = NULL ; -static int errorHandlerQuiet = 0 ; +static int errorHandlerQuiet = 1 ; static int errorHandlerDebug = 0 ; static int errorHandlerThrowException = 0; static int x11ErrorHandler(Display *dpy, XErrorEvent *e) { - if(!errorHandlerQuiet) { + if( !errorHandlerQuiet || errorHandlerDebug ) { const char * errnoStr = strerror(errno); - char threadName[80]; char errCodeStr[80]; char reqCodeStr[80]; - int shallBeDetached = 0; - JNIEnv *jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + JNIEnv *jniEnv = NULL; - (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, (int)e->resourceid, (int)e->serial, + fprintf(stderr, "Info: Nativewindow X11 Error: %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", + e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, (int)e->request_code, (int)e->minor_code, reqCodeStr); + fflush(stderr); - 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, (int)e->resourceid, (int)e->serial, - (int)e->request_code, (int)e->minor_code, reqCodeStr); - } else { + if( errorHandlerDebug || errorHandlerThrowException ) { + jniEnv = NativewindowCommon_GetJNIEnv(0 /* asDaemon */, &shallBeDetached); + if(NULL == jniEnv) { fprintf(stderr, "Nativewindow X11 Error: null JNIEnv"); - #if 0 - if(NULL!=origErrorHandler) { - origErrorHandler(dpy, e); - } - #endif + fflush(stderr); } } - fflush(stderr); - if (NULL != jniEnv && shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); + if( NULL != jniEnv ) { + if( errorHandlerDebug ) { + (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); + } + + if(errorHandlerThrowException) { + NativewindowCommon_throwNewRuntimeException(jniEnv, "Nativewindow X11 Error: %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", + e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, + (int)e->request_code, (int)e->minor_code, reqCodeStr); + } + NativewindowCommon_ReleaseJNIEnv(shallBeDetached); } } return 0; } -void NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync) { +static void NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int force, int onoff, int quiet, int sync) { errorHandlerQuiet = quiet; if(onoff) { - if(NULL==origErrorHandler) { - setupJVMVars(env); - origErrorHandler = XSetErrorHandler(x11ErrorHandler); + if(force || NULL==origErrorHandler) { + XErrorHandler prevErrorHandler; + prevErrorHandler = XSetErrorHandler(x11ErrorHandler); + if(x11ErrorHandler != prevErrorHandler) { // if forced don't overwrite w/ orig w/ our handler + origErrorHandler = prevErrorHandler; + } if(sync && NULL!=dpy) { XSync(dpy, False); } @@ -246,21 +244,16 @@ static int x11IOErrorHandler(Display *dpy) { const char * dpyName = XDisplayName(NULL); const char * errnoStr = strerror(errno); - char threadName[80]; int shallBeDetached = 0; - JNIEnv *jniEnv = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + JNIEnv *jniEnv = NULL; - (void) NativewindowCommon_GetStaticStringMethod(jniEnv, X11UtilClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); - - fprintf(stderr, "Nativewindow X11 IOError (Thread %s): Display %p (%s): %s\n", threadName, dpy, dpyName, errnoStr); - (*jniEnv)->CallStaticVoidMethod(jniEnv, X11UtilClazz, dumpStackID); + fprintf(stderr, "Nativewindow X11 IOError: Display %p (%s): %s\n", dpy, dpyName, errnoStr); + fflush(stderr); + jniEnv = NativewindowCommon_GetJNIEnv(0 /* asDaemon */, &shallBeDetached); if (NULL != jniEnv) { - NativewindowCommon_FatalError(jniEnv, "Nativewindow X11 IOError (Thread %s): Display %p (%s): %s", threadName, dpy, dpyName, errnoStr); - - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } + NativewindowCommon_FatalError(jniEnv, "Nativewindow X11 IOError: Display %p (%s): %s", dpy, dpyName, errnoStr); + NativewindowCommon_ReleaseJNIEnv(shallBeDetached); } if(NULL!=origIOErrorHandler) { origIOErrorHandler(dpy); @@ -271,7 +264,6 @@ static int x11IOErrorHandler(Display *dpy) static void x11IOErrorHandlerEnable(int onoff, JNIEnv * env) { if(onoff) { if(NULL==origIOErrorHandler) { - setupJVMVars(env); origIOErrorHandler = XSetIOErrorHandler(x11IOErrorHandler); } } else { @@ -280,47 +272,49 @@ static void x11IOErrorHandlerEnable(int onoff, JNIEnv * env) { } } -static int _initialized=0; -static jboolean _xinitThreadsOK=JNI_FALSE; +static int _initialized = 0; JNIEXPORT jboolean JNICALL -Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, jboolean firstUIActionOnProcess, jboolean debug) { - if(0==_initialized) { +Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass clazz, 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; - if(debug) { - fprintf(stderr, "X11: XInitThreads() 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); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 1, debug ? 0 : 1, 0 /* no dpy, force, no sync */); _initialized=1; if(JNI_TRUE == debug) { fprintf(stderr, "Info: NativeWindow native init passed\n"); } } - return _xinitThreadsOK; + return JNI_TRUE; } JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Util_shutdown0(JNIEnv *env, jclass _unused) { + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, errorHandlerQuiet, 0 /* no dpy, no sync */); x11IOErrorHandlerEnable(0, env); } JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Util_setX11ErrorHandler0(JNIEnv *env, jclass _unused, jboolean onoff, jboolean quiet) { - NativewindowCommon_x11ErrorHandlerEnable(env, NULL, onoff ? 1 : 0, quiet ? 1 : 0, 0 /* no dpy, no sync */); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, onoff ? 1 : 0, quiet ? 1 : 0, 0 /* no dpy, force, no sync */); +} + +/* Java->C glue code: + * Java package: jogamp.nativewindow.x11.X11Lib + * Java method: boolean XRenderFindVisualFormat(long dpy, long visual, XRenderPictFormat dest) + */ +JNIEXPORT jboolean JNICALL +Java_jogamp_nativewindow_x11_X11Lib_XRenderFindVisualFormat1(JNIEnv *env, jclass _unused, jlong dpy, jlong visual, jobject xRenderPictFormat) { + XRenderPictFormat * dest = (XRenderPictFormat *) (*env)->GetDirectBufferAddress(env, xRenderPictFormat); + XRenderPictFormat * src = XRenderFindVisualFormat((Display *) (intptr_t) dpy, (Visual *) (intptr_t) visual); + if (NULL == src) return JNI_FALSE; + memcpy(dest, src, sizeof(XRenderPictFormat)); + return JNI_TRUE; } /* Java->C glue code: @@ -332,30 +326,30 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_x11_X11Lib_XGetVisualInfo1__JJLjava_nio_ByteBuffer_2Ljava_lang_Object_2I(JNIEnv *env, jclass _unused, jlong arg0, jlong arg1, jobject arg2, jobject arg3, jint arg3_byte_offset) { XVisualInfo * _ptr2 = NULL; int * _ptr3 = NULL; - XVisualInfo * _res; - int count; - jobject jbyteSource; - jobject jbyteCopy; - if(0==arg0) { - NativewindowCommon_FatalError(env, "invalid display connection.."); - } - if (arg2 != NULL) { - _ptr2 = (XVisualInfo *) (((char*) (*env)->GetDirectBufferAddress(env, arg2)) + 0); - } - if (arg3 != NULL) { - _ptr3 = (int *) (((char*) (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) + arg3_byte_offset); + XVisualInfo * _res = NULL; + int count = 0; + jobject jbyteSource = NULL; + jobject jbyteCopy = NULL; + if( 0 == arg0 || 0 == arg2 || 0 == arg3 ) { + NativewindowCommon_FatalError(env, "invalid display connection, vinfo_template or nitems_return"); + return NULL; } - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 1, 0, 0); - _res = XGetVisualInfo((Display *) (intptr_t) arg0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3); - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, 0); - count = _ptr3[0]; - if (arg3 != NULL) { - (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0); + _ptr2 = (XVisualInfo *) (((char*) (*env)->GetDirectBufferAddress(env, arg2)) + 0); + if( NULL != _ptr2 ) { + _ptr3 = (int *) (((char*) (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) + arg3_byte_offset); + if( NULL != _ptr3 ) { + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 1, errorHandlerQuiet, 0); + _res = XGetVisualInfo((Display *) (intptr_t) arg0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3); + // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) arg0, 0, 0, errorHandlerQuiet, 0); + count = _ptr3[0]; + (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0); + } } if (_res == NULL) return NULL; jbyteSource = (*env)->NewDirectByteBuffer(env, _res, count * sizeof(XVisualInfo)); jbyteCopy = (*env)->CallStaticObjectMethod(env, clazzBuffers, cstrBuffers, jbyteSource); + (*env)->DeleteLocalRef(env, jbyteSource); XFree(_res); @@ -371,10 +365,10 @@ Java_jogamp_nativewindow_x11_X11Lib_GetVisualIDFromWindow(JNIEnv *env, jclass _u if(NULL==dpy) { NativewindowCommon_throwNewRuntimeException(env, "invalid display connection.."); - return; + return 0; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 1); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 1); memset(&xwa, 0, sizeof(XWindowAttributes)); XGetWindowAttributes(dpy, w, &xwa); if(NULL != xwa.visual) { @@ -382,7 +376,7 @@ Java_jogamp_nativewindow_x11_X11Lib_GetVisualIDFromWindow(JNIEnv *env, jclass _u } else { r = 0; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1); return r; } @@ -394,9 +388,9 @@ Java_jogamp_nativewindow_x11_X11Lib_DefaultVisualID(JNIEnv *env, jclass _unused, if(0==display) { NativewindowCommon_FatalError(env, "invalid display connection.."); } - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 1, errorHandlerQuiet, 0); r = (jint) XVisualIDFromVisual( DefaultVisual( (Display*) (intptr_t) display, screen ) ); - NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, (Display *) (intptr_t) display, 0, 0, errorHandlerQuiet, 0); return r; } @@ -437,23 +431,68 @@ Java_jogamp_nativewindow_x11_X11Lib_XCloseDisplay__J(JNIEnv *env, jclass _unused if(0==display) { NativewindowCommon_FatalError(env, "invalid display connection.."); } - NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 1, errorHandlerQuiet, 0); _res = XCloseDisplay((Display *) (intptr_t) display); - NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, NULL, 0, 0, errorHandlerQuiet, 0); return _res; } +static void NativewindowX11_setNormalWindowEWMH (Display *dpy, Window w) { + Atom _NET_WM_WINDOW_TYPE = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE", False ); + Atom types[1]={0}; + types[0] = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False ); + XChangeProperty( dpy, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *)&types, 1); + XSync(dpy, False); +} + +#define DECOR_USE_MWM 1 // works for known WMs +// #define DECOR_USE_EWMH 1 // haven't seen this to work (NORMAL->POPUP, never gets undecorated) + +/* see <http://tonyobryan.com/index.php?article=9> */ +#define MWM_HINTS_DECORATIONS (1L << 1) +#define PROP_MWM_HINTS_ELEMENTS 5 + +static void NativewindowX11_setDecorations (Display *dpy, Window w, Bool decorated) { + +#ifdef DECOR_USE_MWM + unsigned long mwmhints[PROP_MWM_HINTS_ELEMENTS] = { MWM_HINTS_DECORATIONS, 0, decorated, 0, 0 }; // flags, functions, decorations, input_mode, status + Atom _MOTIF_WM_HINTS = XInternAtom( dpy, "_MOTIF_WM_HINTS", False ); +#endif + +#ifdef DECOR_USE_EWMH + Atom _NET_WM_WINDOW_TYPE = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE", False ); + Atom types[3]={0}; + int ntypes=0; + if(True==decorated) { + types[ntypes++] = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False ); + } else { + types[ntypes++] = XInternAtom( dpy, "_NET_WM_WINDOW_TYPE_POPUP_MENU", False ); + } +#endif + +#ifdef DECOR_USE_MWM + XChangeProperty( dpy, w, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropModeReplace, (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS); +#endif + +#ifdef DECOR_USE_EWMH + XChangeProperty( dpy, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *)&types, ntypes); +#endif + + XSync(dpy, False); +} + /* * Class: jogamp_nativewindow_x11_X11Lib - * Method: CreateDummyWindow - * Signature: (JIIII)J + * Method: CreateWindow + * Signature: (JJIIIIZZ)J */ -JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow - (JNIEnv *env, jclass unused, jlong display, jint screen_index, jint visualID, jint width, jint height) +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateWindow + (JNIEnv *env, jclass unused, jlong parent, jlong display, jint screen_index, jint visualID, jint width, jint height, jboolean input, jboolean visible) { Display * dpy = (Display *)(intptr_t)display; int scrn_idx = (int)screen_index; - Window windowParent = 0; + Window root = RootWindow(dpy, scrn_idx); + Window windowParent = (Window) parent; Window window = 0; XVisualInfo visualTemplate; @@ -477,9 +516,12 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow return 0; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 0); scrn = ScreenOfDisplay(dpy, scrn_idx); + if(0==windowParent) { + windowParent = root; + } // try given VisualID on screen memset(&visualTemplate, 0, sizeof(XVisualInfo)); @@ -497,7 +539,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow if (visual==NULL) { - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1); NativewindowCommon_throwNewRuntimeException(env, "could not query Visual by given VisualID, bail out!"); return 0; } @@ -507,9 +549,6 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow pVisualQuery=NULL; } - if(0==windowParent) { - windowParent = XRootWindowOfScreen(scrn); - } attrMask = ( CWBackingStore | CWBackingPlanes | CWBackingPixel | CWBackPixmap | CWBorderPixel | CWColormap | CWOverrideRedirect ) ; @@ -521,15 +560,22 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow 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 */ + if( input ) { + xswa.event_mask = X11_MOUSE_EVENT_MASK; + xswa.event_mask |= KeyPressMask | KeyReleaseMask ; + } + if( visible ) { + xswa.event_mask |= FocusChangeMask | SubstructureNotifyMask | StructureNotifyMask | ExposureMask ; + } xswa.colormap = XCreateColormap(dpy, - XRootWindow(dpy, scrn_idx), + windowParent, visual, AllocNone); window = XCreateWindow(dpy, windowParent, - 0, 0, + 0, 0, // only a hint, WM most likely will override width, height, 0, // border width depth, @@ -537,11 +583,27 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow visual, attrMask, &xswa); + if(0==window) { + NativewindowCommon_throwNewRuntimeException(env, "could not create Window, bail out!"); + return 0; + } + + NativewindowX11_setNormalWindowEWMH(dpy, window); + NativewindowX11_setDecorations(dpy, window, False); + + if( visible ) { + XEvent event; + + XMapWindow(dpy, window); + } + XSync(dpy, False); - XSelectInput(dpy, window, 0); // no events + if( !input ) { + XSelectInput(dpy, window, 0); // no events + } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1); DBG_PRINT( "X11: [CreateWindow] created window %p on display %p\n", window, dpy); @@ -551,25 +613,57 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_x11_X11Lib_CreateDummyWindow /* * Class: jogamp_nativewindow_x11_X11Lib - * Method: DestroyDummyWindow + * Method: DestroyWindow * Signature: (JJ)V */ -JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyDummyWindow +JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_DestroyWindow (JNIEnv *env, jclass unused, jlong display, jlong window) { Display * dpy = (Display *)(intptr_t)display; Window w = (Window) window; + XWindowAttributes xwa; if(NULL==dpy) { NativewindowCommon_throwNewRuntimeException(env, "invalid display connection.."); return; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 0); + XSync(dpy, False); + memset(&xwa, 0, sizeof(XWindowAttributes)); + XGetWindowAttributes(dpy, w, &xwa); // prefetch colormap to be destroyed after window destruction + XSelectInput(dpy, w, 0); XUnmapWindow(dpy, w); XSync(dpy, False); XDestroyWindow(dpy, w); - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); + if( None != xwa.colormap ) { + XFreeColormap(dpy, xwa.colormap); + } + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 1); +} + +JNIEXPORT void JNICALL Java_jogamp_nativewindow_x11_X11Lib_SetWindowPosSize + (JNIEnv *env, jclass unused, jlong display, jlong window, jint x, jint y, jint width, jint height) { + Display * dpy = (Display *)(intptr_t)display; + Window w = (Window) window; + XWindowChanges xwc; + int flags = 0; + + memset(&xwc, 0, sizeof(XWindowChanges)); + + if(0<=x && 0<=y) { + flags |= CWX | CWY; + xwc.x=x; + xwc.y=y; + } + + if(0<width && 0<height) { + flags |= CWWidth | CWHeight; + xwc.width=width; + xwc.height=height; + } + XConfigureWindow(dpy, w, flags, &xwc); + XSync(dpy, False); } /* @@ -593,11 +687,11 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_x11_X11Lib_GetRelativeLocatio if( 0 == jdest_win ) { dest_win = root; } if( 0 == jsrc_win ) { src_win = root; } - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); + NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 1, errorHandlerQuiet, 0); res = XTranslateCoordinates(dpy, src_win, dest_win, src_x, src_y, &dest_x, &dest_y, &child); - NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, 0); + // NativewindowCommon_x11ErrorHandlerEnable(env, dpy, 0, 0, errorHandlerQuiet, 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); @@ -605,3 +699,38 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_x11_X11Lib_GetRelativeLocatio return (*env)->NewObject(env, pointClz, pointCstr, (jint)dest_x, (jint)dest_y); } +/* + * Class: jogamp_nativewindow_x11_X11Lib + * Method: QueryExtension0 + * Signature: (JLjava/lang/String;)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_x11_X11Lib_QueryExtension0 + (JNIEnv *env, jclass unused, jlong jdisplay, jstring jextensionName) +{ + int32_t major_opcode, first_event, first_error; + jboolean res = JNI_FALSE; + Display * display = (Display *) (intptr_t) jdisplay; + const char* extensionName = NULL; + + if(NULL==display) { + NativewindowCommon_throwNewRuntimeException(env, "NULL argument \"display\""); + return res; + } + if ( NULL == jextensionName ) { + NativewindowCommon_throwNewRuntimeException(env, "NULL argument \"extensionName\""); + return res; + } + extensionName = (*env)->GetStringUTFChars(env, jextensionName, (jboolean*)NULL); + if ( NULL == extensionName ) { + NativewindowCommon_throwNewRuntimeException(env, "Failed to get UTF-8 chars for argument \"extensionName\""); + return res; + } + + res = True == XQueryExtension(display, extensionName, &major_opcode, &first_event, &first_error) ? JNI_TRUE : JNI_FALSE; + + if ( NULL != jextensionName ) { + (*env)->ReleaseStringUTFChars(env, jextensionName, extensionName); + } + return res; +} + diff --git a/src/nativewindow/native/x11/Xmisc.h b/src/nativewindow/native/x11/Xmisc.h index a44da950d..91f2ac5d9 100644 --- a/src/nativewindow/native/x11/Xmisc.h +++ b/src/nativewindow/native/x11/Xmisc.h @@ -39,6 +39,4 @@ #include <X11/Xlib.h> #include <X11/Xutil.h> -void NativewindowCommon_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync); - #endif /* Xmisc_h */ |