diff options
Diffstat (limited to 'src/newt/native/MacWindow.m')
-rw-r--r-- | src/newt/native/MacWindow.m | 295 |
1 files changed, 260 insertions, 35 deletions
diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m index a13ffaf31..ddd59f0a1 100644 --- a/src/newt/native/MacWindow.m +++ b/src/newt/native/MacWindow.m @@ -38,6 +38,7 @@ #import "MouseEvent.h" #import "KeyEvent.h" +#import "ScreenMode.h" #import <ApplicationServices/ApplicationServices.h> @@ -48,7 +49,6 @@ static const char * const ClazzAnyCstrName = "<init>"; static const char * const ClazzNamePointCstrSignature = "(II)V"; static jclass pointClz = NULL; static jmethodID pointCstr = NULL; -static jmethodID focusActionID = NULL; static NSString* jstringToNSString(JNIEnv* env, jstring jstr) { @@ -192,13 +192,57 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_MacDisplay_initNSAppli JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacDisplay_runNSApplication0 (JNIEnv *env, jclass clazz) { - // NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; DBG_PRINT( "\nrunNSApplication0.0\n"); [NSApp run]; DBG_PRINT( "\nrunNSApplication0.X\n"); - // [pool release]; + [pool release]; +} + +/* + * Class: jogamp_newt_driver_macosx_MacDisplay + * Method: stopNSApplication0 + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacDisplay_stopNSApplication0 + (JNIEnv *env, jclass clazz) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + DBG_PRINT( "\nstopNSApplication0.0 nsApp.running %d\n", (NSApp && [NSApp isRunning])); + + if(NSApp && [NSApp isRunning]) { + [NSApp performSelectorOnMainThread:@selector(stop:) withObject:nil waitUntilDone:YES]; + // [NSApp stop: nil]; + NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined + location: NSMakePoint(0,0) + modifierFlags: 0 + timestamp: 0.0 + windowNumber: 0 + context: nil + subtype: 0 + data1: 0 + data2: 0]; + DBG_PRINT( "\nstopNSApplication0.1\n"); + [NSApp postEvent: event atStart: true]; + } + /** + DBG_PRINT( "\nstopNSApplication0.2\n"); + if(NSApp && [NSApp isRunning]) { + DBG_PRINT( "\nstopNSApplication0.3\n"); + [NSApp terminate:nil]; + } */ + + DBG_PRINT( "\nstopNSApplication0.X\n"); + [pool release]; +} + +static NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx) { + NSArray *screens = [NSScreen screens]; + if(screen_idx<0) screen_idx=0; + if(screen_idx>=[screens count]) screen_idx=0; + return (NSScreen *) [screens objectAtIndex: screen_idx]; } /* @@ -211,10 +255,7 @@ JNIEXPORT jint JNICALL Java_jogamp_newt_driver_macosx_MacScreen_getWidthImpl0 { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSArray *screens = [NSScreen screens]; - if(screen_idx<0) screen_idx=0; - if(screen_idx>=[screens count]) screen_idx=0; - NSScreen *screen = (NSScreen *) [screens objectAtIndex: screen_idx]; + NSScreen *screen = NewtScreen_getNSScreenByIndex((int)screen_idx); NSRect rect = [screen frame]; [pool release]; @@ -232,10 +273,7 @@ JNIEXPORT jint JNICALL Java_jogamp_newt_driver_macosx_MacScreen_getHeightImpl0 { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSArray *screens = [NSScreen screens]; - if(screen_idx<0) screen_idx=0; - if(screen_idx>=[screens count]) screen_idx=0; - NSScreen *screen = (NSScreen *) [screens objectAtIndex: screen_idx]; + NSScreen *screen = NewtScreen_getNSScreenByIndex((int)screen_idx); NSRect rect = [screen frame]; [pool release]; @@ -243,6 +281,175 @@ JNIEXPORT jint JNICALL Java_jogamp_newt_driver_macosx_MacScreen_getHeightImpl0 return (jint) (rect.size.height); } +static CGDirectDisplayID NewtScreen_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]; +} + +/** + * Only in >= 10.6: + * CGDisplayModeGetWidth(mode) + * CGDisplayModeGetRefreshRate(mode) + * CGDisplayModeGetHeight(mode) + */ +static long GetDictionaryLong(CFDictionaryRef theDict, const void* key) +{ + long value = 0; + CFNumberRef numRef; + numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key); + if (numRef != NULL) + CFNumberGetValue(numRef, kCFNumberLongType, &value); + return value; +} +#define CGDDGetModeWidth(mode) GetDictionaryLong((mode), kCGDisplayWidth) +#define CGDDGetModeHeight(mode) GetDictionaryLong((mode), kCGDisplayHeight) +#define CGDDGetModeRefreshRate(mode) GetDictionaryLong((mode), kCGDisplayRefreshRate) +#define CGDDGetModeBitsPerPixel(mode) GetDictionaryLong((mode), kCGDisplayBitsPerPixel) + +// Duplicate each Mode by all possible rotations (4): +// For each real-mode: [mode, 0], [mode, 90], [mode, 180], [mode, 270] +#define ROTMODES_PER_REALMODE 4 + +/* + * Class: jogamp_newt_driver_macosx_MacScreen + * Method: getScreenMode0 + * Signature: (II)[I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_MacScreen_getScreenMode0 + (JNIEnv *env, jobject obj, jint scrn_idx, jint mode_idx) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + int prop_num = NUM_SCREEN_MODE_PROPERTIES_ALL; + NSScreen *screen = NewtScreen_getNSScreenByIndex((int)scrn_idx); + CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen); + + CFArrayRef availableModes = CGDisplayAvailableModes(display); + CFIndex numberOfAvailableModes = CFArrayGetCount(availableModes); + CFIndex numberOfAvailableModesRots = ROTMODES_PER_REALMODE * numberOfAvailableModes; + CFDictionaryRef mode = NULL; + int currentCCWRot = (int)CGDisplayRotation(display); + jint ccwRot = 0; + +#ifdef VERBOSE_ON + if(0 >= mode_idx) { + // only for current mode (-1) and first mode (scanning) + DBG_PRINT( "getScreenMode0: scrn %d (%p, %p), mode %d, avail: %d/%d, current rot %d ccw\n", + (int)scrn_idx, screen, (void*)(intptr_t)display, (int)mode_idx, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots, currentCCWRot); + } +#endif + + if(numberOfAvailableModesRots<=mode_idx) { + // n/a - end of modes + DBG_PRINT( "getScreenMode0: end of modes: mode %d, avail: %d/%d\n", + (int)mode_idx, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots); + [pool release]; + return (*env)->NewIntArray(env, 0); + } else if(-1 < mode_idx) { + // only at initialization time, where index >= 0 + prop_num++; // add 1st extra prop, mode_idx + mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, mode_idx / ROTMODES_PER_REALMODE); + ccwRot = mode_idx % ROTMODES_PER_REALMODE * 90; + } else { + // current mode + mode = CGDisplayCurrentMode(display); + ccwRot = currentCCWRot; + } + // mode = CGDisplayModeRetain(mode); // 10.6 on CGDisplayModeRef + + CGSize screenDim = CGDisplayScreenSize(display); + int mWidth = CGDDGetModeWidth(mode); + int mHeight = CGDDGetModeHeight(mode); + + // swap width and height, since OSX reflects rotated dimension, we don't + if ( 90 == currentCCWRot || 270 == currentCCWRot ) { + int tempWidth = mWidth; + mWidth = mHeight; + mHeight = tempWidth; + } + + jint prop[ prop_num ]; + int propIndex = 0; + int propIndexRes = 0; + + if( -1 < mode_idx ) { + prop[propIndex++] = mode_idx; + } + prop[propIndex++] = 0; // set later for verification of iterator + propIndexRes = propIndex; + prop[propIndex++] = mWidth; + prop[propIndex++] = mHeight; + prop[propIndex++] = CGDDGetModeBitsPerPixel(mode); + prop[propIndex++] = (jint) screenDim.width; + prop[propIndex++] = (jint) screenDim.height; + prop[propIndex++] = CGDDGetModeRefreshRate(mode); + prop[propIndex++] = ccwRot; + prop[propIndex - NUM_SCREEN_MODE_PROPERTIES_ALL] = ( -1 < mode_idx ) ? propIndex-1 : propIndex ; // count == NUM_SCREEN_MODE_PROPERTIES_ALL + + DBG_PRINT( "getScreenMode0: Mode %d/%d (%d): %dx%d, %d bpp, %dx%d mm, %d Hz, rot %d ccw\n", + (int)mode_idx, (int)numberOfAvailableModesRots, (int)numberOfAvailableModes, + (int)prop[propIndexRes+0], (int)prop[propIndexRes+1], (int)prop[propIndexRes+2], + (int)prop[propIndexRes+3], (int)prop[propIndexRes+4], (int)prop[propIndexRes+5], (int)prop[propIndexRes+6]); + + jintArray properties = (*env)->NewIntArray(env, prop_num); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", prop_num); + } + (*env)->SetIntArrayRegion(env, properties, 0, prop_num, prop); + + // CGDisplayModeRelease(mode); // 10.6 on CGDisplayModeRef + [pool release]; + + return properties; +} + +/* + * Class: jogamp_newt_driver_macosx_MacScreen + * Method: setScreenMode0 + * Signature: (II)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_MacScreen_setScreenMode0 + (JNIEnv *env, jobject object, jint scrn_idx, jint mode_idx) +{ + jboolean res = JNI_TRUE; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + NSScreen *screen = NewtScreen_getNSScreenByIndex((int)scrn_idx); + CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen); + + CFArrayRef availableModes = CGDisplayAvailableModes(display); + CFIndex numberOfAvailableModes = CFArrayGetCount(availableModes); + CFIndex numberOfAvailableModesRots = ROTMODES_PER_REALMODE * numberOfAvailableModes; + + CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, mode_idx / ROTMODES_PER_REALMODE); + // mode = CGDisplayModeRetain(mode); // 10.6 on CGDisplayModeRef + + int ccwRot = mode_idx % ROTMODES_PER_REALMODE * 90; + DBG_PRINT( "setScreenMode0: scrn %d (%p, %p), mode %d, rot %d ccw, avail: %d/%d\n", + (int)scrn_idx, screen, (void*)(intptr_t)display, (int)mode_idx, ccwRot, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots); + + if(ccwRot!=0) { + // FIXME: How to rotate the display/screen on OSX programmatically ? + DBG_PRINT( "setScreenMode0: Don't know how to rotate screen on OS X: rot %d ccw\n", ccwRot); + res = JNI_FALSE; + } + if(JNI_TRUE == res) { + CGError err = CGDisplaySwitchToMode(display, mode); + if(kCGErrorSuccess != err) { + DBG_PRINT( "setScreenMode0: SetMode failed: %d\n", (int)err); + res = JNI_FALSE; + } + } + + // CGDisplayModeRelease(mode); // 10.6 on CGDisplayModeRef + [pool release]; + + return res; +} + /* * Class: jogamp_newt_driver_macosx_MacWindow * Method: initIDs @@ -272,11 +479,6 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_MacWindow_initIDs0 ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); } - focusActionID = (*env)->GetMethodID(env, clazz, "focusAction", "()Z"); - if(NULL==focusActionID) { - NewtCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch method focusAction()Z"); - } - // Need this when debugging, as it is necessary to attach gdb to // the running java process -- "gdb java" doesn't work // printf("Going to sleep for 10 seconds\n"); @@ -449,8 +651,9 @@ NS_DURING if([mView isInFullScreenMode]) { [mView exitFullScreenModeWithOptions: NULL]; } - [mWin setContentView: nil]; - [mView release]; + // Note: mWin's release will also release it's mView! + // [mWin setContentView: nil]; + // [mView release]; } NS_HANDLER NS_ENDHANDLER @@ -463,7 +666,11 @@ NS_ENDHANDLER DBG_PRINT( "windowClose.1 - %p,%d view %p,%d, parent %p\n", mWin, getRetainCount(mWin), mView, getRetainCount(mView), pWin); - [mWin close]; // performs release! + // '[mWin close]' causes a crash at exit. + // This probably happens b/c it sends events to the main loop + // but our resources are gone ?! + // However, issuing a simple release seems to work quite well. + [mWin release]; DBG_PRINT( "windowClose.X - %p,%d view %p,%d, parent %p\n", mWin, getRetainCount(mWin), mView, getRetainCount(mView), pWin); @@ -510,26 +717,44 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_requestFocus0 (JNIEnv *env, jobject window, jlong w, jboolean force) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSWindow* win = (NSWindow*) ((intptr_t) w); + NSWindow* mWin = (NSWindow*) ((intptr_t) w); #ifdef VERBOSE_ON - BOOL hasFocus = [win isKeyWindow]; + BOOL hasFocus = [mWin isKeyWindow]; #endif - DBG_PRINT( "requestFocus - window: %p, force %d, hasFocus %d (START)\n", win, force, hasFocus); - - // Even if we already own the focus, we need the 'focusAction()' call - // and the other probably redundant NS calls to force proper focus traversal - // of the parent TK (AWT doesn't do it properly on OSX). - if( JNI_TRUE==force || JNI_FALSE == (*env)->CallBooleanMethod(env, window, focusActionID) ) { - DBG_PRINT( "makeKeyWindow win %p\n", win); - // [win performSelectorOnMainThread:@selector(orderFrontRegardless) withObject:nil waitUntilDone:YES]; - // [win performSelectorOnMainThread:@selector(makeKeyWindow) withObject:nil waitUntilDone:YES]; - [win orderFrontRegardless]; - [win makeKeyWindow]; - [win makeFirstResponder: nil]; - } + DBG_PRINT( "requestFocus - window: %p, force %d, hasFocus %d (START)\n", mWin, force, hasFocus); + + [mWin makeFirstResponder: nil]; + // [mWin performSelectorOnMainThread:@selector(orderFrontRegardless) withObject:nil waitUntilDone:YES]; + // [mWin performSelectorOnMainThread:@selector(makeKeyWindow) withObject:nil waitUntilDone:YES]; + [mWin orderFrontRegardless]; + [mWin makeKeyWindow]; + + DBG_PRINT( "requestFocus - window: %p, force %d (END)\n", mWin, force); + + [pool release]; +} - DBG_PRINT( "requestFocus - window: %p, force %d (END)\n", win, force); +/* + * Class: jogamp_newt_driver_macosx_MacWindow + * Method: requestFocusParent0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_requestFocusParent0 + (JNIEnv *env, jobject window, jlong w) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSWindow* mWin = (NSWindow*) ((intptr_t) w); + NSWindow* pWin = [mWin parentWindow]; +#ifdef VERBOSE_ON + BOOL hasFocus = [mWin isKeyWindow]; +#endif + + DBG_PRINT( "requestFocusParent0 - window: %p, parent: %p, hasFocus %d (START)\n", mWin, pWin, hasFocus ); + if(NULL != pWin) { + [pWin makeKeyWindow]; + } + DBG_PRINT( "requestFocusParent0 - window: %p, parent: %p (END)\n", mWin, pWin); [pool release]; } |