aboutsummaryrefslogtreecommitdiffstats
path: root/src/newt/native/MacWindow.m
diff options
context:
space:
mode:
Diffstat (limited to 'src/newt/native/MacWindow.m')
-rw-r--r--src/newt/native/MacWindow.m295
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];
}