diff options
Diffstat (limited to 'src/nativewindow/native/macosx/OSXmisc.m')
-rw-r--r-- | src/nativewindow/native/macosx/OSXmisc.m | 822 |
1 files changed, 661 insertions, 161 deletions
diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m index 38ffde98b..d95d1cdbf 100644 --- a/src/nativewindow/native/macosx/OSXmisc.m +++ b/src/nativewindow/native/macosx/OSXmisc.m @@ -32,13 +32,14 @@ #include <stdarg.h> #include <unistd.h> #include <AppKit/AppKit.h> +#import <QuartzCore/QuartzCore.h> +#import "NativeWindowProtocols.h" #include "NativewindowCommon.h" #include "jogamp_nativewindow_macosx_OSXUtil.h" #include "jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow.h" #include <jawt_md.h> -#import <JavaNativeFoundation.h> // #define VERBOSE 1 // @@ -49,20 +50,34 @@ #define DBG_PRINT(...) #endif +// #define VERBOSE2 1 +// +#ifdef VERBOSE2 + #define DBG_PRINT2(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT2(...) +#endif + +// #define DBG_LIFECYCLE 1 + static const char * const ClazzNameRunnable = "java/lang/Runnable"; static jmethodID runnableRunID = NULL; -static const char * const ClazzNamePoint = "javax/media/nativewindow/util/Point"; static const char * const ClazzAnyCstrName = "<init>"; + +static const char * const ClazzNamePoint = "javax/media/nativewindow/util/Point"; static const char * const ClazzNamePointCstrSignature = "(II)V"; static jclass pointClz = NULL; static jmethodID pointCstr = NULL; -static int _initialized=0; +static const char * const ClazzNameInsets = "javax/media/nativewindow/util/Insets"; +static const char * const ClazzNameInsetsCstrSignature = "(IIII)V"; +static jclass insetsClz = NULL; +static jmethodID insetsCstr = NULL; JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) { - if(0==_initialized) { + if( NativewindowCommon_init(env) ) { jclass c; c = (*env)->FindClass(env, ClazzNamePoint); if(NULL==c) { @@ -79,6 +94,21 @@ Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) { ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); } + c = (*env)->FindClass(env, ClazzNameInsets); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't find %s", ClazzNameInsets); + } + insetsClz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==insetsClz) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't use %s", ClazzNameInsets); + } + insetsCstr = (*env)->GetMethodID(env, insetsClz, ClazzAnyCstrName, ClazzNameInsetsCstrSignature); + if(NULL==insetsCstr) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch %s.%s %s", + ClazzNameInsets, ClazzAnyCstrName, ClazzNameInsetsCstrSignature); + } + c = (*env)->FindClass(env, ClazzNameRunnable); if(NULL==c) { NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't find %s", ClazzNameRunnable); @@ -87,11 +117,26 @@ Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) { if(NULL==runnableRunID) { NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch %s.run()V", ClazzNameRunnable); } - _initialized=1; } return JNI_TRUE; } +JNIEXPORT jboolean JNICALL +Java_jogamp_nativewindow_macosx_OSXUtil_isNSView0(JNIEnv *env, jclass _unused, jlong object) { + NSObject *nsObj = (NSObject*) (intptr_t) object; + jboolean u = [nsObj isKindOfClass:[NSView class]]; + DBG_PRINT( "isNSView(obj: %p): %s -> %d\n", nsObj, [[nsObj description] UTF8String], u); + return u; +} + +JNIEXPORT jboolean JNICALL +Java_jogamp_nativewindow_macosx_OSXUtil_isNSWindow0(JNIEnv *env, jclass _unused, jlong object) { + NSObject *nsObj = (NSObject*) (intptr_t) object; + jboolean u = [nsObj isKindOfClass:[NSWindow class]]; + DBG_PRINT( "isNSWindow(obj: %p): %s -> %d\n", nsObj, [[nsObj description] UTF8String], u); + return u; +} + /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil * Method: getLocationOnScreen0 @@ -150,33 +195,45 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetLocationOnS /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil - * Method: CreateNSView0 - * Signature: (IIIIZ)J + * Method: getInsets0 + * Signature: (J)Ljavax/media/nativewindow/util/Insets; */ -JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateNSView0 - (JNIEnv *env, jclass unused, jint x, jint y, jint width, jint height) +JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetInsets0 + (JNIEnv *env, jclass unused, jlong winOrView) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSRect rect = NSMakeRect(x, y, width, height); - NSView * view = [[NSView alloc] initWithFrame: rect] ; - [view setCanDrawConcurrently: YES]; - [pool release]; - return (jlong) (intptr_t) view; -} + NSObject *nsObj = (NSObject*) (intptr_t) winOrView; + NSWindow* win = NULL; + NSView* view = NULL; + jint il,ir,it,ib; + + if( [nsObj isKindOfClass:[NSWindow class]] ) { + win = (NSWindow*) nsObj; + view = [win contentView]; + } else if( nsObj != NULL && [nsObj isKindOfClass:[NSView class]] ) { + view = (NSView*) nsObj; + win = [view window]; + } else { + NativewindowCommon_throwNewRuntimeException(env, "neither win not view %p\n", nsObj); + } + + NSRect frameRect = [win frame]; + NSRect contentRect = [win contentRectForFrameRect: frameRect]; + + // note: this is a simplistic implementation which doesn't take + // into account DPI and scaling factor + CGFloat l = contentRect.origin.x - frameRect.origin.x; + il = (jint)l; // l + ir = (jint)(frameRect.size.width - (contentRect.size.width + l)); // r + it = (jint)(frameRect.size.height - contentRect.size.height); // t + ib = (jint)(contentRect.origin.y - frameRect.origin.y); // b + + jobject res = (*env)->NewObject(env, insetsClz, insetsCstr, il, ir, it, ib); -/* - * Class: Java_jogamp_nativewindow_macosx_OSXUtil - * Method: DestroyNSView0 - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyNSView0 - (JNIEnv *env, jclass unused, jlong nsView) -{ - NSView* view = (NSView*) (intptr_t) nsView; - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [view release]; [pool release]; + + return res; } /* @@ -197,6 +254,14 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateNSWindow0 defer: YES]; [myWindow setReleasedWhenClosed: YES]; // default [myWindow setPreservesContentDuringLiveResize: YES]; + // Remove animations +NS_DURING + if ( [myWindow respondsToSelector:@selector(setAnimationBehavior:)] ) { + // Available >= 10.7 - Removes default animations + [myWindow setAnimationBehavior: NSWindowAnimationBehaviorNone]; + } +NS_HANDLER +NS_ENDHANDLER // invisible .. [myWindow setOpaque: NO]; @@ -224,31 +289,290 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyNSWindow0 /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: GetNSView0 + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetNSView0 + (JNIEnv *env, jclass unused, jlong window) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSWindow* win = (NSWindow*) ((intptr_t) window); + + jlong res = (jlong) ((intptr_t) [win contentView]); + + DBG_PRINT( "GetNSView(window: %p): %p\n", win, (void*) (intptr_t) res); + + [pool release]; + return res; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: GetNSWindow0 + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetNSWindow0 + (JNIEnv *env, jclass unused, jlong view) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSView* v = (NSView*) ((intptr_t) view); + + jlong res = (jlong) ((intptr_t) [v window]); + + DBG_PRINT( "GetNSWindow(view: %p): %p\n", v, (void*) (intptr_t) res); + + [pool release]; + return res; +} + +/** + * Track lifecycle via DBG_PRINT messages, if VERBOSE is enabled! + */ +@interface MyCALayer: CALayer +{ +@private + BOOL fixedFrameSet; + CGRect fixedFrame; + float visibleOpacity; + BOOL visibleOpacityZeroed; +} +- (id)init; +#ifdef DBG_LIFECYCLE +- (id)retain; +- (oneway void)release; +- (void)dealloc; +#endif +- (id<CAAction>)actionForKey:(NSString *)key ; +- (void)layoutSublayers; +- (void)setFrame:(CGRect) frame; +- (void)fixCALayerLayout: (CALayer*) subLayer visible:(BOOL)visible x:(jint)x y:(jint)y width:(jint)width height:(jint)height caLayerQuirks:(jint)caLayerQuirks force:(jboolean) force; + +@end + +@implementation MyCALayer + +- (id)init +{ + DBG_PRINT("MyCALayer::init.0\n"); + MyCALayer * o = [super init]; + o->fixedFrameSet = 0; + o->fixedFrame = CGRectMake(0, 0, 0, 0); + o->visibleOpacity = 1.0; + o->visibleOpacityZeroed = 0; + DBG_PRINT("MyCALayer::init.X: new %p\n", o); + return o; +} + +#ifdef DBG_LIFECYCLE + +- (id)retain +{ + DBG_PRINT("MyCALayer::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyCALayer::retain: %@",[NSThread callStackSymbols]); + id o = [super retain]; + DBG_PRINT("MyCALayer::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]); + return o; +} + +- (oneway void)release +{ + DBG_PRINT("MyCALayer::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyCALayer::release: %@",[NSThread callStackSymbols]); + [super release]; + // DBG_PRINT("MyCALayer::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]); +} + +- (void)dealloc +{ + DBG_PRINT("MyCALayer::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyCALayer::dealloc: %@",[NSThread callStackSymbols]); + [super dealloc]; + // DBG_PRINT("MyCALayer.dealloc.X: %p\n", self); +} + +#endif + +- (id<CAAction>)actionForKey:(NSString *)key +{ + DBG_PRINT("MyCALayer::actionForKey.0 %p key %s -> NIL\n", self, [key UTF8String]); + return nil; + // return [super actionForKey: key]; +} + +- (void)layoutSublayers +{ + if( fixedFrameSet ) { + NSArray* subs = [self sublayers]; + if( NULL != subs ) { + CGRect rFrame = [self frame]; + if( !CGRectEqualToRect(fixedFrame, rFrame) ) { + #ifdef VERBOSE + DBG_PRINT("CALayer::layoutSublayers.0: Root %p frame %lf/%lf %lfx%lf -> %lf/%lf %lfx%lf\n", + self, + rFrame.origin.x, rFrame.origin.y, rFrame.size.width, rFrame.size.height, + fixedFrame.origin.x, fixedFrame.origin.y, fixedFrame.size.width, fixedFrame.size.height); + #endif + [super setFrame: fixedFrame]; + } + NSUInteger i = 0; + for(i=0; i<[subs count]; i++) { + CALayer* sub = [subs objectAtIndex: i]; + CGRect sFrame = [sub frame]; + CGRect sFrame2 = CGRectMake(0, 0, fixedFrame.size.width, fixedFrame.size.height); + if( !CGRectEqualToRect(sFrame2, sFrame) ) { + #ifdef VERBOSE + DBG_PRINT("CALayer::layoutSublayers.1: Sub[%d] %p frame %lf/%lf %lfx%lf -> %lf/%lf %lfx%lf\n", + (int)i, sub, + sFrame.origin.x, sFrame.origin.y, sFrame.size.width, sFrame.size.height, + sFrame2.origin.x, sFrame2.origin.y, sFrame2.size.width, sFrame2.size.height); + #endif + [sub setFrame: sFrame2]; + } + #ifdef VERBOSE + DBG_PRINT("CALayer::layoutSublayers.X: Root %p . Sub[%d] %p : frame r: %lf/%lf %lfx%lf . s: %lf/%lf %lfx%lf\n", + self, (int)i, sub, + rFrame.origin.x, rFrame.origin.y, rFrame.size.width, rFrame.size.height, + sFrame.origin.x, sFrame.origin.y, sFrame.size.width, sFrame.size.height); + #endif + } + } + } else { + [super layoutSublayers]; + } +} + +- (void) setFrame:(CGRect) frame +{ + if( fixedFrameSet ) { + [super setFrame: fixedFrame]; + } else { + [super setFrame: frame]; + } +} + +- (void)fixCALayerLayout: (CALayer*) subLayer visible:(BOOL)visible x:(jint)x y:(jint)y width:(jint)width height:(jint)height caLayerQuirks:(jint)caLayerQuirks force:(jboolean) force +{ + int loutQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_LAYOUT & caLayerQuirks ); + { + CALayer* superLayer = [self superlayer]; + CGRect superFrame = [superLayer frame]; + CGRect lFrame = [self frame]; + if( visible ) { + // Opacity must be 0 to see through the disabled CALayer + [subLayer setOpacity: visibleOpacity]; + [self setOpacity: visibleOpacity]; + [self setHidden: NO]; + [subLayer setHidden: NO]; + visibleOpacityZeroed = 0; + } else { + [subLayer setHidden: YES]; + [self setHidden: YES]; + if( !visibleOpacityZeroed ) { + visibleOpacity = [self opacity]; + } + [subLayer setOpacity: 0.0]; + [self setOpacity: 0.0]; + visibleOpacityZeroed = 1; + } + int posQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_POSITION & caLayerQuirks ) && ( lFrame.origin.x!=0 || lFrame.origin.y!=0 ); + int sizeQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_SIZE & caLayerQuirks ) && ( lFrame.size.width!=width || lFrame.size.height!=height ); + if( !posQuirk || loutQuirk ) { + // Use root layer position, sub-layer will be on 0/0, + // Given AWT position is location on screen w/o insets and top/left origin! + fixedFrame.origin.x = x; + fixedFrame.origin.y = superFrame.size.height - height - y; // AWT's position top/left -> bottom/left + posQuirk |= 8; + } else { + // Buggy super layer position, always use 0/0 + fixedFrame.origin.x = 0; + fixedFrame.origin.y = 0; + } + if( !sizeQuirk ) { + fixedFrame.size.width = lFrame.size.width; + fixedFrame.size.height = lFrame.size.height; + } else { + fixedFrame.size.width = width; + fixedFrame.size.height = height; + } + DBG_PRINT("CALayer::FixCALayerLayout0.0: Visible %d, Quirks [%d, pos %d, size %d, lout %d, force %d], Super %p frame %lf/%lf %lfx%lf, Root %p frame %lf/%lf %lfx%lf, usr %d/%d %dx%d -> %lf/%lf %lfx%lf\n", + (int)visible, caLayerQuirks, posQuirk, sizeQuirk, loutQuirk, (int)force, + superLayer, superFrame.origin.x, superFrame.origin.y, superFrame.size.width, superFrame.size.height, + self, lFrame.origin.x, lFrame.origin.y, lFrame.size.width, lFrame.size.height, + x, y, width, height, fixedFrame.origin.x, fixedFrame.origin.y, fixedFrame.size.width, fixedFrame.size.height); + if( posQuirk || sizeQuirk || loutQuirk ) { + fixedFrameSet = 1; + [super setFrame: fixedFrame]; + } + } + if( NULL != subLayer ) { + CGRect lFrame = [subLayer frame]; + int sizeQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_SIZE & caLayerQuirks ) && ( lFrame.size.width!=width || lFrame.size.height!=height ); + CGFloat _x, _y, _w, _h; + int posQuirk = 0 != ( NW_DEDICATEDFRAME_QUIRK_POSITION & caLayerQuirks ) && ( lFrame.origin.x!=0 || lFrame.origin.y!=0 ); + // Sub rel. to used root layer + _x = 0; + _y = 0; + posQuirk |= 8; + if( !sizeQuirk ) { + _w = lFrame.size.width; + _h = lFrame.size.height; + } else { + _w = width; + _h = height; + } + DBG_PRINT("CALayer::FixCALayerLayout1.0: Visible %d, Quirks [%d, pos %d, size %d, lout %d, force %d], SubL %p frame %lf/%lf %lfx%lf, usr %dx%d -> %lf/%lf %lfx%lf\n", + (int)visible, caLayerQuirks, posQuirk, sizeQuirk, loutQuirk, (int)force, + subLayer, lFrame.origin.x, lFrame.origin.y, lFrame.size.width, lFrame.size.height, + width, height, _x, _y, _w, _h); + if( force || posQuirk || sizeQuirk || loutQuirk ) { + lFrame.origin.x = _x; + lFrame.origin.y = _y; + lFrame.size.width = _w; + lFrame.size.height = _h; + if( [subLayer conformsToProtocol:@protocol(NWDedicatedFrame)] ) { + CALayer <NWDedicatedFrame> * subLayerDS = (CALayer <NWDedicatedFrame> *) subLayer; + [subLayerDS setDedicatedFrame: lFrame quirks: caLayerQuirks]; + } else { + [subLayer setFrame: lFrame]; + } + } + } +} + +@end + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil * Method: CreateCALayer0 - * Signature: (V)J + * Signature: (II)J */ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateCALayer0 - (JNIEnv *env, jclass unused) + (JNIEnv *env, jclass unused, jint width, jint height) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - CALayer* layer = [[CALayer alloc] init]; - DBG_PRINT("CALayer::CreateCALayer.0: %p (refcnt %d)\n", layer, (int)[layer retainCount]); + MyCALayer* layer = [[MyCALayer alloc] init]; + DBG_PRINT("CALayer::CreateCALayer.0: root %p 0/0 %dx%d (refcnt %d)\n", layer, (int)width, (int)height, (int)[layer retainCount]); + // avoid zero size + if(0 == width) { width = 32; } + if(0 == height) { height = 32; } // initial dummy size ! - CGRect lRect = [layer frame]; - lRect.origin.x = 0; - lRect.origin.y = 0; - lRect.size.width = 32; - lRect.size.height = 32; - [layer setFrame: lRect]; + CGRect lFrame = [layer frame]; + lFrame.origin.x = 0; + lFrame.origin.y = 0; + lFrame.size.width = width; + lFrame.size.height = height; + [layer setFrame: lFrame]; // no animations for add/remove/swap sublayers etc // doesn't work: [layer removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition] [layer removeAllAnimations]; - DBG_PRINT("CALayer::CreateCALayer.1: %p %lf/%lf %lfx%lf\n", layer, lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height); - DBG_PRINT("CALayer::CreateCALayer.X: %p (refcnt %d)\n", layer, (int)[layer retainCount]); - + // [layer addAnimation:nil forKey:kCATransition]; + [layer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; + [layer setNeedsDisplayOnBoundsChange: YES]; + DBG_PRINT("CALayer::CreateCALayer.1: root %p %lf/%lf %lfx%lf\n", layer, lFrame.origin.x, lFrame.origin.y, lFrame.size.width, lFrame.size.height); [pool release]; + DBG_PRINT("CALayer::CreateCALayer.X: root %p (refcnt %d)\n", layer, (int)[layer retainCount]); return (jlong) ((intptr_t) layer); } @@ -256,42 +580,76 @@ JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateCALayer0 /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil * Method: AddCASublayer0 - * Signature: (JJ)V + * Signature: (JJIIIII)V */ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0 - (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer) + (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer, jint x, jint y, jint width, jint height, jint caLayerQuirks) { - JNF_COCOA_ENTER(env); - CALayer* rootLayer = (CALayer*) ((intptr_t) rootCALayer); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer); CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + [rootLayer retain]; // Pairs w/ RemoveCASublayer + [subLayer retain]; // Pairs w/ RemoveCASublayer + CGRect lRectRoot = [rootLayer frame]; - DBG_PRINT("CALayer::AddCASublayer0.0: Origin %p frame0: %lf/%lf %lfx%lf\n", - rootLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height); - if(lRectRoot.origin.x!=0 || lRectRoot.origin.y!=0) { - lRectRoot.origin.x = 0; - lRectRoot.origin.y = 0; - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - [rootLayer setFrame: lRectRoot]; - }]; - DBG_PRINT("CALayer::AddCASublayer0.1: Origin %p frame*: %lf/%lf %lfx%lf\n", - rootLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height); + DBG_PRINT("CALayer::AddCASublayer0.0: Quirks %d, Root %p (refcnt %d), Sub %p (refcnt %d), frame0: %lf/%lf %lfx%lf\n", + caLayerQuirks, rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount], + lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height); + + [subLayer setFrame:lRectRoot]; + [rootLayer addSublayer:subLayer]; + + // no animations for add/remove/swap sublayers etc + // doesn't work: [layer removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition] + [rootLayer removeAllAnimations]; + // [rootLayer addAnimation:nil forKey:kCATransition]; // JAU + [rootLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; + [rootLayer setNeedsDisplayOnBoundsChange: YES]; + [subLayer removeAllAnimations]; + // [subLayer addAnimation:nil forKey:kCATransition]; // JAU + [subLayer setAutoresizingMask: (kCALayerWidthSizable|kCALayerHeightSizable)]; + [subLayer setNeedsDisplayOnBoundsChange: YES]; + + if( 0 != caLayerQuirks ) { + [rootLayer fixCALayerLayout: subLayer visible:1 x:x y:y width:width height:height caLayerQuirks:caLayerQuirks force:JNI_TRUE]; } - DBG_PRINT("CALayer::AddCASublayer0.2: %p . %p %lf/%lf %lfx%lf (refcnt %d)\n", - rootLayer, subLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height, (int)[subLayer retainCount]); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - // simple 1:1 layout ! - [subLayer setFrame:lRectRoot]; - [rootLayer addSublayer:subLayer]; + [CATransaction commit]; + + [pool release]; + DBG_PRINT("CALayer::AddCASublayer0.X: root %p (refcnt %d) .sub %p (refcnt %d)\n", + rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount]); +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: FixCALayerLayout0 + * Signature: (JJIII)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_FixCALayerLayout0 + (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer, jboolean visible, jint x, jint y, jint width, jint height, jint caLayerQuirks) +{ + if( 0 != caLayerQuirks ) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer); + if( NULL == rootLayer ) { + NativewindowCommon_throwNewRuntimeException(env, "Argument \"rootLayer\" is null"); + } + CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; - // no animations for add/remove/swap sublayers etc - // doesn't work: [layer removeAnimationForKey: kCAOnOrderIn, kCAOnOrderOut, kCATransition] - [rootLayer removeAllAnimations]; - [subLayer removeAllAnimations]; - }]; - DBG_PRINT("CALayer::AddCASublayer0.X: %p . %p (refcnt %d)\n", rootLayer, subLayer, (int)[subLayer retainCount]); - JNF_COCOA_EXIT(env); + [rootLayer fixCALayerLayout: subLayer visible:(BOOL)visible x:x y:y width:width height:height caLayerQuirks:caLayerQuirks force:JNI_FALSE]; + + [CATransaction commit]; + + [pool release]; + } } /* @@ -302,18 +660,27 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RemoveCASublayer0 (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer) { - JNF_COCOA_ENTER(env); - CALayer* rootLayer = (CALayer*) ((intptr_t) rootCALayer); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* rootLayer = (MyCALayer*) ((intptr_t) rootCALayer); CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); (void)rootLayer; // no warnings - DBG_PRINT("CALayer::RemoveCASublayer0.0: %p . %p (refcnt %d)\n", rootLayer, subLayer, (int)[subLayer retainCount]); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - [subLayer removeFromSuperlayer]; - }]; - DBG_PRINT("CALayer::RemoveCASublayer0.X: %p . %p\n", rootLayer, subLayer); - JNF_COCOA_EXIT(env); + DBG_PRINT("CALayer::RemoveCASublayer0.0: root %p (refcnt %d) .sub %p (refcnt %d)\n", + rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount]); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + [subLayer removeFromSuperlayer]; + [subLayer release]; // Pairs w/ AddCASublayer + [rootLayer release]; // Pairs w/ AddCASublayer + + [CATransaction commit]; + + [pool release]; + DBG_PRINT("CALayer::RemoveCASublayer0.X: root %p (refcnt %d) .sub %p (refcnt %d)\n", + rootLayer, (int)[rootLayer retainCount], subLayer, (int)[subLayer retainCount]); } /* @@ -324,36 +691,113 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RemoveCASublayer0 JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyCALayer0 (JNIEnv *env, jclass unused, jlong caLayer) { - JNF_COCOA_ENTER(env); - CALayer* layer = (CALayer*) ((intptr_t) caLayer); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyCALayer* layer = (MyCALayer*) ((intptr_t) caLayer); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + DBG_PRINT("CALayer::DestroyCALayer0.0: root %p (refcnt %d)\n", layer, (int)[layer retainCount]); + [layer release]; // Trigger release and dealloc of root CALayer, it's child etc .. + + [CATransaction commit]; + + [pool release]; + DBG_PRINT("CALayer::DestroyCALayer0.X: root %p\n", layer); +} + +/* + * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow + * Method: GetJAWTSurfaceLayersHandle0 + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_GetJAWTSurfaceLayersHandle0 + (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer) +{ + JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer); + if (NULL == dsi) { + NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer"); + return 0; + } + id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; + return (jlong) ((intptr_t) surfaceLayers); +} + +/* + * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow + * Method: SetJAWTRootSurfaceLayer0 + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_SetJAWTRootSurfaceLayer0 + (JNIEnv *env, jclass unused, jlong jawtSurfaceLayersHandle, jlong caLayer) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)(intptr_t)jawtSurfaceLayersHandle; + MyCALayer* layer = (MyCALayer*) (intptr_t) caLayer; + DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.0: pre %p -> root %p (refcnt %d)\n", [surfaceLayers layer], layer, (int)[layer retainCount]); + [surfaceLayers setLayer: [layer retain]]; // Pairs w/ Unset + + [CATransaction commit]; + + [pool release]; + DBG_PRINT("CALayer::SetJAWTRootSurfaceLayer.X: root %p (refcnt %d)\n", layer, (int)[layer retainCount]); +} + +/* + * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow + * Method: UnsetJAWTRootSurfaceLayer0 + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_UnsetJAWTRootSurfaceLayer0 + (JNIEnv *env, jclass unused, jlong jawtSurfaceLayersHandle, jlong caLayer) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + + id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)(intptr_t)jawtSurfaceLayersHandle; + MyCALayer* layer = (MyCALayer*) (intptr_t) caLayer; + if(layer != [surfaceLayers layer]) { + NativewindowCommon_throwNewRuntimeException(env, "Attached layer %p doesn't match given layer %p\n", surfaceLayers.layer, layer); + return; + } + DBG_PRINT("CALayer::UnsetJAWTRootSurfaceLayer.0: root %p (refcnt %d) -> nil\n", layer, (int)[layer retainCount]); + [layer release]; // Pairs w/ Set + [surfaceLayers setLayer: NULL]; + + [CATransaction commit]; - DBG_PRINT("CALayer::DestroyCALayer0.0: %p (refcnt %d)\n", layer, (int)[layer retainCount]); - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - [layer release]; // performs release! - }]; - DBG_PRINT("CALayer::DestroyCALayer0.X: %p\n", layer); - JNF_COCOA_EXIT(env); + [pool release]; + DBG_PRINT("CALayer::UnsetJAWTRootSurfaceLayer.X: root %p (refcnt %d) -> nil\n", layer, (int)[layer retainCount]); } @interface MainRunnable : NSObject { - JavaVM *jvmHandle; - int jvmVersion; jobject runnableObj; } -- (id) initWithRunnable: (jobject)runnable jvmHandle: (JavaVM*)jvm jvmVersion: (int)jvmVers; +- (id) initWithRunnable: (jobject)runnable; - (void) jRun; +#ifdef DBG_LIFECYCLE +- (id)retain; +- (oneway void)release; +- (void)dealloc; +#endif + + @end @implementation MainRunnable -- (id) initWithRunnable: (jobject)runnable jvmHandle: (JavaVM*)jvm jvmVersion: (int)jvmVers +- (id) initWithRunnable: (jobject)runnable { - jvmHandle = jvm; - jvmVersion = jvmVers; runnableObj = runnable; return [super init]; } @@ -361,58 +805,111 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyCALayer0 - (void) jRun { int shallBeDetached = 0; - JNIEnv* env = NativewindowCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + JNIEnv* env = NativewindowCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + DBG_PRINT2("MainRunnable.1 env: %d\n", (int)(NULL!=env)); if(NULL!=env) { + DBG_PRINT2("MainRunnable.1.0\n"); (*env)->CallVoidMethod(env, runnableObj, runnableRunID); + DBG_PRINT2("MainRunnable.1.1\n"); + (*env)->DeleteGlobalRef(env, runnableObj); - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } + DBG_PRINT2("MainRunnable.1.3\n"); + // detaching thread not required - daemon + // NativewindowCommon_ReleaseJNIEnv(shallBeDetached); } + DBG_PRINT2("MainRunnable.X\n"); } -@end +#ifdef DBG_LIFECYCLE +- (id)retain +{ + DBG_PRINT2("MainRunnable::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + id o = [super retain]; + DBG_PRINT2("MainRunnable::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]); + return o; +} -/* - * Class: Java_jogamp_nativewindow_macosx_OSXUtil - * Method: RunOnMainThread0 - * Signature: (ZLjava/lang/Runnable;)V - */ -JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunOnMainThread0 - (JNIEnv *env, jclass unused, jboolean jwait, jobject runnable) +- (oneway void)release { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + DBG_PRINT2("MainRunnable::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + [super release]; + // DBG_PRINT2("MainRunnable::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]); +} + +- (void)dealloc +{ + DBG_PRINT2("MainRunnable::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]); + [super dealloc]; + // DBG_PRINT2("MainRunnable.dealloc.X: %p\n", self); +} + +#endif + +@end + +static void RunOnThread (JNIEnv *env, jobject runnable, BOOL onMain, jint delayInMS) +{ + BOOL isMainThread = [NSThread isMainThread]; + BOOL forkOnMain = onMain && ( NO == isMainThread || 0 < delayInMS ); + + DBG_PRINT2( "RunOnThread0: forkOnMain %d [onMain %d, delay %dms, isMainThread %d], NSApp %d, NSApp-isRunning %d\n", + (int)forkOnMain, (int)onMain, (int)delayInMS, (int)isMainThread, (int)(NULL!=NSApp), (int)([NSApp isRunning])); - if ( NO == [NSThread isMainThread] ) { - jobject runnableGlob = (*env)->NewGlobalRef(env, runnable); + if ( forkOnMain ) { + jobject runnableObj = (*env)->NewGlobalRef(env, runnable); - BOOL wait = (JNI_TRUE == jwait) ? YES : NO; - JavaVM *jvmHandle = NULL; - int jvmVersion = 0; + DBG_PRINT2( "RunOnThread.1.0\n"); + MainRunnable * mr = [[MainRunnable alloc] initWithRunnable: runnableObj]; - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; + if( onMain ) { + [mr performSelectorOnMainThread:@selector(jRun) withObject:nil waitUntilDone:NO]; } else { - jvmVersion = (*env)->GetVersion(env); + NSTimeInterval delay = (double)delayInMS/1000.0; + [mr performSelector:@selector(jRun) withObject:nil afterDelay:delay]; } + DBG_PRINT2( "RunOnThread.1.1\n"); - MainRunnable * mr = [[MainRunnable alloc] initWithRunnable: runnableGlob jvmHandle: jvmHandle jvmVersion: jvmVersion]; - [mr performSelectorOnMainThread:@selector(jRun) withObject:nil waitUntilDone:wait]; [mr release]; + DBG_PRINT2( "RunOnThread.1.2\n"); - (*env)->DeleteGlobalRef(env, runnableGlob); } else { + DBG_PRINT2( "RunOnThread.2\n"); (*env)->CallVoidMethod(env, runnable, runnableRunID); } + DBG_PRINT2( "RunOnThread.X\n"); +} +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: RunOnMainThread0 + * Signature: (ZLjava/lang/Runnable;)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunOnMainThread0 + (JNIEnv *env, jclass unused, jobject runnable) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + RunOnThread (env, runnable, YES, 0); [pool release]; } /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil - * Method: RunOnMainThread0 - * Signature: (V)V + * Method: RunLater0 + * Signature: (ZLjava/lang/Runnable;I)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunLater0 + (JNIEnv *env, jclass unused, jboolean onMain, jobject runnable, jint delay) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + RunOnThread (env, runnable, onMain ? YES : NO, delay); + [pool release]; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: IsMainThread0 + * Signature: (V)Z */ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_IsMainThread0 (JNIEnv *env, jclass unused) @@ -420,60 +917,63 @@ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_IsMainThread0 return ( [NSThread isMainThread] == YES ) ? JNI_TRUE : JNI_FALSE ; } -/* - * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow - * Method: AttachJAWTSurfaceLayer - * Signature: (JJ)Z +/*** + * The following static functions are copied out of NEWT's OSX impl. <src/newt/native/MacWindow.m> + * May need to push code to NativeWindow, to remove duplication. */ -JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_AttachJAWTSurfaceLayer0 - (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer, jlong caLayer) +static NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx) { + NSArray *screens = [NSScreen screens]; + if(screen_idx<0) screen_idx=0; + if(screen_idx>=[screens count]) screen_idx=0; + return (NSScreen *) [screens objectAtIndex: screen_idx]; +} +static CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen) { + // Mind: typedef uint32_t CGDirectDisplayID; - however, we assume it's 64bit on 64bit ?! + NSDictionary * dict = [screen deviceDescription]; + NSNumber * val = (NSNumber *) [dict objectForKey: @"NSScreenNumber"]; + // [NSNumber integerValue] returns NSInteger which is 32 or 64 bit native size + return (CGDirectDisplayID) [val integerValue]; +} +static long GetDictionaryLong(CFDictionaryRef theDict, const void* key) { - JNF_COCOA_ENTER(env); - JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer); - if (NULL == dsi) { - NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer"); - return JNI_FALSE; - } - CALayer* layer = (CALayer*) (intptr_t) caLayer; - [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; - DBG_PRINT("CALayer::attachJAWTSurfaceLayer: %p -> %p (refcnt %d)\n", surfaceLayers.layer, layer, (int)[layer retainCount]); - surfaceLayers.layer = layer; // already incr. retain count - DBG_PRINT("CALayer::attachJAWTSurfaceLayer.X: %p (refcnt %d)\n", layer, (int)[layer retainCount]); - }]; - JNF_COCOA_EXIT(env); - return JNI_TRUE; + long value = 0; + CFNumberRef numRef; + numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key); + if (numRef != NULL) + CFNumberGetValue(numRef, kCFNumberLongType, &value); + return value; } +#define CGDDGetModeRefreshRate(mode) GetDictionaryLong((mode), kCGDisplayRefreshRate) /* - * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow - * Method: DetachJAWTSurfaceLayer - * Signature: (JJ)Z -JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_DetachJAWTSurfaceLayer0 - (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer, jlong caLayer) + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: GetScreenRefreshRate + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetScreenRefreshRate0 + (JNIEnv *env, jclass unused, jint scrn_idx) { - JNF_COCOA_ENTER(env); - JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer); - if (NULL == dsi) { - NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer"); - return JNI_FALSE; - } - CALayer* layer = (CALayer*) (intptr_t) caLayer; - { - id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; - if(layer != surfaceLayers.layer) { - NativewindowCommon_throwNewRuntimeException(env, "Attached layer %p doesn't match given layer %p\n", surfaceLayers.layer, layer); - return JNI_FALSE; + int res = 0; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSScreen *screen = NewtScreen_getNSScreenByIndex((int)scrn_idx); + DBG_PRINT("GetScreenRefreshRate.0: screen %p\n", (void *)screen); + if(NULL != screen) { + CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen); + DBG_PRINT("GetScreenRefreshRate.1: display %p\n", (void *)(intptr_t)display); + if(0 != display) { + CFDictionaryRef mode = CGDisplayCurrentMode(display); + DBG_PRINT("GetScreenRefreshRate.2: mode %p\n", (void *)mode); + if(NULL != mode) { + res = CGDDGetModeRefreshRate(mode); + DBG_PRINT("GetScreenRefreshRate.3: res %d\n", res); + } } } - // [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; - DBG_PRINT("CALayer::detachJAWTSurfaceLayer: (%p) %p -> NULL\n", layer, surfaceLayers.layer); - surfaceLayers.layer = NULL; - [layer release]; - // }]; - JNF_COCOA_EXIT(env); - return JNI_TRUE; + if(0 == res) { + res = 60; // default .. (experienced on OSX 10.6.8) + } + DBG_PRINT("GetScreenRefreshRate.X: %d\n", (int)res); + [pool release]; + return res; } - */ |