Jogamp
80e70216ed61664fe1917614569ed6de52fd29b9
[jogl.git] / src / newt / native / MacWindow.m
1 /*
2  * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
3  * 
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  * 
8  * - Redistribution of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * 
11  * - Redistribution in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in the
13  *   documentation and/or other materials provided with the distribution.
14  * 
15  * Neither the name of Sun Microsystems, Inc. or the names of
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  * 
19  * This software is provided "AS IS," without a warranty of any kind. ALL
20  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
23  * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
24  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
25  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
26  * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
27  * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
28  * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
29  * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
30  * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  * 
32  */
33
34 #import <inttypes.h>
35
36 #import "jogamp_newt_driver_macosx_WindowDriver.h"
37 #import "NewtMacWindow.h"
38
39 #import "MouseEvent.h"
40 #import "KeyEvent.h"
41 #import "ScreenMode.h"
42
43 #import <ApplicationServices/ApplicationServices.h>
44
45 #import <stdio.h>
46
47 #ifdef DBG_PERF
48     #include "timespec.h"
49 #endif
50
51 static const char * const ClazzNamePoint = "javax/media/nativewindow/util/Point";
52 static const char * const ClazzAnyCstrName = "<init>";
53 static const char * const ClazzNamePointCstrSignature = "(II)V";
54 static jclass pointClz = NULL;
55 static jmethodID pointCstr = NULL;
56
57 static NSString* jstringToNSString(JNIEnv* env, jstring jstr)
58 {
59     const jchar* jstrChars = (*env)->GetStringChars(env, jstr, NULL);
60     NSString* str = [[NSString alloc] initWithCharacters: jstrChars length: (*env)->GetStringLength(env, jstr)];
61     (*env)->ReleaseStringChars(env, jstr, jstrChars);
62     return str;
63 }
64
65 static void setWindowClientTopLeftPoint(NewtMacWindow* mWin, jint x, jint y, BOOL doDisplay) {
66     DBG_PRINT( "setWindowClientTopLeftPoint.0 - window: %p %d/%d, display %d\n", mWin, (int)x, (int)y, (int)doDisplay);
67     NSPoint pS = [mWin newtAbsClientTLWinPos2AbsBLScreenPos: NSMakePoint(x, y)];
68     DBG_PRINT( "setWindowClientTopLeftPoint.1: %d/%d\n", (int)pS.x, (int)pS.y);
69
70     [mWin setFrameOrigin: pS];
71     DBG_PRINT( "setWindowClientTopLeftPoint.X: %d/%d\n", (int)pS.x, (int)pS.y);
72
73     if( doDisplay ) {
74         NSView* mView = [mWin contentView];
75         [mWin invalidateCursorRectsForView: mView];
76     }
77 }
78
79 static void setWindowClientTopLeftPointAndSize(NewtMacWindow* mWin, jint x, jint y, jint width, jint height, BOOL doDisplay) {
80     DBG_PRINT( "setWindowClientTopLeftPointAndSize.0 - window: %p %d/%d %dx%d, display %d\n", mWin, (int)x, (int)y, (int)width, (int)height, (int)doDisplay);
81     NSSize clientSZ = NSMakeSize(width, height);
82     NSPoint pS = [mWin newtAbsClientTLWinPos2AbsBLScreenPos: NSMakePoint(x, y) size: clientSZ];
83     NSSize topSZ = [mWin newtClientSize2TLSize: clientSZ];
84     NSRect rect = { pS, topSZ };
85     DBG_PRINT( "setWindowClientTopLeftPointAndSize.1: %d/%d %dx%d\n", (int)rect.origin.x, (int)rect.origin.y, (int)rect.size.width, (int)rect.size.height);
86
87     [mWin setFrame: rect display:doDisplay];
88     DBG_PRINT( "setWindowClientTopLeftPointAndSize.X: %d/%d %dx%d\n", (int)rect.origin.x, (int)rect.origin.y, (int)rect.size.width, (int)rect.size.height);
89
90     // -> display:YES
91     // if( doDisplay ) {
92     //   NSView* mView = [mWin contentView];
93     //   [mWin invalidateCursorRectsForView: mView];
94     // }
95 }
96
97 #ifdef VERBOSE_ON
98 static int getRetainCount(NSObject * obj) {
99     return ( NULL == obj ) ? -1 : (int)([obj retainCount]) ;
100 }
101 #endif
102
103 static void setJavaWindowObject(JNIEnv *env, jobject newJavaWindowObject, NewtView *view, BOOL enable) {
104     DBG_PRINT( "setJavaWindowObject.0: View %p\n", view);
105     if( !enable) {
106         jobject globJavaWindowObject = [view getJavaWindowObject];
107         if( NULL != globJavaWindowObject ) {
108             DBG_PRINT( "setJavaWindowObject.1: View %p - Clear old javaWindowObject %p\n", view, globJavaWindowObject);
109             (*env)->DeleteGlobalRef(env, globJavaWindowObject);
110             [view setJavaWindowObject: NULL];
111         }
112     } else if( NULL != newJavaWindowObject ) {
113         DBG_PRINT( "setJavaWindowObject.2: View %p - Set new javaWindowObject %p\n", view, newJavaWindowObject);
114         jobject globJavaWindowObject = (*env)->NewGlobalRef(env, newJavaWindowObject);
115         [view setJavaWindowObject: globJavaWindowObject];
116     }
117     DBG_PRINT( "setJavaWindowObject.X: View %p\n", view);
118 }
119
120 static void changeContentView(JNIEnv *env, jobject javaWindowObject, NSView *pview, NewtMacWindow *win, NewtView *newView, BOOL setJavaWindow) {
121     NSView* oldNSView = [win contentView];
122     NewtView* oldNewtView = NULL;
123 #ifdef VERBOSE_ON
124     int dbgIdx = 1;
125 #endif
126
127     if( [oldNSView isKindOfClass:[NewtView class]] ) {
128         oldNewtView = (NewtView *) oldNSView;
129     }
130
131     DBG_PRINT( "changeContentView.%d win %p, view (%p,%d (%d) -> %p,%d), parent view %p\n", 
132         dbgIdx++, win, oldNSView, getRetainCount(oldNSView), NULL!=oldNewtView, newView, getRetainCount(newView), pview);
133
134     if( NULL!=oldNSView ) {
135 NS_DURING
136         // Available >= 10.5 - Makes the menubar disapear
137         BOOL iifs;
138         if ( [oldNSView respondsToSelector:@selector(isInFullScreenMode)] ) {
139             iifs = [oldNSView isInFullScreenMode];
140         } else {
141             iifs = NO;
142         }
143         if(iifs && [oldNSView respondsToSelector:@selector(exitFullScreenModeWithOptions:)] ) {
144             [oldNSView exitFullScreenModeWithOptions: NULL];
145         }
146 NS_HANDLER
147 NS_ENDHANDLER
148         DBG_PRINT( "changeContentView.%d win %p, view (%p,%d (%d) -> %p,%d)\n", 
149             dbgIdx++, win, oldNSView, getRetainCount(oldNSView), NULL!=oldNewtView, newView, getRetainCount(newView));
150
151         if( NULL != oldNewtView ) {
152             [oldNewtView setDestroyNotifySent: false];
153             setJavaWindowObject(env, NULL, oldNewtView, NO);
154         }
155         [oldNSView removeFromSuperviewWithoutNeedingDisplay];
156     }
157     DBG_PRINT( "changeContentView.%d win %p, view (%p,%d -> %p,%d), isHidden %d, isHiddenOrHasHiddenAncestor: %d\n", 
158         dbgIdx++, win, oldNSView, getRetainCount(oldNSView), newView, getRetainCount(newView), [newView isHidden], [newView isHiddenOrHasHiddenAncestor]);
159
160     if( NULL!=newView ) {
161         [newView setDestroyNotifySent: false];
162         if( setJavaWindow ) {
163             setJavaWindowObject(env, javaWindowObject, newView, YES);
164         }
165
166         DBG_PRINT( "changeContentView.%d win %p, view (%p,%d -> %p,%d)\n", 
167             dbgIdx++, win, oldNSView, getRetainCount(oldNSView), newView, getRetainCount(newView));
168
169         if(NULL!=pview) {
170             [pview addSubview: newView positioned: NSWindowAbove relativeTo: nil];
171         }
172     }
173     DBG_PRINT( "changeContentView.%d win %p, view (%p,%d -> %p,%d), isHidden %d, isHiddenOrHasHiddenAncestor: %d\n", 
174         dbgIdx++, win, oldNSView, getRetainCount(oldNSView), newView, getRetainCount(newView), [newView isHidden], [newView isHiddenOrHasHiddenAncestor]);
175
176     [win setContentView: newView];
177
178     DBG_PRINT( "changeContentView.%d win %p, view (%p,%d -> %p,%d), isHidden %d, isHiddenOrHasHiddenAncestor: %d\n", 
179         dbgIdx++, win, oldNSView, getRetainCount(oldNSView), newView, getRetainCount(newView), [newView isHidden], [newView isHiddenOrHasHiddenAncestor]);
180
181     // make sure the insets are updated in the java object
182     [win updateInsets: env jwin:javaWindowObject];
183
184     DBG_PRINT( "changeContentView.X win %p, view (%p,%d -> %p,%d)\n", 
185         win, oldNSView, getRetainCount(oldNSView), newView, getRetainCount(newView));
186 }
187
188 /*
189  * Class:     jogamp_newt_driver_macosx_DisplayDriver
190  * Method:    initIDs
191  * Signature: ()Z
192  */
193 JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_initNSApplication0
194   (JNIEnv *env, jclass clazz)
195 {
196     static int initialized = 0;
197
198     if(initialized) return JNI_TRUE;
199     initialized = 1;
200
201     NewtCommon_init(env);
202
203     // This little bit of magic is needed in order to receive mouse
204     // motion events and allow key focus to be properly transferred.
205     // FIXME: are these Carbon APIs? They come from the
206     // ApplicationServices.framework.
207     ProcessSerialNumber psn;
208     if (GetCurrentProcess(&psn) == noErr) {
209         TransformProcessType(&psn, kProcessTransformToForegroundApplication);
210         SetFrontProcess(&psn);
211     }
212
213     // Initialize the shared NSApplication instance
214     [NSApplication sharedApplication];
215
216     // Need this when debugging, as it is necessary to attach gdb to
217     // the running java process -- "gdb java" doesn't work
218     //    printf("Going to sleep for 10 seconds\n");
219     //    sleep(10);
220
221     return (jboolean) JNI_TRUE;
222 }
223
224 /*
225  * Class:     jogamp_newt_driver_macosx_DisplayDriver
226  * Method:    runNSApplication0
227  * Signature: ()V
228  */
229 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_runNSApplication0
230   (JNIEnv *env, jclass clazz)
231 {
232     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
233     DBG_PRINT( "\nrunNSApplication0.0\n");
234
235     [NSApp run];
236
237     DBG_PRINT( "\nrunNSApplication0.X\n");
238     [pool release];
239 }
240
241 /*
242  * Class:     jogamp_newt_driver_macosx_DisplayDriver
243  * Method:    stopNSApplication0
244  * Signature: ()V
245  */
246 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_stopNSApplication0
247   (JNIEnv *env, jclass clazz)
248 {
249     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
250     DBG_PRINT( "\nstopNSApplication0.0 nsApp.running %d\n", (NSApp && [NSApp isRunning]));
251
252     if(NSApp && [NSApp isRunning]) {
253         [NSApp performSelectorOnMainThread:@selector(stop:) withObject:nil waitUntilDone:YES];
254         // [NSApp stop: nil];
255         NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
256                                             location: NSMakePoint(0,0)
257                                        modifierFlags: 0
258                                            timestamp: 0.0
259                                         windowNumber: 0
260                                              context: nil
261                                              subtype: 0
262                                                data1: 0
263                                                data2: 0];
264         DBG_PRINT( "\nstopNSApplication0.1\n");
265         [NSApp postEvent: event atStart: true];
266     }
267     /**
268     DBG_PRINT( "\nstopNSApplication0.2\n");
269     if(NSApp && [NSApp isRunning]) {
270         DBG_PRINT( "\nstopNSApplication0.3\n");
271         [NSApp terminate:nil];
272     } */
273
274     DBG_PRINT( "\nstopNSApplication0.X\n");
275     [pool release];
276 }
277
278 static NSImage * createNSImageFromData(JNIEnv *env, unsigned char * iconData, jint jiconWidth, jint jiconHeight) {
279     if( NULL != iconData ) {
280         NSInteger iconWidth = (NSInteger) jiconWidth;
281         NSInteger iconHeight = (NSInteger) jiconHeight;
282         const NSInteger bpc = 8 /* bits per component */, spp=4 /* RGBA */, bpp = bpc * spp;
283         const NSBitmapFormat bfmt = NSAlphaNonpremultipliedBitmapFormat;
284         const BOOL hasAlpha = YES;
285
286         NSBitmapImageRep* bir = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: &iconData
287                                     pixelsWide: iconWidth
288                                     pixelsHigh: iconHeight
289                                     bitsPerSample: bpc
290                                     samplesPerPixel: spp
291                                     hasAlpha: hasAlpha
292                                     isPlanar: NO
293                                     colorSpaceName: NSCalibratedRGBColorSpace
294                                     bitmapFormat: bfmt
295                                     bytesPerRow: iconWidth*4
296                                     bitsPerPixel: bpp];
297         [bir autorelease];
298         NSImage* nsImage = [[NSImage alloc] initWithCGImage: [bir CGImage] size:NSZeroSize];
299         return nsImage;
300     }
301     return NULL;
302 }
303
304 /*
305  * Class:     jogamp_newt_driver_macosx_DisplayDriver
306  * Method:    setAppIcon0
307  */
308 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_setAppIcon0
309   (JNIEnv *env, jobject unused, jobject pixels, jint pixels_byte_offset, jboolean pixels_is_direct, jint width, jint height)
310 {
311     if( 0 == pixels ) {
312         return;
313     }
314     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
315     // NOTE: MUST BE DIRECT BUFFER, since NSBitmapImageRep uses buffer directly!
316     unsigned char * pixelPtr = (unsigned char *) ( JNI_TRUE == pixels_is_direct ? 
317                                             (*env)->GetDirectBufferAddress(env, pixels) : 
318                                             (*env)->GetPrimitiveArrayCritical(env, pixels, NULL) );
319     NSImage * nsImage = createNSImageFromData(env, pixelPtr + pixels_byte_offset, width, height);
320     if( NULL != nsImage ) {
321         [nsImage autorelease];
322         [NSApp setApplicationIconImage: nsImage];
323     }
324     if ( JNI_FALSE == pixels_is_direct ) {
325         (*env)->ReleasePrimitiveArrayCritical(env, pixels, (void*)pixelPtr, JNI_ABORT);  
326     }
327     [pool release];
328 }
329
330 JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_createPointerIcon0
331   (JNIEnv *env, jobject unused, jobject pixels, jint pixels_byte_offset, jboolean pixels_is_direct, jint width, jint height, jint hotX, jint hotY)
332 {
333     if( 0 == pixels ) {
334         return 0;
335     }
336     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
337     unsigned char * pixelPtr = (unsigned char *) ( JNI_TRUE == pixels_is_direct ? 
338                                             (*env)->GetDirectBufferAddress(env, pixels) : 
339                                             (*env)->GetPrimitiveArrayCritical(env, pixels, NULL) );
340     NSImage * nsImage = createNSImageFromData(env, pixelPtr + pixels_byte_offset, width, height);
341     NSCursor * res = NULL;
342     if( NULL != nsImage ) {
343         [nsImage autorelease];
344         NSPoint hotP = { hotX, hotY };
345         res = [[NSCursor alloc] initWithImage: nsImage hotSpot: hotP];
346     }
347     if ( JNI_FALSE == pixels_is_direct ) {
348         (*env)->ReleasePrimitiveArrayCritical(env, pixels, (void*)pixelPtr, JNI_ABORT);  
349     }
350     [pool release];
351     DBG_PRINT( "createPointerIcon0 %p\n", res);
352     return (jlong) (intptr_t) res;
353 }
354
355 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_destroyPointerIcon0
356   (JNIEnv *env, jobject unused, jlong handle)
357 {
358     NSCursor * c = (NSCursor*) (intptr_t) handle ;
359     if( NULL != c && NO == [c isKindOfClass:[NSCursor class]] ) {
360         NewtCommon_throwNewRuntimeException(env, "Not a NSCursor %p", c);
361         return;
362     }
363     DBG_PRINT( "destroyPointerIcon0 %p\n", c);
364     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
365     [c release];
366     [pool release];
367 }
368
369 NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx, BOOL cap) {
370     NSArray *screens = [NSScreen screens];
371     if( screen_idx<0 || screen_idx>=[screens count] ) {
372         if( cap ) {
373             screen_idx=0;
374         } else {
375             return NULL;
376         }
377     }
378     return (NSScreen *) [screens objectAtIndex: screen_idx];
379 }
380
381 NSScreen * NewtScreen_getNSScreenByCoord(int x, int y) {
382     NSArray *screens = [NSScreen screens];
383     int i;
384     for(i=[screens count]-1; i>=0; i--) {
385         NSScreen * screen = (NSScreen *) [screens objectAtIndex: i];
386         NSRect frame = [screen frame];
387         if( x >= frame.origin.x && 
388             y >= frame.origin.y &&
389             x <  frame.origin.x + frame.size.width &&
390             y <  frame.origin.y + frame.size.height ) {
391             return screen;
392         }
393     }
394     return (NSScreen *) [screens objectAtIndex: 0];
395 }
396
397 static void NewtScreen_dump() {
398 #ifdef VERBOSE_ON
399     NSArray *screens = [NSScreen screens];
400     int i;
401     for(i=0; i<[screens count]; i++) {
402         NSScreen * screen = (NSScreen *) [screens objectAtIndex: i];
403         NSRect screenFrame = [screen frame];
404         NSRect screenVisibleFrame = [screen visibleFrame];
405         CGFloat pixelScale = 1.0; // default
406 NS_DURING
407         // Available >= 10.7
408         pixelScale = [screen backingScaleFactor]; // HiDPI scaling
409 NS_HANDLER
410 NS_ENDHANDLER
411         NSWindowDepth depth = [screen depth]; // an (int) value!
412         DBG_PRINT( "NSScreen #%d (%p): Frame %lf/%lf %lfx%lf (vis %lf/%lf %lfx%lf), scale %lf, depth %d\n",
413             i, screen,
414             screenFrame.origin.x, screenFrame.origin.y, screenFrame.size.width, screenFrame.size.height,
415             screenVisibleFrame.origin.x, screenVisibleFrame.origin.y, screenVisibleFrame.size.width, screenVisibleFrame.size.height,
416             pixelScale, depth);
417     }
418 #endif
419 }
420
421
422 CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen) {
423     // Mind: typedef uint32_t CGDirectDisplayID; - however, we assume it's 64bit on 64bit ?!
424     NSDictionary * dict = [screen deviceDescription];
425     NSNumber * val = (NSNumber *) [dict objectForKey: @"NSScreenNumber"];
426     // [NSNumber integerValue] returns NSInteger which is 32 or 64 bit native size
427     return (CGDirectDisplayID) [val integerValue];
428 }
429
430 /**
431  * Only in >= 10.6:
432  *   CGDisplayModeGetWidth(mode)
433  *   CGDisplayModeGetRefreshRate(mode)
434  *   CGDisplayModeGetHeight(mode)
435  */
436 static long GetDictionaryLong(CFDictionaryRef theDict, const void* key) 
437 {
438     long value = 0;
439     CFNumberRef numRef;
440     numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key); 
441     if (numRef != NULL)
442         CFNumberGetValue(numRef, kCFNumberLongType, &value);    
443     return value;
444 }
445 #define CGDDGetModeWidth(mode) GetDictionaryLong((mode), kCGDisplayWidth)
446 #define CGDDGetModeHeight(mode) GetDictionaryLong((mode), kCGDisplayHeight)
447 #define CGDDGetModeRefreshRate(mode) GetDictionaryLong((mode), kCGDisplayRefreshRate)
448 #define CGDDGetModeBitsPerPixel(mode) GetDictionaryLong((mode), kCGDisplayBitsPerPixel)
449
450 // Duplicate each Mode by all possible rotations (4):
451 // For each real-mode: [mode, 0], [mode, 90], [mode, 180], [mode, 270]
452 #define ROTMODES_PER_REALMODE 4
453
454 /*
455  * Class:     jogamp_newt_driver_macosx_ScreenDriver
456  * Method:    getMonitorCount0
457  * Signature: ()I
458  */
459 JNIEXPORT jint JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getMonitorCount0
460   (JNIEnv *env, jobject obj)
461 {
462     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
463     NSArray *screens = [NSScreen screens];
464     [pool release];
465     return (jint) [screens count];
466 }
467
468 /*
469  * Class:     jogamp_newt_driver_macosx_ScreenDriver
470  * Method:    getMonitorProps0
471  * Signature: (I)[I
472  */
473 JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getMonitorProps0
474   (JNIEnv *env, jobject obj, jint crt_idx)
475 {
476     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
477
478 #ifdef DBG_PERF
479     struct timespec t0, t1, td;
480     long td_ms;
481     timespec_now(&t0);
482 #endif
483
484 #ifdef DBG_PERF
485     timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td);
486     fprintf(stderr, "MacScreen_getMonitorProps0.1: %ld ms\n", td_ms); fflush(NULL);
487 #endif
488     NSScreen *screen = NewtScreen_getNSScreenByIndex((int)crt_idx, false);
489     if( NULL == screen ) {
490         [pool release];
491         return NULL;
492     }
493     CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen);
494 #ifdef DBG_PERF
495     timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td);
496     fprintf(stderr, "MacScreen_getMonitorProps0.2: %ld ms\n", td_ms); fflush(NULL);
497 #endif
498
499     CGSize sizeMM = CGDisplayScreenSize(display);
500 #ifdef DBG_PERF
501     timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td);
502     fprintf(stderr, "MacScreen_getMonitorProps0.3: %ld ms\n", td_ms); fflush(NULL);
503 #endif
504
505     CGRect dBounds = CGDisplayBounds (display); // origin top-left
506 #ifdef VERBOSE_ON
507     BOOL usesGL = CGDisplayUsesOpenGLAcceleration(display);
508     NSRect sFrame = [screen frame]; // origin bottom-left
509     DBG_PRINT( "getMonitorProps0: scrn %d, top-left displayBounds[%d/%d %dx%d], bottom-left screenFrame[%d/%d %dx%d], usesGL %d\n", (int)crt_idx, 
510                  (int)dBounds.origin.x, (int)dBounds.origin.y, (int)dBounds.size.width, (int)dBounds.size.height,
511                  (int)sFrame.origin.x, (int)sFrame.origin.y, (int)sFrame.size.width, (int)sFrame.size.height,
512                  (int)usesGL);
513 #endif
514
515     jsize propCount = MIN_MONITOR_DEVICE_PROPERTIES - 1 - NUM_MONITOR_MODE_PROPERTIES;
516     jint prop[ propCount ];
517     int offset = 0;
518     prop[offset++] = propCount;
519     prop[offset++] = crt_idx;
520     prop[offset++] = (jint) sizeMM.width;
521     prop[offset++] = (jint) sizeMM.height;
522     prop[offset++] = (jint) dBounds.origin.x;    // rotated viewport x      (pixel units, will be fixed in java code)
523     prop[offset++] = (jint) dBounds.origin.y;    // rotated viewport y      (pixel units, will be fixed in java code)
524     prop[offset++] = (jint) dBounds.size.width;  // rotated viewport width  (pixel units, will be fixed in java code)
525     prop[offset++] = (jint) dBounds.size.height; // rotated viewport height (pixel units, will be fixed in java code)
526     prop[offset++] = (jint) dBounds.origin.x;    // rotated viewport x      (window units, will be fixed in java code)
527     prop[offset++] = (jint) dBounds.origin.y;    // rotated viewport y      (window units, will be fixed in java code)
528     prop[offset++] = (jint) dBounds.size.width;  // rotated viewport width  (window units, will be fixed in java code)
529     prop[offset++] = (jint) dBounds.size.height; // rotated viewport height (window units, will be fixed in java code)
530
531     jintArray properties = (*env)->NewIntArray(env, propCount);
532     if (properties == NULL) {
533         NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", propCount);
534     }
535     (*env)->SetIntArrayRegion(env, properties, 0, propCount, prop);
536     
537     [pool release];
538
539     return properties;
540 }
541
542 /*
543  * Class:     jogamp_newt_driver_macosx_ScreenDriver
544  * Method:    getMonitorMode0
545  * Signature: (II)[I
546  */
547 JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getMonitorMode0
548   (JNIEnv *env, jobject obj, jint crt_idx, jint mode_idx)
549 {
550     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
551
552     NSScreen *screen = NewtScreen_getNSScreenByIndex((int)crt_idx, false);
553     if( NULL == screen ) {
554         [pool release];
555         return NULL;
556     }
557     CGFloat pixelScale = 1.0; // default
558 NS_DURING
559     // Available >= 10.7
560     pixelScale = [screen backingScaleFactor]; // HiDPI scaling
561 NS_HANDLER
562 NS_ENDHANDLER
563
564     CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen);
565
566     CFArrayRef availableModes = CGDisplayAvailableModes(display);
567     CFIndex numberOfAvailableModes = CFArrayGetCount(availableModes);
568     CFIndex numberOfAvailableModesRots = ROTMODES_PER_REALMODE * numberOfAvailableModes; 
569     CFDictionaryRef mode = NULL;
570     int currentCCWRot = (int)CGDisplayRotation(display);
571     jint ccwRot = 0;
572     int nativeId = 0;
573
574 #ifdef VERBOSE_ON
575     if(0 >= mode_idx) {
576         // only for current mode (-1) and first mode (scanning)
577         DBG_PRINT( "getScreenMode0: scrn %d (s %p, d %p, pscale %lf), mode %d, avail: %d/%d, current rot %d ccw\n",  
578             (int)crt_idx, screen, (void*)(intptr_t)display, pixelScale, (int)mode_idx, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots, currentCCWRot);
579     }
580 #endif
581
582     if(numberOfAvailableModesRots<=mode_idx) {
583         // n/a - end of modes
584         DBG_PRINT( "getScreenMode0: end of modes: mode %d, avail: %d/%d\n",
585             (int)mode_idx, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots);
586         [pool release];
587         return NULL;
588     } else if(-1 < mode_idx) {
589         // only at initialization time, where index >= 0
590         nativeId = mode_idx / ROTMODES_PER_REALMODE;
591         ccwRot = mode_idx % ROTMODES_PER_REALMODE * 90;
592         mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, nativeId);
593     } else {
594         // current mode
595         mode = CGDisplayCurrentMode(display);
596         ccwRot = currentCCWRot;
597         CFRange range = CFRangeMake (0, numberOfAvailableModes);
598         nativeId = CFArrayGetFirstIndexOfValue(availableModes, range, (CFDictionaryRef)mode);
599     }
600     // mode = CGDisplayModeRetain(mode); // 10.6 on CGDisplayModeRef
601
602     int mWidth = CGDDGetModeWidth(mode);
603     int mHeight = CGDDGetModeHeight(mode);
604     if( -1 == mode_idx ) {
605         mWidth *= (int)pixelScale;   // accomodate HiDPI
606         mHeight *= (int)pixelScale; // accomodate HiDPI
607     }
608
609     // swap width and height, since OSX reflects rotated dimension, we don't
610     if ( 90 == currentCCWRot || 270 == currentCCWRot ) {
611         int tempWidth = mWidth;
612         mWidth = mHeight;
613         mHeight = tempWidth;
614     }
615
616     jint prop[ NUM_MONITOR_MODE_PROPERTIES_ALL ];
617     int propIndex = 0;
618
619     int refreshRate = CGDDGetModeRefreshRate(mode);
620     int fRefreshRate = ( 0 < refreshRate ) ? refreshRate : 60; // default .. (experienced on OSX 10.6.8)
621     prop[propIndex++] = NUM_MONITOR_MODE_PROPERTIES_ALL;
622     prop[propIndex++] = mWidth;
623     prop[propIndex++] = mHeight;
624     prop[propIndex++] = CGDDGetModeBitsPerPixel(mode);
625     prop[propIndex++] = fRefreshRate * 100; // Hz*100
626     prop[propIndex++] = 0; // flags
627     prop[propIndex++] = nativeId;
628     prop[propIndex++] = ccwRot;
629  
630     DBG_PRINT( "getScreenMode0: Mode %d/%d (%d): %dx%d, %d bpp, %d / %d Hz, nativeId %d, rot %d ccw\n",
631         (int)mode_idx, (int)numberOfAvailableModesRots, (int)numberOfAvailableModes, 
632         (int)prop[1], (int)prop[2], (int)prop[3],
633         (int)prop[4], refreshRate, (int)prop[6], (int)prop[7]);
634
635     jintArray properties = (*env)->NewIntArray(env, NUM_MONITOR_MODE_PROPERTIES_ALL);
636     if (properties == NULL) {
637         NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", NUM_MONITOR_MODE_PROPERTIES_ALL);
638     }
639     (*env)->SetIntArrayRegion(env, properties, 0, NUM_MONITOR_MODE_PROPERTIES_ALL, prop);
640     
641     // CGDisplayModeRelease(mode); // 10.6 on CGDisplayModeRef
642     [pool release];
643
644     return properties;
645 }
646
647 /*
648  * Class:     jogamp_newt_driver_macosx_ScreenDriver
649  * Method:    setMonitorMode0
650  * Signature: (III)Z
651  */
652 JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_setMonitorMode0
653   (JNIEnv *env, jobject object, jint crt_idx, jint nativeId, jint ccwRot)
654 {
655     jboolean res = JNI_TRUE;
656     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
657
658     NSScreen *screen = NewtScreen_getNSScreenByIndex((int)crt_idx, false);
659     if( NULL == screen ) {
660         [pool release];
661         return JNI_FALSE;
662     }
663     CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen);
664
665     CFArrayRef availableModes = CGDisplayAvailableModes(display);
666     CFIndex numberOfAvailableModes = CFArrayGetCount(availableModes);
667 #ifdef VERBOSE_ON
668     CFIndex numberOfAvailableModesRots = ROTMODES_PER_REALMODE * numberOfAvailableModes;
669 #endif
670
671     DBG_PRINT( "setScreenMode0: scrn %d (%p, %p), nativeID %d, rot %d ccw, avail: %d/%d\n",  
672         (int)crt_idx, screen, (void*)(intptr_t)display, (int)nativeId, ccwRot, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots);
673
674     CFDictionaryRef mode = NULL;
675
676     if( 0 != ccwRot ) {
677         // FIXME: How to rotate the display/screen on OSX programmatically ?
678         DBG_PRINT( "setScreenMode0: Don't know how to rotate screen on OS X: rot %d ccw\n", ccwRot);
679         res = JNI_FALSE;
680     } else {
681         if( numberOfAvailableModes <= nativeId ) {
682             res = JNI_FALSE;
683         } else {
684             mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, nativeId);
685             // mode = CGDisplayModeRetain(mode); // 10.6 on CGDisplayModeRef
686         }
687     }
688
689     if( NULL != mode ) {
690         CGError err = CGDisplaySwitchToMode(display, mode);
691         if(kCGErrorSuccess != err) {
692             DBG_PRINT( "setScreenMode0: SetMode failed: %d\n", (int)err);
693             res = JNI_FALSE;
694         }
695     }
696
697     // CGDisplayModeRelease(mode); // 10.6 on CGDisplayModeRef
698     [pool release];
699
700     return res;
701 }
702
703 /*
704  * Class:     jogamp_newt_driver_macosx_WindowDriver
705  * Method:    initIDs
706  * Signature: ()Z
707  */
708 JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_initIDs0
709   (JNIEnv *env, jclass clazz)
710 {
711     static int initialized = 0;
712
713     if(initialized) return JNI_TRUE;
714     initialized = 1;
715
716     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
717
718     NewtScreen_dump();
719
720     jclass c;
721     c = (*env)->FindClass(env, ClazzNamePoint);
722     if(NULL==c) {
723         NewtCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_WindowDriver_initIDs0: can't find %s", ClazzNamePoint);
724     }
725     pointClz = (jclass)(*env)->NewGlobalRef(env, c);
726     (*env)->DeleteLocalRef(env, c);
727     if(NULL==pointClz) {
728         NewtCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_WindowDriver_initIDs0: can't use %s", ClazzNamePoint);
729     }
730     pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature);
731     if(NULL==pointCstr) {
732         NewtCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_WindowDriver_initIDs0: can't fetch %s.%s %s",
733             ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature);
734     }
735
736     // Need this when debugging, as it is necessary to attach gdb to
737     // the running java process -- "gdb java" doesn't work
738     //    printf("Going to sleep for 10 seconds\n");
739     //    sleep(10);
740
741     BOOL res =  [NewtMacWindow initNatives: env forClass: clazz];
742     [pool release];
743
744     return (jboolean) res;
745 }
746
747 /**
748  * Class:     jogamp_newt_driver_macosx_WindowDriver
749  * Method:    createView0
750  * Signature: (IIIIZ)J
751  */
752 JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_createView0
753   (JNIEnv *env, jobject jthis, jint x, jint y, jint w, jint h, 
754    jboolean fullscreen)
755 {
756     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
757
758     DBG_PRINT( "createView0 - %p (this), %d/%d %dx%d, fs %d (START)\n",
759         (void*)(intptr_t)jthis, (int)x, (int)y, (int)w, (int)h, (int)fullscreen);
760
761     NSRect rectView = NSMakeRect(0, 0, w, h);
762     NewtView *myView = [[NewtView alloc] initWithFrame: rectView] ;
763 NS_DURING
764     // Available >= 10.7
765     [myView setWantsBestResolutionOpenGLSurface: YES]; // HiDPI scaling: Always desired
766 NS_HANDLER
767 NS_ENDHANDLER
768     DBG_PRINT( "createView0.X - new view: %p\n", myView);
769
770     [pool release];
771
772     return (jlong) (intptr_t) myView;
773 }
774
775 /**
776  * Method creates a deferred un-initialized Window, hence no special invocation required inside method.
777  *
778  * Class:     jogamp_newt_driver_macosx_WindowDriver
779  * Method:    createWindow0
780  * Signature: (IIIIZIIJ)J
781  */
782 JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_createWindow0
783   (JNIEnv *env, jobject jthis, jint x, jint y, jint w, jint h, 
784    jboolean fullscreen, jint styleMask, jint bufferingType, jlong jview)
785 {
786     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
787     NewtView* myView = (NewtView*) (intptr_t) jview ;
788
789     DBG_PRINT( "createWindow0 - %p (this), %d/%d %dx%d, fs %d, style %X, buffType %X, view %p (START)\n",
790         (void*)(intptr_t)jthis, (int)x, (int)y, (int)w, (int)h, (int)fullscreen, 
791         (int)styleMask, (int)bufferingType, myView);
792     (void)myView;
793
794     if (fullscreen) {
795         styleMask = NSBorderlessWindowMask;
796     }
797     NSRect rectWin = NSMakeRect(x, y, w, h);
798
799     // Allocate the window
800     NewtMacWindow* myWindow = [[NewtMacWindow alloc] initWithContentRect: rectWin
801                                                styleMask: (NSUInteger) styleMask
802                                                backing: (NSBackingStoreType) bufferingType
803                                                defer: YES
804                                                isFullscreenWindow: fullscreen];
805     // DBG_PRINT( "createWindow0.1 - %p, isVisible %d\n", myWindow, [myWindow isVisible]);
806
807     DBG_PRINT( "createWindow0.X - %p, isVisible %d\n", myWindow, [myWindow isVisible]);
808
809     [pool release];
810
811     return (jlong) ((intptr_t) myWindow);
812 }
813
814 /**
815  * Method is called on Main-Thread, hence no special invocation required inside method.
816  *
817  * Class:     jogamp_newt_driver_macosx_WindowDriver
818  * Method:    initWindow0
819  * Signature: (JJIIIIZZZJ)V
820  */
821 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_initWindow0
822   (JNIEnv *env, jobject jthis, jlong parent, jlong window, jint x, jint y, jint w, jint h,
823    jboolean opaque, jboolean visible, jlong jview)
824 {
825     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
826     NewtMacWindow* myWindow = (NewtMacWindow*) ((intptr_t) window);
827     NewtView* myView = (NewtView*) (intptr_t) jview ;
828     BOOL fullscreen = myWindow->isFullscreenWindow;
829
830     DBG_PRINT( "initWindow0 - %p (this), %p (parent), %p (window), %d/%d %dx%d, opaque %d, fs %d, visible %d, view %p (START)\n",
831         (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, (int)x, (int)y, (int)w, (int)h, 
832         (int) opaque, (int)fullscreen, (int)visible, myView);
833
834     [myWindow setReleasedWhenClosed: NO]; // We control NSWindow destruction!
835     [myWindow setPreservesContentDuringLiveResize: NO];
836 NS_DURING
837         if ( [myWindow respondsToSelector:@selector(setRestorable:)] ) {
838             // Available >= 10.7 - Removes restauration 'feature', really close
839             [myWindow setRestorable: NO];
840         }
841 NS_HANDLER
842 NS_ENDHANDLER
843
844     NSObject* nsParentObj = (NSObject*) ((intptr_t) parent);
845     NSWindow* parentWindow = NULL;
846     NSView* parentView = NULL;
847     if( nsParentObj != NULL && [nsParentObj isKindOfClass:[NSWindow class]] ) {
848         parentWindow = (NSWindow*) nsParentObj;
849         parentView = [parentWindow contentView];
850         DBG_PRINT( "initWindow0 - Parent is NSWindow : %p (win) -> %p (view) \n", parentWindow, parentView);
851     } else if( nsParentObj != NULL && [nsParentObj isKindOfClass:[NSView class]] ) {
852         parentView = (NSView*) nsParentObj;
853         parentWindow = [parentView window];
854         DBG_PRINT( "initWindow0 - Parent is NSView : %p -(view) > %p (win) \n", parentView, parentWindow);
855     } else {
856         DBG_PRINT( "initWindow0 - Parent is neither NSWindow nor NSView : %p\n", nsParentObj);
857     }
858     DBG_PRINT( "initWindow0 - is visible.1: %d\n", [myWindow isVisible]);
859
860     // Remove animations for child windows
861     if(NULL != parentWindow) {
862 NS_DURING
863         if ( [myWindow respondsToSelector:@selector(setAnimationBehavior:)] ) {
864             // Available >= 10.7 - Removes default animations
865             [myWindow setAnimationBehavior: NSWindowAnimationBehaviorNone];
866         }
867 NS_HANDLER
868 NS_ENDHANDLER
869     }
870
871 #ifdef VERBOSE_ON
872     int dbgIdx = 1;
873 #endif
874     if(opaque) {
875         [myWindow setOpaque: YES];
876         DBG_PRINT( "initWindow0.%d\n", dbgIdx++);
877         if (!fullscreen) {
878             [myWindow setShowsResizeIndicator: YES];
879         }
880         DBG_PRINT( "initWindow0.%d\n", dbgIdx++);
881     } else {
882         [myWindow setOpaque: NO];
883         [myWindow setBackgroundColor: [NSColor clearColor]];
884     }
885
886     // specify we want mouse-moved events
887     [myWindow setAcceptsMouseMovedEvents:YES];
888
889     DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", 
890         dbgIdx++, myWindow, myView, [myWindow isVisible]);
891
892     // Set the content view
893     changeContentView(env, jthis, parentView, myWindow, myView, NO);
894     [myWindow setInitialFirstResponder: myView];
895
896     DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", 
897         dbgIdx++, myWindow, myView, [myWindow isVisible]);
898
899     if(NULL!=parentWindow) {
900         [myWindow attachToParent: parentWindow];
901     }
902
903     DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d, visible %d\n", 
904         dbgIdx++, myWindow, myView, [myWindow isVisible], visible);
905
906     // Immediately re-position this window based on an upper-left coordinate system
907     setWindowClientTopLeftPointAndSize(myWindow, x, y, w, h, NO);
908
909     DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", 
910         dbgIdx++, myWindow, myView, [myWindow isVisible]);
911
912 NS_DURING
913     // concurrent view rendering
914     // Available >= 10.6 - Makes the menubar disapear
915     if ( [myWindow respondsToSelector:@selector(setAllowsConcurrentViewDrawing:)] ) {
916         [myWindow setAllowsConcurrentViewDrawing: YES];
917     }
918
919     DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", 
920         dbgIdx++, myWindow, myView, [myWindow isVisible]);
921
922     if ( [myView respondsToSelector:@selector(setCanDrawConcurrently:)] ) {
923         [myView setCanDrawConcurrently: YES];
924     }
925 NS_HANDLER
926 NS_ENDHANDLER
927
928     DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", 
929         dbgIdx++, myWindow, myView, [myWindow isVisible]);
930
931     // visible on front
932     if( visible ) {
933         [myWindow orderFront: myWindow];
934     }
935
936     DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", 
937         dbgIdx++, myWindow, myView, [myWindow isVisible]);
938
939     // force surface creation
940     // [myView lockFocus];
941     // [myView unlockFocus];
942
943     // Set the next responder to be the window so that we can forward
944     // right mouse button down events
945     [myView setNextResponder: myWindow];
946
947     DBG_PRINT( "initWindow0.%d - %p (this), %p (parent): new window: %p, view %p\n",
948         dbgIdx++, (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, myView);
949
950     [myView setDestroyNotifySent: false];
951     setJavaWindowObject(env, jthis, myView, YES);
952
953     DBG_PRINT( "initWindow0.%d - %p (this), %p (parent): new window: %p, view %p\n",
954         dbgIdx++, (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, myView);
955
956 NS_DURING
957     if( fullscreen ) {
958         /** 
959          * See Bug 914: We don't use exclusive fullscreen anymore (capturing display)
960          * allowing ALT-TAB to allow process/app switching!
961          * Shall have no penalty on modern GPU and is also recommended, see bottom box @
962          * <https://developer.apple.com/library/mac/documentation/graphicsimaging/Conceptual/QuartzDisplayServicesConceptual/Articles/DisplayCapture.html>
963          *
964         NSScreen *myScreen =  NewtScreen_getNSScreenByCoord(x, y);
965         if ( [myView respondsToSelector:@selector(enterFullScreenMode:withOptions:)] ) {
966             // Available >= 10.5 - Makes the menubar disapear
967             [myView enterFullScreenMode: myScreen withOptions:NULL];
968         } */
969         if( myWindow->hasPresentationSwitch ) {
970             DBG_PRINT( "initWindow0.%d - %p view %p, setPresentationOptions 0x%X\n", 
971                 dbgIdx++, myWindow, myView, (int)myWindow->fullscreenPresentationOptions);
972             [NSApp setPresentationOptions: myWindow->fullscreenPresentationOptions];
973         }
974     }
975 NS_HANDLER
976 NS_ENDHANDLER
977
978     DBG_PRINT( "initWindow0.%d - %p (this), %p (parent): new window: %p, view %p\n",
979         dbgIdx++, (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, myView);
980
981     [pool release];
982     DBG_PRINT( "initWindow0.X - %p (this), %p (parent): new window: %p, view %p\n",
983         (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, myView);
984 }
985
986 /**
987  * Method is called on Main-Thread, hence no special invocation required inside method.
988  *
989  * Class:     jogamp_newt_driver_macosx_WindowDriver
990  * Method:    close0
991  * Signature: (J)V
992  */
993 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_close0
994   (JNIEnv *env, jobject unused, jlong window)
995 {
996     NewtMacWindow* mWin = (NewtMacWindow*) ((intptr_t) window);
997     if( NULL == mWin ) {
998         DBG_PRINT( "windowClose.0 - NULL NEWT win - abort\n");
999         return;
1000     }
1001     BOOL isNSWin = [mWin isKindOfClass:[NSWindow class]];
1002     BOOL isNewtWin = [mWin isKindOfClass:[NewtMacWindow class]];
1003     NSWindow *pWin = [mWin parentWindow];
1004     DBG_PRINT( "windowClose.0 - %p [isNSWindow %d, isNewtWin %d], parent %p\n", mWin, isNSWin, isNewtWin, pWin);
1005     (void)isNSWin; // silence
1006     if( !isNewtWin ) {
1007         NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin);
1008         return;
1009     }
1010     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1011     NewtView* mView = (NewtView *)[mWin contentView];
1012     BOOL fullscreen = mWin->isFullscreenWindow;
1013     BOOL destroyNotifySent, isNSView, isNewtView;
1014     if( NULL != mView ) {
1015         isNSView = [mView isKindOfClass:[NSView class]];
1016         isNewtView = [mView isKindOfClass:[NewtView class]];
1017         destroyNotifySent = isNewtView ? [mView getDestroyNotifySent] : false;
1018     } else {
1019         isNSView = false;
1020         isNewtView = false;
1021         destroyNotifySent = false;
1022     }
1023
1024     DBG_PRINT( "windowClose.0 - %p, destroyNotifySent %d, view %p [isNSView %d, isNewtView %d], fullscreen %d, parent %p\n", 
1025         mWin, destroyNotifySent, mView, isNSView, isNewtView, (int)fullscreen, pWin);
1026
1027     [mWin setRealized: NO];
1028
1029     if( isNewtView ) {
1030         // cleanup view
1031         [mView setDestroyNotifySent: true];
1032         setJavaWindowObject(env, NULL, mView, NO);
1033     }
1034
1035 NS_DURING
1036     /** 
1037      * See Bug 914: We don't use exclusive fullscreen anymore (capturing display)
1038      * See initWindow0(..) above ..
1039     if(NULL!=mView) {
1040         BOOL iifs;
1041         if ( [mView respondsToSelector:@selector(isInFullScreenMode)] ) {
1042             iifs = [mView isInFullScreenMode];
1043         } else {
1044             iifs = NO;
1045         }
1046         if(iifs && [mView respondsToSelector:@selector(exitFullScreenModeWithOptions:)] ) {
1047             [mView exitFullScreenModeWithOptions: NULL];
1048         }
1049     } */
1050     // Note: mWin's release will also release it's mView!
1051     DBG_PRINT( "windowClose.1a - %p view %p, fullscreen %d, hasPresSwitch %d, defaultPresentationOptions 0x%X\n", 
1052         mWin, mView, (int)fullscreen, (int)mWin->hasPresentationSwitch, (int)mWin->defaultPresentationOptions);
1053
1054     if( fullscreen && mWin->hasPresentationSwitch ) {
1055         DBG_PRINT( "windowClose.1b - %p view %p, setPresentationOptions 0x%X\n", 
1056             mWin, mView, (int)mWin->defaultPresentationOptions);
1057         [NSApp setPresentationOptions: mWin->defaultPresentationOptions];
1058     }
1059 NS_HANDLER
1060 NS_ENDHANDLER
1061
1062     if(NULL!=pWin) {
1063         [mWin detachFromParent: pWin];
1064     }
1065     [mWin orderOut: mWin];
1066
1067     DBG_PRINT( "windowClose.2 - %p view %p, parent %p\n", mWin, mView, pWin);
1068
1069     [mWin release];
1070
1071     DBG_PRINT( "windowClose.Xp\n");
1072
1073     [pool release];
1074 }
1075
1076 /*
1077  * Class:     Java_jogamp_newt_driver_macosx_WindowDriver
1078  * Method:    lockSurface0
1079  * Signature: (JJ)Z
1080  */
1081 JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_lockSurface0
1082   (JNIEnv *env, jclass clazz, jlong window, jlong view)
1083 {
1084     NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window);
1085     if(NO == [mWin isRealized]) {
1086         return JNI_FALSE;
1087     }
1088     NewtView * mView = (NewtView *) ((intptr_t) view);
1089     return [mView softLock] == YES ? JNI_TRUE : JNI_FALSE;
1090     /** deadlocks, since we render independent of focus
1091     return [mView lockFocusIfCanDraw] == YES ? JNI_TRUE : JNI_FALSE; */
1092 }
1093
1094 /*
1095  * Class:     Java_jogamp_newt_driver_macosx_WindowDriver
1096  * Method:    unlockSurface0
1097  * Signature: (JJ)Z
1098  */
1099 JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_unlockSurface0
1100   (JNIEnv *env, jclass clazz, jlong window, jlong view)
1101 {
1102     // NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window);
1103     (void) window;
1104     NewtView * mView = (NewtView *) ((intptr_t) view);
1105     return [mView softUnlock] == YES ? JNI_TRUE : JNI_FALSE;
1106     /** deadlocks, since we render independent of focus
1107     [mView unlockFocus]; */
1108 }
1109
1110 /*
1111  * Class:     jogamp_newt_driver_macosx_WindowDriver
1112  * Method:    requestFocus0
1113  * Signature: (JZ)V
1114  */
1115 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_requestFocus0
1116   (JNIEnv *env, jobject window, jlong w, jboolean force)
1117 {
1118     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1119     NSWindow* mWin = (NSWindow*) ((intptr_t) w);
1120 #ifdef VERBOSE_ON
1121     BOOL hasFocus = [mWin isKeyWindow];
1122 #endif
1123     DBG_PRINT( "requestFocus - window: %p, force %d, hasFocus %d (START)\n", mWin, force, hasFocus);
1124
1125     [mWin setAcceptsMouseMovedEvents: YES];
1126     [mWin makeFirstResponder: nil];
1127     [mWin orderFrontRegardless];
1128     [mWin makeKeyWindow];
1129
1130     DBG_PRINT( "requestFocus - window: %p, force %d (END)\n", mWin, force);
1131
1132     [pool release];
1133 }
1134
1135 /*
1136  * Class:     jogamp_newt_driver_macosx_WindowDriver
1137  * Method:    resignFocus0
1138  * Signature: (J)V
1139  */
1140 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_resignFocus0
1141   (JNIEnv *env, jobject window, jlong w)
1142 {
1143     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1144     NSWindow* mWin = (NSWindow*) ((intptr_t) w);
1145     NSWindow* pWin = [mWin parentWindow];
1146     BOOL hasFocus = [mWin isKeyWindow];
1147
1148     DBG_PRINT( "requestFocusParent0 - window: %p, parent %p, hasFocus %d (START)\n", mWin, pWin, hasFocus );
1149     if( hasFocus ) {
1150         if(NULL != pWin) {
1151             // [mWin makeFirstResponder: pWin];
1152             [pWin makeKeyWindow];
1153         } else {
1154             [pWin resignKeyWindow];
1155         }
1156     }
1157     DBG_PRINT( "requestFocusParent0 - window: %p (END)\n", mWin);
1158
1159     [pool release];
1160 }
1161
1162 /*
1163  * Class:     jogamp_newt_driver_macosx_WindowDriver
1164  * Method:    orderFront0
1165  * Signature: (J)V
1166  */
1167 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_orderFront0
1168   (JNIEnv *env, jobject unused, jlong window)
1169 {
1170     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1171     NSWindow* mWin = (NSWindow*) ((intptr_t) window);
1172     NSWindow* pWin = [mWin parentWindow];
1173
1174     DBG_PRINT( "orderFront0 - window: (parent %p) %p visible %d (START)\n", pWin, mWin, [mWin isVisible]);
1175
1176     if( NULL == pWin ) {
1177         [mWin orderFrontRegardless];
1178     } else {
1179         [mWin orderWindow: NSWindowAbove relativeTo: [pWin windowNumber]];
1180     }
1181
1182     DBG_PRINT( "orderFront0 - window: (parent %p) %p (END)\n", pWin, mWin);
1183
1184     [pool release];
1185 }
1186
1187 /*
1188  * Class:     jogamp_newt_driver_macosx_WindowDriver
1189  * Method:    orderOut
1190  * Signature: (J)V
1191  */
1192 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_orderOut0
1193   (JNIEnv *env, jobject unused, jlong window)
1194 {
1195     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1196     NSWindow* mWin = (NSWindow*) ((intptr_t) window);
1197     NSWindow* pWin = [mWin parentWindow];
1198
1199     DBG_PRINT( "orderOut0 - window: (parent %p) %p visible %d (START)\n", pWin, mWin, [mWin isVisible]);
1200
1201     if( NULL == pWin ) {
1202         [mWin orderOut: mWin];
1203     } else {
1204         [mWin orderWindow: NSWindowOut relativeTo: [pWin windowNumber]];
1205     }
1206
1207     DBG_PRINT( "orderOut0 - window: (parent %p) %p (END)\n", pWin, mWin);
1208
1209     [pool release];
1210 }
1211
1212 /*
1213  * Class:     jogamp_newt_driver_macosx_WindowDriver
1214  * Method:    setTitle0
1215  * Signature: (JLjava/lang/String;)V
1216  */
1217 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setTitle0
1218   (JNIEnv *env, jobject unused, jlong window, jstring title)
1219 {
1220     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1221     NSWindow* win = (NSWindow*) ((intptr_t) window);
1222
1223     DBG_PRINT( "setTitle0 - window: %p (START)\n", win);
1224
1225     NSString* str = jstringToNSString(env, title);
1226     [str autorelease];
1227     [win setTitle: str];
1228
1229     DBG_PRINT( "setTitle0 - window: %p (END)\n", win);
1230
1231     [pool release];
1232 }
1233
1234 /*
1235  * Class:     jogamp_newt_driver_macosx_WindowDriver
1236  * Method:    contentView0
1237  * Signature: (J)J
1238  */
1239 JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_contentView0
1240   (JNIEnv *env, jobject unused, jlong window)
1241 {
1242     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1243     NSWindow* win = (NSWindow*) ((intptr_t) window);
1244     NSView* nsView = [win contentView];
1245     NewtView* newtView = NULL;
1246
1247     if( [nsView isKindOfClass:[NewtView class]] ) {
1248         newtView = (NewtView *) nsView;
1249     }
1250
1251     DBG_PRINT( "contentView0 - window: %p, view: %p, newtView %p\n", win, nsView, newtView);
1252
1253     jlong res = (jlong) ((intptr_t) nsView);
1254
1255     [pool release];
1256     return res;
1257 }
1258
1259 /**
1260  * Method is called on Main-Thread, hence no special invocation required inside method.
1261  *
1262  * Class:     jogamp_newt_driver_macosx_WindowDriver
1263  * Method:    changeContentView
1264  * Signature: (J)V
1265  */
1266 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_changeContentView0
1267   (JNIEnv *env, jobject jthis, jlong parentWindowOrView, jlong window, jlong jview)
1268 {
1269     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1270
1271     NewtView* newView = (NewtView *) ((intptr_t) jview);
1272     NewtMacWindow* win = (NewtMacWindow*) ((intptr_t) window);
1273
1274     DBG_PRINT( "changeContentView0.0 -  win %p, view (%p,%d)\n", 
1275         win, newView, getRetainCount(newView));
1276
1277     NSObject *nsParentObj = (NSObject*) ((intptr_t) parentWindowOrView);
1278     NSView* pView = NULL;
1279     if( NULL != nsParentObj ) {
1280         if( [nsParentObj isKindOfClass:[NSWindow class]] ) {
1281             NSWindow * pWin = (NSWindow*) nsParentObj;
1282             pView = [pWin contentView];
1283         } else if( [nsParentObj isKindOfClass:[NSView class]] ) {
1284             pView = (NSView*) nsParentObj;
1285         }
1286     }
1287
1288     changeContentView(env, jthis, pView, win, newView, YES);
1289
1290     DBG_PRINT( "changeContentView0.X\n");
1291
1292     [pool release];
1293 }
1294
1295 /*
1296  * Class:     jogamp_newt_driver_macosx_WindowDriver
1297  * Method:    setWindowClientTopLeftPointAndSize0
1298  * Signature: (JIIIIZ)V
1299  */
1300 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setWindowClientTopLeftPointAndSize0
1301   (JNIEnv *env, jobject unused, jlong window, jint x, jint y, jint w, jint h, jboolean display)
1302 {
1303     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1304     NewtMacWindow* mWin = (NewtMacWindow*) ((intptr_t) window);
1305
1306     DBG_PRINT( "setWindowClientTopLeftPointAndSize - window: %p (START)\n", mWin);
1307
1308     setWindowClientTopLeftPointAndSize(mWin, x, y, w, h, display);
1309
1310     DBG_PRINT( "setWindowClientTopLeftPointAndSize - window: %p (END)\n", mWin);
1311
1312     [pool release];
1313 }
1314
1315 /*
1316  * Class:     jogamp_newt_driver_macosx_WindowDriver
1317  * Method:    setWindowClientTopLeftPoint0
1318  * Signature: (JIIZ)V
1319  */
1320 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setWindowClientTopLeftPoint0
1321   (JNIEnv *env, jobject unused, jlong window, jint x, jint y, jboolean display)
1322 {
1323     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1324     NewtMacWindow* mWin = (NewtMacWindow*) ((intptr_t) window);
1325
1326     DBG_PRINT( "setWindowClientTopLeftPoint - window: %p (START)\n", mWin);
1327
1328     setWindowClientTopLeftPoint(mWin, x, y, display);
1329
1330     DBG_PRINT( "setWindowClientTopLeftPoint - window: %p (END)\n", mWin);
1331
1332     [pool release];
1333 }
1334
1335 /*
1336  * Class:     jogamp_newt_driver_macosx_WindowDriver
1337  * Method:    setAlwaysOnTop0
1338  * Signature: (JZ)V
1339  */
1340 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setAlwaysOnTop0
1341   (JNIEnv *env, jobject unused, jlong window, jboolean atop)
1342 {
1343     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1344     NSWindow* win = (NSWindow*) ((intptr_t) window);
1345
1346     DBG_PRINT( "setAlwaysOnTop0 - window: %p, atop %d (START)\n", win, (int)atop);
1347
1348     if(atop) {
1349         [win setLevel:NSFloatingWindowLevel];
1350     } else {
1351         [win setLevel:NSNormalWindowLevel];
1352     }
1353
1354     DBG_PRINT( "setAlwaysOnTop0 - window: %p, atop %d (END)\n", win, (int)atop);
1355
1356     [pool release];
1357 }
1358
1359 /*
1360  * Class:     jogamp_newt_driver_macosx_WindowDriver
1361  * Method:    getLocationOnScreen0
1362  * Signature: (JII)Ljavax/media/nativewindow/util/Point;
1363  */
1364 JNIEXPORT jobject JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_getLocationOnScreen0
1365   (JNIEnv *env, jclass unused, jlong win, jint src_x, jint src_y)
1366 {
1367     NewtMacWindow *mWin = (NewtMacWindow*) (intptr_t) win;
1368     if( ![mWin isKindOfClass:[NewtMacWindow class]] ) {
1369         NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin);
1370         return NULL;
1371     }
1372     NSPoint p0 = [mWin getLocationOnScreen: NSMakePoint(src_x, src_y)];
1373     return (*env)->NewObject(env, pointClz, pointCstr, (jint)p0.x, (jint)p0.y);
1374 }
1375
1376 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setPointerIcon0
1377   (JNIEnv *env, jobject unused, jlong window, jlong handle)
1378 {
1379     NSCursor *c = (NSCursor*) (intptr_t) handle ;
1380     if ( NULL != c && NO == [c isKindOfClass:[NSCursor class]] ) {
1381         NewtCommon_throwNewRuntimeException(env, "Not a NSCursor %p", c);
1382         return;
1383     }
1384     NewtMacWindow *mWin = (NewtMacWindow*) (intptr_t) window;
1385     if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) {
1386         NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin);
1387         return;
1388     }
1389     NewtView* nView = (NewtView *) [mWin contentView];
1390     if( ! [nView isKindOfClass:[NewtView class]] ) {
1391         NewtCommon_throwNewRuntimeException(env, "Not a NewtView %p", nView);
1392         return;
1393     }
1394     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1395     [nView setPointerIcon: c];
1396     [pool release];
1397 }
1398
1399 /*
1400  * Class:     Java_jogamp_newt_driver_macosx_WindowDriver
1401  * Method:    setPointerVisible0
1402  * Signature: (JZ)Z
1403  */
1404 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setPointerVisible0
1405   (JNIEnv *env, jclass clazz, jlong window, jboolean hasFocus, jboolean mouseVisible)
1406 {
1407     NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window);
1408     if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) {
1409         NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin);
1410         return;
1411     }
1412     NewtView* nView = (NewtView *) [mWin contentView];
1413     if( ! [nView isKindOfClass:[NewtView class]] ) {
1414         NewtCommon_throwNewRuntimeException(env, "Not a NewtView %p", nView);
1415         return;
1416     }
1417     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1418     [nView setMouseVisible: ( JNI_TRUE == mouseVisible ) ? YES : NO 
1419                   hasFocus: ( JNI_TRUE == hasFocus ) ? YES : NO];
1420     [pool release];
1421 }
1422
1423 /*
1424  * Class:     Java_jogamp_newt_driver_macosx_WindowDriver
1425  * Method:    confinePointer0
1426  * Signature: (JZ)Z
1427  */
1428 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_confinePointer0
1429   (JNIEnv *env, jclass clazz, jlong window, jboolean confine)
1430 {
1431     NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window);
1432     if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) {
1433         NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin);
1434         return;
1435     }
1436     NewtView* nView = (NewtView *) [mWin contentView];
1437     if( ! [nView isKindOfClass:[NewtView class]] ) {
1438         NewtCommon_throwNewRuntimeException(env, "Not a NewtView %p", nView);
1439         return;
1440     }
1441     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1442     [nView setMouseConfined: ( JNI_TRUE == confine ) ? YES : NO];
1443     [pool release];
1444 }
1445
1446 /*
1447  * Class:     Java_jogamp_newt_driver_macosx_WindowDriver
1448  * Method:    warpPointer0
1449  * Signature: (JJII)V
1450  */
1451 JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_warpPointer0
1452   (JNIEnv *env, jclass clazz, jlong window, jint x, jint y)
1453 {
1454     NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window);
1455     if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) {
1456         NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin);
1457         return;
1458     }
1459     NewtView* nView = (NewtView *) [mWin contentView];
1460     if( ! [nView isKindOfClass:[NewtView class]] ) {
1461         NewtCommon_throwNewRuntimeException(env, "Not a NewtView %p", nView);
1462         return;
1463     }
1464     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1465     [nView setMousePosition: [mWin newtRelClientTLWinPos2AbsBLScreenPos: NSMakePoint(x, y)]];
1466     [pool release];
1467 }
1468
http://JogAmp.org git info: FAQ, tutorial and man pages.