2 * Copyright 2011 JogAmp Community. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
34 #include <AppKit/AppKit.h>
35 #import <QuartzCore/QuartzCore.h>
36 #import "NativeWindowProtocols.h"
38 #include "NativewindowCommon.h"
39 #include "jogamp_nativewindow_macosx_OSXUtil.h"
40 #include "jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow.h"
47 // #define DBG_PRINT(...) NSLog(@ ## __VA_ARGS__)
48 #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr)
50 #define DBG_PRINT(...)
56 #define DBG_PRINT2(...) fprintf(stderr, __VA_ARGS__); fflush(stderr)
58 #define DBG_PRINT2(...)
61 // #define DBG_LIFECYCLE 1
63 static const char * const ClazzNameRunnable = "java/lang/Runnable";
64 static jmethodID runnableRunID = NULL;
66 static const char * const ClazzAnyCstrName = "<init>";
68 static const char * const ClazzNamePoint = "javax/media/nativewindow/util/Point";
69 static const char * const ClazzNamePointCstrSignature = "(II)V";
70 static jclass pointClz = NULL;
71 static jmethodID pointCstr = NULL;
73 static const char * const ClazzNameInsets = "javax/media/nativewindow/util/Insets";
74 static const char * const ClazzNameInsetsCstrSignature = "(IIII)V";
75 static jclass insetsClz = NULL;
76 static jmethodID insetsCstr = NULL;
78 JNIEXPORT jboolean JNICALL
79 Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) {
80 if( NativewindowCommon_init(env) ) {
82 c = (*env)->FindClass(env, ClazzNamePoint);
84 NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't find %s", ClazzNamePoint);
86 pointClz = (jclass)(*env)->NewGlobalRef(env, c);
87 (*env)->DeleteLocalRef(env, c);
89 NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't use %s", ClazzNamePoint);
91 pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature);
93 NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch %s.%s %s",
94 ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature);
97 c = (*env)->FindClass(env, ClazzNameInsets);
99 NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't find %s", ClazzNameInsets);
101 insetsClz = (jclass)(*env)->NewGlobalRef(env, c);
102 (*env)->DeleteLocalRef(env, c);
103 if(NULL==insetsClz) {
104 NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't use %s", ClazzNameInsets);
106 insetsCstr = (*env)->GetMethodID(env, insetsClz, ClazzAnyCstrName, ClazzNameInsetsCstrSignature);
107 if(NULL==insetsCstr) {
108 NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch %s.%s %s",
109 ClazzNameInsets, ClazzAnyCstrName, ClazzNameInsetsCstrSignature);
112 c = (*env)->FindClass(env, ClazzNameRunnable);
114 NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't find %s", ClazzNameRunnable);
116 runnableRunID = (*env)->GetMethodID(env, c, "run", "()V");
117 if(NULL==runnableRunID) {
118 NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch %s.run()V", ClazzNameRunnable);
124 JNIEXPORT jboolean JNICALL
125 Java_jogamp_nativewindow_macosx_OSXUtil_isNSView0(JNIEnv *env, jclass _unused, jlong object) {
126 NSObject *nsObj = (NSObject*) (intptr_t) object;
127 jboolean u = [nsObj isKindOfClass:[NSView class]];
128 DBG_PRINT( "isNSView(obj: %p): %s -> %d\n", nsObj, [[nsObj description] UTF8String], u);
132 JNIEXPORT jboolean JNICALL
133 Java_jogamp_nativewindow_macosx_OSXUtil_isNSWindow0(JNIEnv *env, jclass _unused, jlong object) {
134 NSObject *nsObj = (NSObject*) (intptr_t) object;
135 jboolean u = [nsObj isKindOfClass:[NSWindow class]];
136 DBG_PRINT( "isNSWindow(obj: %p): %s -> %d\n", nsObj, [[nsObj description] UTF8String], u);
140 static CGDirectDisplayID OSXUtil_getCGDirectDisplayIDByNSScreen(NSScreen *screen) {
141 // Mind: typedef uint32_t CGDirectDisplayID; - however, we assume it's 64bit on 64bit ?!
142 NSDictionary * dict = [screen deviceDescription];
143 NSNumber * val = (NSNumber *) [dict objectForKey: @"NSScreenNumber"];
144 // [NSNumber integerValue] returns NSInteger which is 32 or 64 bit native size
145 return (CGDirectDisplayID) [val integerValue];
149 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
150 * Method: getLocationOnScreen0
151 * Signature: (JII)Ljavax/media/nativewindow/util/Point;
153 JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetLocationOnScreen0
154 (JNIEnv *env, jclass unused, jlong winOrView, jint src_x, jint src_y)
156 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
159 * return location in 0/0 top-left space,
160 * OSX is 0/0 bottom-left space naturally
162 NSObject *nsObj = (NSObject*) (intptr_t) winOrView;
163 NSWindow* win = NULL;
166 if( [nsObj isKindOfClass:[NSWindow class]] ) {
167 win = (NSWindow*) nsObj;
168 view = [win contentView];
169 } else if( nsObj != NULL && [nsObj isKindOfClass:[NSView class]] ) {
170 view = (NSView*) nsObj;
173 NativewindowCommon_throwNewRuntimeException(env, "neither win nor view %p\n", nsObj);
175 NSRect viewFrame = [view frame];
179 r.origin.y = viewFrame.size.height - src_y; // y-flip for 0/0 top-left
182 // NSRect rS = [win convertRectToScreen: r]; // 10.7
183 NSPoint oS = [win convertBaseToScreen: r.origin]; // BL-screen
185 NSScreen* screen = [win screen];
186 CGDirectDisplayID display = OSXUtil_getCGDirectDisplayIDByNSScreen(screen);
187 CGRect frameTL = CGDisplayBounds (display); // origin top-left
188 NSRect frameBL = [screen frame]; // origin bottom-left
189 oS.y = frameTL.origin.y + frameTL.size.height - ( oS.y - frameBL.origin.y ); // y-flip from BL-screen -> TL-screen
192 NSRect winFrame = [win frame];
193 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",
194 win, (int)src_x, (int)src_y,
195 (int)winFrame.origin.x, (int)winFrame.origin.y, (int)winFrame.size.width, (int)winFrame.size.height,
196 (int)viewFrame.origin.x, (int)viewFrame.origin.y, (int)viewFrame.size.width, (int)viewFrame.size.height,
197 (int)frameTL.origin.x, (int)frameTL.origin.y, (int)frameTL.size.width, (int)frameTL.size.height,
198 (int)frameBL.origin.x, (int)frameBL.origin.y, (int)frameBL.size.width, (int)frameBL.size.height,
199 (int)oS.x, (int)oS.y);
202 jobject res = (*env)->NewObject(env, pointClz, pointCstr, (jint)oS.x, (jint)oS.y);
210 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
212 * Signature: (J)Ljavax/media/nativewindow/util/Insets;
214 JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetInsets0
215 (JNIEnv *env, jclass unused, jlong winOrView)
217 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
219 NSObject *nsObj = (NSObject*) (intptr_t) winOrView;
220 NSWindow* win = NULL;
224 if( [nsObj isKindOfClass:[NSWindow class]] ) {
225 win = (NSWindow*) nsObj;
226 view = [win contentView];
227 } else if( nsObj != NULL && [nsObj isKindOfClass:[NSView class]] ) {
228 view = (NSView*) nsObj;
231 NativewindowCommon_throwNewRuntimeException(env, "neither win nor view %p\n", nsObj);
234 NSRect frameRect = [win frame];
235 NSRect contentRect = [win contentRectForFrameRect: frameRect];
237 // note: this is a simplistic implementation which doesn't take
238 // into account DPI and scaling factor
239 CGFloat l = contentRect.origin.x - frameRect.origin.x;
241 ir = (jint)(frameRect.size.width - (contentRect.size.width + l)); // r
242 it = (jint)(frameRect.size.height - contentRect.size.height); // t
243 ib = (jint)(contentRect.origin.y - frameRect.origin.y); // b
245 jobject res = (*env)->NewObject(env, insetsClz, insetsCstr, il, ir, it, ib);
253 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
254 * Method: GetPixelScale0
257 JNIEXPORT jdouble JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetPixelScale0
258 (JNIEnv *env, jclass unused, jint screen_idx)
260 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
264 NSArray *screens = [NSScreen screens];
265 if( screen_idx<0 || screen_idx>=[screens count] ) {
269 screen = (NSScreen *) [screens objectAtIndex: screen_idx];
270 pixelScale = 1.0; // default
273 pixelScale = [screen backingScaleFactor]; // HiDPI scaling
279 return (jdouble)pixelScale;
283 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
284 * Method: GetPixelScale1
287 JNIEXPORT jdouble JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetPixelScale1
288 (JNIEnv *env, jclass unused, jlong winOrView)
290 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
292 NSObject *nsObj = (NSObject*) (intptr_t) winOrView;
293 NSWindow* win = NULL;
295 NSScreen *screen = NULL;
297 if( [nsObj isKindOfClass:[NSWindow class]] ) {
298 win = (NSWindow*) nsObj;
299 view = [win contentView];
300 screen = [win screen];
301 } else if( nsObj != NULL && [nsObj isKindOfClass:[NSView class]] ) {
302 view = (NSView*) nsObj;
304 screen = [win screen];
306 NativewindowCommon_throwNewRuntimeException(env, "neither win nor view %p\n", nsObj);
309 CGFloat pixelScale = 1.0; // default
312 pixelScale = [screen backingScaleFactor]; // HiDPI scaling
318 return (jdouble)pixelScale;
322 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
323 * Method: CreateNSWindow0
324 * Signature: (IIIIZ)J
326 JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateNSWindow0
327 (JNIEnv *env, jclass unused, jint x, jint y, jint width, jint height)
329 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
330 NSRect rect = NSMakeRect(x, y, width, height);
332 // Allocate the window
333 NSWindow* myWindow = [[NSWindow alloc] initWithContentRect: rect
334 styleMask: NSBorderlessWindowMask
335 backing: NSBackingStoreBuffered
337 [myWindow setReleasedWhenClosed: YES]; // default
338 [myWindow setPreservesContentDuringLiveResize: YES];
341 if ( [myWindow respondsToSelector:@selector(setAnimationBehavior:)] ) {
342 // Available >= 10.7 - Removes default animations
343 [myWindow setAnimationBehavior: NSWindowAnimationBehaviorNone];
349 [myWindow setOpaque: NO];
350 [myWindow setBackgroundColor: [NSColor clearColor]];
354 return (jlong) ((intptr_t) myWindow);
358 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
359 * Method: DestroyNSWindow0
362 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyNSWindow0
363 (JNIEnv *env, jclass unused, jlong nsWindow)
365 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
366 NSWindow* mWin = (NSWindow*) ((intptr_t) nsWindow);
368 [mWin close]; // performs release!
373 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
377 JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetNSView0
378 (JNIEnv *env, jclass unused, jlong window)
380 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
381 NSWindow* win = (NSWindow*) ((intptr_t) window);
383 jlong res = (jlong) ((intptr_t) [win contentView]);
385 DBG_PRINT( "GetNSView(window: %p): %p\n", win, (void*) (intptr_t) res);
392 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
393 * Method: GetNSWindow0
396 JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetNSWindow0
397 (JNIEnv *env, jclass unused, jlong view)
399 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
400 NSView* v = (NSView*) ((intptr_t) view);
402 jlong res = (jlong) ((intptr_t) [v window]);
404 DBG_PRINT( "GetNSWindow(view: %p): %p\n", v, (void*) (intptr_t) res);
411 * Track lifecycle via DBG_PRINT messages, if VERBOSE is enabled!
413 @interface MyCALayer: CALayer
418 float visibleOpacity;
419 BOOL visibleOpacityZeroed;
424 - (oneway void)release;
427 - (id<CAAction>)actionForKey:(NSString *)key ;
428 - (void)layoutSublayers;
429 - (void)setFrame:(CGRect) frame;
430 - (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;
434 @implementation MyCALayer
438 DBG_PRINT("MyCALayer::init.0\n");
439 MyCALayer * o = [super init];
440 o->fixedFrameSet = 0;
441 o->fixedFrame = CGRectMake(0, 0, 0, 0);
442 o->visibleOpacity = 1.0;
443 o->visibleOpacityZeroed = 0;
444 DBG_PRINT("MyCALayer::init.X: new %p\n", o);
452 DBG_PRINT("MyCALayer::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]);
453 // NSLog(@"MyCALayer::retain: %@",[NSThread callStackSymbols]);
454 id o = [super retain];
455 DBG_PRINT("MyCALayer::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]);
459 - (oneway void)release
461 DBG_PRINT("MyCALayer::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]);
462 // NSLog(@"MyCALayer::release: %@",[NSThread callStackSymbols]);
464 // DBG_PRINT("MyCALayer::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]);
469 DBG_PRINT("MyCALayer::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]);
470 // NSLog(@"MyCALayer::dealloc: %@",[NSThread callStackSymbols]);
472 // DBG_PRINT("MyCALayer.dealloc.X: %p\n", self);
477 - (id<CAAction>)actionForKey:(NSString *)key
479 DBG_PRINT("MyCALayer::actionForKey.0 %p key %s -> NIL\n", self, [key UTF8String]);
481 // return [super actionForKey: key];
484 - (void)layoutSublayers
486 if( fixedFrameSet ) {
487 NSArray* subs = [self sublayers];
489 CGRect rFrame = [self frame];
490 if( !CGRectEqualToRect(fixedFrame, rFrame) ) {
492 DBG_PRINT("CALayer::layoutSublayers.0: Root %p frame %lf/%lf %lfx%lf -> %lf/%lf %lfx%lf\n",
494 rFrame.origin.x, rFrame.origin.y, rFrame.size.width, rFrame.size.height,
495 fixedFrame.origin.x, fixedFrame.origin.y, fixedFrame.size.width, fixedFrame.size.height);
497 [super setFrame: fixedFrame];
500 for(i=0; i<[subs count]; i++) {
501 CALayer* sub = [subs objectAtIndex: i];
502 CGRect sFrame = [sub frame];
503 CGRect sFrame2 = CGRectMake(0, 0, fixedFrame.size.width, fixedFrame.size.height);
504 if( !CGRectEqualToRect(sFrame2, sFrame) ) {
506 DBG_PRINT("CALayer::layoutSublayers.1: Sub[%d] %p frame %lf/%lf %lfx%lf -> %lf/%lf %lfx%lf\n",
508 sFrame.origin.x, sFrame.origin.y, sFrame.size.width, sFrame.size.height,
509 sFrame2.origin.x, sFrame2.origin.y, sFrame2.size.width, sFrame2.size.height);
511 [sub setFrame: sFrame2];
514 DBG_PRINT("CALayer::layoutSublayers.X: Root %p . Sub[%d] %p : frame r: %lf/%lf %lfx%lf . s: %lf/%lf %lfx%lf\n",
516 rFrame.origin.x, rFrame.origin.y, rFrame.size.width, rFrame.size.height,
517 sFrame.origin.x, sFrame.origin.y, sFrame.size.width, sFrame.size.height);
522 [super layoutSublayers];
526 - (void) setFrame:(CGRect) frame
528 if( fixedFrameSet ) {
529 [super setFrame: fixedFrame];
531 [super setFrame: frame];
535 - (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
537 int loutQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_LAYOUT & caLayerQuirks );
539 CALayer* superLayer = [self superlayer];
540 CGRect superFrame = [superLayer frame];
541 CGRect lFrame = [self frame];
543 // Opacity must be 0 to see through the disabled CALayer
544 [subLayer setOpacity: visibleOpacity];
545 [self setOpacity: visibleOpacity];
546 [self setHidden: NO];
547 [subLayer setHidden: NO];
548 visibleOpacityZeroed = 0;
550 [subLayer setHidden: YES];
551 [self setHidden: YES];
552 if( !visibleOpacityZeroed ) {
553 visibleOpacity = [self opacity];
555 [subLayer setOpacity: 0.0];
556 [self setOpacity: 0.0];
557 visibleOpacityZeroed = 1;
559 int posQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_POSITION & caLayerQuirks ) && ( lFrame.origin.x!=0 || lFrame.origin.y!=0 );
560 int sizeQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_SIZE & caLayerQuirks ) && ( lFrame.size.width!=width || lFrame.size.height!=height );
561 if( !posQuirk || loutQuirk ) {
562 // Use root layer position, sub-layer will be on 0/0,
563 // Given AWT position is location on screen w/o insets and top/left origin!
564 fixedFrame.origin.x = x;
565 fixedFrame.origin.y = superFrame.size.height - height - y; // AWT's position top/left -> bottom/left
568 // Buggy super layer position, always use 0/0
569 fixedFrame.origin.x = 0;
570 fixedFrame.origin.y = 0;
573 fixedFrame.size.width = lFrame.size.width;
574 fixedFrame.size.height = lFrame.size.height;
576 fixedFrame.size.width = width;
577 fixedFrame.size.height = height;
579 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",
580 (int)visible, caLayerQuirks, posQuirk, sizeQuirk, loutQuirk, (int)force,
581 superLayer, superFrame.origin.x, superFrame.origin.y, superFrame.size.width, superFrame.size.height,
582 self, lFrame.origin.x, lFrame.origin.y, lFrame.size.width, lFrame.size.height,
583 x, y, width, height, fixedFrame.origin.x, fixedFrame.origin.y, fixedFrame.size.width, fixedFrame.size.height);
584 if( posQuirk || sizeQuirk || loutQuirk ) {
586 [super setFrame: fixedFrame];
589 if( NULL != subLayer ) {
590 CGRect lFrame = [subLayer frame];
591 int sizeQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_SIZE & caLayerQuirks ) && ( lFrame.size.width!=width || lFrame.size.height!=height );
592 CGFloat _x, _y, _w, _h;
593 int posQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_POSITION & caLayerQuirks ) && ( lFrame.origin.x!=0 || lFrame.origin.y!=0 );
594 // Sub rel. to used root layer
599 _w = lFrame.size.width;
600 _h = lFrame.size.height;
605 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",
606 (int)visible, caLayerQuirks, posQuirk, sizeQuirk, loutQuirk, (int)force,
607 subLayer, lFrame.origin.x, lFrame.origin.y, lFrame.size.width, lFrame.size.height,
608 width, height, _x, _y, _w, _h);
609 if( force || posQuirk || sizeQuirk || loutQuirk ) {
610 lFrame.origin.x = _x;
611 lFrame.origin.y = _y;
612 lFrame.size.width = _w;
613 lFrame.size.height = _h;
614 if( [subLayer conformsToProtocol:@protocol(NWDedicatedFrame)] ) {
615 CALayer <NWDedicatedFrame> * subLayerDS = (CALayer <NWDedicatedFrame> *) subLayer;
616 [subLayerDS setDedicatedFrame: lFrame quirks: caLayerQuirks];
618 [subLayer setFrame: lFrame];
627 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
628 * Method: CreateCALayer0
631 JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateCALayer0
632 (JNIEnv *env, jclass unused, jint width, jint height, jfloat contentsScale)
634 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
636 MyCALayer* layer = [[MyCALayer alloc] init];
637 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]);
639 if(0 == width) { width = 32; }
640 if(0 == height) { height = 32; }
644 [layer setContentsScale: (CGFloat)contentsScale];
648 // initial dummy size !
649 CGRect lFrame = [layer frame];
652 lFrame.size.width = width;
653 lFrame.size.height = height;
654 [layer setFrame: lFrame];
655 // no animations for add/remove/swap sublayers etc
656 // doesn't work: [layer removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition]
657 [layer removeAllAnimations];
658 // [layer addAnimation:nil forKey:kCATransition];
659 [layer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)];
660 [layer setNeedsDisplayOnBoundsChange: YES];
661 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);
663 DBG_PRINT("CALayer::CreateCALayer.X: root %p (refcnt %d)\n", layer, (int)[layer retainCount]);
665 return (jlong) ((intptr_t) layer);
669 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
670 * Method: AddCASublayer0
671 * Signature: (JJIIIIIF)V
673 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0
674 (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer, jint x, jint y, jint width, jint height, jfloat contentsScale, jint caLayerQuirks)
676 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
677 MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer);
678 CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer);
680 [CATransaction begin];
681 [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
683 [rootLayer retain]; // Pairs w/ RemoveCASublayer
684 [subLayer retain]; // Pairs w/ RemoveCASublayer
686 CGRect lRectRoot = [rootLayer frame];
689 DBG_PRINT("CALayer::AddCASublayer0.0: Quirks %d, Root %p (refcnt %d), Sub %p (refcnt %d), frame0: %lf/%lf %lfx%lf scale %lf\n",
690 caLayerQuirks, rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount],
691 lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height, (float)contentsScale);
694 [subLayer setContentsScale: (CGFloat)contentsScale];
698 [subLayer setFrame:lRectRoot];
699 [rootLayer addSublayer:subLayer];
701 // no animations for add/remove/swap sublayers etc
702 // doesn't work: [layer removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition]
703 [rootLayer removeAllAnimations];
704 // [rootLayer addAnimation:nil forKey:kCATransition]; // JAU
705 [rootLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)];
706 [rootLayer setNeedsDisplayOnBoundsChange: YES];
707 [subLayer removeAllAnimations];
708 // [subLayer addAnimation:nil forKey:kCATransition]; // JAU
709 [subLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)];
710 [subLayer setNeedsDisplayOnBoundsChange: YES];
712 if( 0 != caLayerQuirks ) {
713 [rootLayer fixCALayerLayout: subLayer visible:1 x:x y:y width:width height:height caLayerQuirks:caLayerQuirks force:JNI_TRUE];
716 [CATransaction commit];
719 DBG_PRINT("CALayer::AddCASublayer0.X: root %p (refcnt %d) .sub %p (refcnt %d)\n",
720 rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount]);
724 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
725 * Method: FixCALayerLayout0
726 * Signature: (JJIII)V
728 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_FixCALayerLayout0
729 (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer, jboolean visible, jint x, jint y, jint width, jint height, jint caLayerQuirks)
731 if( 0 != caLayerQuirks ) {
732 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
733 MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer);
734 if( NULL == rootLayer ) {
735 NativewindowCommon_throwNewRuntimeException(env, "Argument \"rootLayer\" is null");
737 CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer);
739 [CATransaction begin];
740 [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
742 [rootLayer fixCALayerLayout: subLayer visible:(BOOL)visible x:x y:y width:width height:height caLayerQuirks:caLayerQuirks force:JNI_FALSE];
744 [CATransaction commit];
751 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
752 * Method: SetCALayerPixelScale0
755 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_SetCALayerPixelScale0
756 (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer, jfloat contentsScale)
758 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
759 MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer);
760 if( NULL == rootLayer ) {
761 NativewindowCommon_throwNewRuntimeException(env, "Argument \"rootLayer\" is null");
763 CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer);
765 [CATransaction begin];
766 [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
769 [rootLayer setContentsScale: (CGFloat)contentsScale];
770 if( NULL != subLayer ) {
771 [subLayer setContentsScale: (CGFloat)contentsScale];
776 [CATransaction commit];
782 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
783 * Method: RemoveCASublayer0
786 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RemoveCASublayer0
787 (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer)
789 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
790 MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer);
791 CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer);
793 (void)rootLayer; // no warnings
795 DBG_PRINT("CALayer::RemoveCASublayer0.0: root %p (refcnt %d) .sub %p (refcnt %d)\n",
796 rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount]);
798 [CATransaction begin];
799 [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
801 [subLayer removeFromSuperlayer];
802 [subLayer release]; // Pairs w/ AddCASublayer
803 [rootLayer release]; // Pairs w/ AddCASublayer
805 [CATransaction commit];
808 DBG_PRINT("CALayer::RemoveCASublayer0.X: root %p (refcnt %d) .sub %p (refcnt %d)\n",
809 rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount]);
813 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
814 * Method: DestroyCALayer0
817 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyCALayer0
818 (JNIEnv *env, jclass unused, jlong caLayer)
820 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
821 MyCALayer* layer = (MyCALayer*) ((intptr_t) caLayer);
823 [CATransaction begin];
824 [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
826 DBG_PRINT("CALayer::DestroyCALayer0.0: root %p (refcnt %d)\n", layer, (int)[layer retainCount]);
827 [layer release]; // Trigger release and dealloc of root CALayer, it's child etc ..
829 [CATransaction commit];
832 DBG_PRINT("CALayer::DestroyCALayer0.X: root %p\n", layer);
836 * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow
837 * Method: GetJAWTSurfaceLayersHandle0
840 JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_GetJAWTSurfaceLayersHandle0
841 (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer)
843 JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer);
845 NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer");
848 id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo;
849 return (jlong) ((intptr_t) surfaceLayers);
853 * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow
854 * Method: SetJAWTRootSurfaceLayer0
857 JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_SetJAWTRootSurfaceLayer0
858 (JNIEnv *env, jclass unused, jlong jawtSurfaceLayersHandle, jlong caLayer)
860 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
862 [CATransaction begin];
863 [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
865 id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)(intptr_t)jawtSurfaceLayersHandle;
866 MyCALayer* layer = (MyCALayer*) (intptr_t) caLayer;
867 DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.0: pre %p -> root %p (refcnt %d)\n", [surfaceLayers layer], layer, (int)[layer retainCount]);
868 [surfaceLayers setLayer: [layer retain]]; // Pairs w/ Unset
870 [CATransaction commit];
873 DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.X: root %p (refcnt %d)\n", layer, (int)[layer retainCount]);
877 * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow
878 * Method: UnsetJAWTRootSurfaceLayer0
881 JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_UnsetJAWTRootSurfaceLayer0
882 (JNIEnv *env, jclass unused, jlong jawtSurfaceLayersHandle, jlong caLayer)
884 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
886 [CATransaction begin];
887 [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
889 id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)(intptr_t)jawtSurfaceLayersHandle;
890 MyCALayer* layer = (MyCALayer*) (intptr_t) caLayer;
891 if(layer != [surfaceLayers layer]) {
892 NativewindowCommon_throwNewRuntimeException(env, "Attached layer %p doesn't match given layer %p\n", surfaceLayers.layer, layer);
895 DBG_PRINT("CALayer::UnsetJAWTRootSurfaceLayer.0: root %p (refcnt %d) -> nil\n", layer, (int)[layer retainCount]);
896 [layer release]; // Pairs w/ Set
897 [surfaceLayers setLayer: NULL];
899 [CATransaction commit];
902 DBG_PRINT("CALayer::UnsetJAWTRootSurfaceLayer.X: root %p (refcnt %d) -> nil\n", layer, (int)[layer retainCount]);
905 @interface MainRunnable : NSObject
911 - (id) initWithRunnable: (jobject)runnable;
916 - (oneway void)release;
923 @implementation MainRunnable
925 - (id) initWithRunnable: (jobject)runnable
927 runnableObj = runnable;
933 int shallBeDetached = 0;
934 JNIEnv* env = NativewindowCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached);
935 DBG_PRINT2("MainRunnable.1 env: %d\n", (int)(NULL!=env));
937 DBG_PRINT2("MainRunnable.1.0\n");
938 (*env)->CallVoidMethod(env, runnableObj, runnableRunID);
939 DBG_PRINT2("MainRunnable.1.1\n");
940 (*env)->DeleteGlobalRef(env, runnableObj);
942 DBG_PRINT2("MainRunnable.1.3\n");
943 // detaching thread not required - daemon
944 // NativewindowCommon_ReleaseJNIEnv(shallBeDetached);
946 DBG_PRINT2("MainRunnable.X\n");
953 DBG_PRINT2("MainRunnable::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]);
954 id o = [super retain];
955 DBG_PRINT2("MainRunnable::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]);
959 - (oneway void)release
961 DBG_PRINT2("MainRunnable::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]);
963 // DBG_PRINT2("MainRunnable::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]);
968 DBG_PRINT2("MainRunnable::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]);
970 // DBG_PRINT2("MainRunnable.dealloc.X: %p\n", self);
977 static void RunOnThread (JNIEnv *env, jobject runnable, BOOL onMain, jint delayInMS)
979 BOOL isMainThread = [NSThread isMainThread];
980 BOOL forkOnMain = onMain && ( NO == isMainThread || 0 < delayInMS );
982 DBG_PRINT2( "RunOnThread0: forkOnMain %d [onMain %d, delay %dms, isMainThread %d], NSApp %d, NSApp-isRunning %d\n",
983 (int)forkOnMain, (int)onMain, (int)delayInMS, (int)isMainThread, (int)(NULL!=NSApp), (int)([NSApp isRunning]));
986 jobject runnableObj = (*env)->NewGlobalRef(env, runnable);
988 DBG_PRINT2( "RunOnThread.1.0\n");
989 MainRunnable * mr = [[MainRunnable alloc] initWithRunnable: runnableObj];
992 [mr performSelectorOnMainThread:@selector(jRun) withObject:nil waitUntilDone:NO];
994 NSTimeInterval delay = (double)delayInMS/1000.0;
995 [mr performSelector:@selector(jRun) withObject:nil afterDelay:delay];
997 DBG_PRINT2( "RunOnThread.1.1\n");
1000 DBG_PRINT2( "RunOnThread.1.2\n");
1003 DBG_PRINT2( "RunOnThread.2\n");
1004 (*env)->CallVoidMethod(env, runnable, runnableRunID);
1006 DBG_PRINT2( "RunOnThread.X\n");
1010 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
1011 * Method: RunOnMainThread0
1012 * Signature: (ZLjava/lang/Runnable;)V
1014 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunOnMainThread0
1015 (JNIEnv *env, jclass unused, jobject runnable)
1017 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1018 RunOnThread (env, runnable, YES, 0);
1023 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
1025 * Signature: (ZLjava/lang/Runnable;I)V
1027 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunLater0
1028 (JNIEnv *env, jclass unused, jboolean onMain, jobject runnable, jint delay)
1030 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1031 RunOnThread (env, runnable, onMain ? YES : NO, delay);
1036 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
1037 * Method: IsMainThread0
1040 JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_IsMainThread0
1041 (JNIEnv *env, jclass unused)
1043 return ( [NSThread isMainThread] == YES ) ? JNI_TRUE : JNI_FALSE ;
1047 * The following static functions are copied out of NEWT's OSX impl. <src/newt/native/MacWindow.m>
1048 * May need to push code to NativeWindow, to remove duplication.
1050 static NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx) {
1051 NSArray *screens = [NSScreen screens];
1052 if(screen_idx<0) screen_idx=0;
1053 if(screen_idx>=[screens count]) screen_idx=0;
1054 return (NSScreen *) [screens objectAtIndex: screen_idx];
1056 static CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen) {
1057 // Mind: typedef uint32_t CGDirectDisplayID; - however, we assume it's 64bit on 64bit ?!
1058 NSDictionary * dict = [screen deviceDescription];
1059 NSNumber * val = (NSNumber *) [dict objectForKey: @"NSScreenNumber"];
1060 // [NSNumber integerValue] returns NSInteger which is 32 or 64 bit native size
1061 return (CGDirectDisplayID) [val integerValue];
1063 static long GetDictionaryLong(CFDictionaryRef theDict, const void* key)
1067 numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
1069 CFNumberGetValue(numRef, kCFNumberLongType, &value);
1072 #define CGDDGetModeRefreshRate(mode) GetDictionaryLong((mode), kCGDisplayRefreshRate)
1075 * Class: Java_jogamp_nativewindow_macosx_OSXUtil
1076 * Method: GetScreenRefreshRate
1079 JNIEXPORT jint JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetScreenRefreshRate0
1080 (JNIEnv *env, jclass unused, jint scrn_idx)
1083 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1084 NSScreen *screen = NewtScreen_getNSScreenByIndex((int)scrn_idx);
1085 DBG_PRINT("GetScreenRefreshRate.0: screen %p\n", (void *)screen);
1086 if(NULL != screen) {
1087 CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen);
1088 DBG_PRINT("GetScreenRefreshRate.1: display %p\n", (void *)(intptr_t)display);
1090 CFDictionaryRef mode = CGDisplayCurrentMode(display);
1091 DBG_PRINT("GetScreenRefreshRate.2: mode %p\n", (void *)mode);
1093 res = CGDDGetModeRefreshRate(mode);
1094 DBG_PRINT("GetScreenRefreshRate.3: res %d\n", res);
1099 res = 60; // default .. (experienced on OSX 10.6.8)
1101 DBG_PRINT("GetScreenRefreshRate.X: %d\n", (int)res);