/* * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #import #import #import #import #import #import #import #include "jni_util.h" #import "CMenuBar.h" #import "InitIDs.h" #import "LWCToolkit.h" #import "ThreadUtilities.h" #import "AWT_debug.h" #import "CSystemColors.h" #import "NSApplicationAWT.h" #import "PropertiesUtilities.h" #import "ApplicationDelegate.h" #import "sun_lwawt_macosx_LWCToolkit.h" #import "sizecalc.h" int gNumberOfButtons; jint* gButtonDownMasks; // Indicates that the app has been started with -XstartOnFirstThread // (directly or via WebStart settings), and AWT should not run its // own event loop in this mode. Even if a loop isn't running yet, // we expect an embedder (e.g. SWT) to start it some time later. static BOOL forceEmbeddedMode = NO; // Indicates if awt toolkit is embedded into another UI toolkit static BOOL isEmbedded = NO; // This is the data necessary to have JNI_OnLoad wait for AppKit to start. static BOOL sAppKitStarted = NO; static pthread_mutex_t sAppKitStarted_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t sAppKitStarted_cv = PTHREAD_COND_INITIALIZER; @implementation AWTToolkit static long eventCount; + (long) getEventCount{ return eventCount; } + (void) eventCountPlusPlus{ eventCount++; } @end @interface AWTRunLoopObject : NSObject { BOOL _shouldEndRunLoop; } @end @implementation AWTRunLoopObject - (id) init { self = [super init]; if (self != nil) { _shouldEndRunLoop = NO; } return self; } - (BOOL) shouldEndRunLoop { return _shouldEndRunLoop; } - (void) endRunLoop { _shouldEndRunLoop = YES; } @end @interface JavaRunnable : NSObject { } @property jobject runnable; - (id)initWithRunnable:(jobject)gRunnable; - (void)perform; @end @implementation JavaRunnable @synthesize runnable = _runnable; - (id)initWithRunnable:(jobject)gRunnable { if (self = [super init]) { self.runnable = gRunnable; } return self; } - (void)dealloc { JNIEnv *env = [ThreadUtilities getJNIEnv]; if (self.runnable) { (*env)->DeleteGlobalRef(env, self.runnable); } [super dealloc]; } - (void)perform { JNIEnv* env = [ThreadUtilities getJNIEnv]; static JNF_CLASS_CACHE(sjc_Runnable, "java/lang/Runnable"); static JNF_MEMBER_CACHE(jm_Runnable_run, sjc_Runnable, "run", "()V"); JNFCallVoidMethod(env, self.runnable, jm_Runnable_run); [self release]; } @end void setBusy(BOOL busy) { AWT_ASSERT_APPKIT_THREAD; JNIEnv *env = [ThreadUtilities getJNIEnv]; static JNF_CLASS_CACHE(jc_AWTAutoShutdown, "sun/awt/AWTAutoShutdown"); if (busy) { static JNF_STATIC_MEMBER_CACHE(jm_notifyBusyMethod, jc_AWTAutoShutdown, "notifyToolkitThreadBusy", "()V"); JNFCallStaticVoidMethod(env, jm_notifyBusyMethod); } else { static JNF_STATIC_MEMBER_CACHE(jm_notifyFreeMethod, jc_AWTAutoShutdown, "notifyToolkitThreadFree", "()V"); JNFCallStaticVoidMethod(env, jm_notifyFreeMethod); } } static void setUpAWTAppKit(BOOL installObservers) { if (installObservers) { AWT_STARTUP_LOG(@"Setting up busy observers"); // Add CFRunLoopObservers to call into AWT so that AWT knows that the // AWT thread (which is the AppKit main thread) is alive. This way AWT // will not automatically shutdown. CFRunLoopObserverRef busyObserver = CFRunLoopObserverCreateWithHandler( NULL, // CFAllocator kCFRunLoopAfterWaiting, // CFOptionFlags true, // repeats NSIntegerMax, // order ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { setBusy(YES); }); CFRunLoopObserverRef notBusyObserver = CFRunLoopObserverCreateWithHandler( NULL, // CFAllocator kCFRunLoopBeforeWaiting, // CFOptionFlags true, // repeats NSIntegerMin, // order ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { setBusy(NO); }); CFRunLoopRef runLoop = [[NSRunLoop currentRunLoop] getCFRunLoop]; CFRunLoopAddObserver(runLoop, busyObserver, kCFRunLoopDefaultMode); CFRunLoopAddObserver(runLoop, notBusyObserver, kCFRunLoopDefaultMode); CFRelease(busyObserver); CFRelease(notBusyObserver); setBusy(YES); } JNIEnv* env = [ThreadUtilities getJNIEnv]; static JNF_CLASS_CACHE(jc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit"); static JNF_STATIC_MEMBER_CACHE(jsm_installToolkitThreadInJava, jc_LWCToolkit, "installToolkitThreadInJava", "()V"); JNFCallStaticVoidMethod(env, jsm_installToolkitThreadInJava); } BOOL isSWTInWebStart(JNIEnv* env) { NSString *swtWebStart = [PropertiesUtilities javaSystemPropertyForKey:@"com.apple.javaws.usingSWT" withEnv:env]; return [@"true" isCaseInsensitiveLike:swtWebStart]; } static void AWT_NSUncaughtExceptionHandler(NSException *exception) { NSLog(@"Apple AWT Internal Exception: %@", [exception description]); } @interface AWTStarter : NSObject + (void)start:(BOOL)headless; + (void)starter:(BOOL)onMainThread headless:(BOOL)headless; + (void)appKitIsRunning:(id)arg; @end @implementation AWTStarter + (BOOL) isConnectedToWindowServer { SecuritySessionId session_id; SessionAttributeBits session_info; OSStatus status = SessionGetInfo(callerSecuritySession, &session_id, &session_info); if (status != noErr) return NO; if (!(session_info & sessionHasGraphicAccess)) return NO; return YES; } + (BOOL) markAppAsDaemon { id jrsAppKitAWTClass = objc_getClass("JRSAppKitAWT"); SEL markAppSel = @selector(markAppIsDaemon); if (![jrsAppKitAWTClass respondsToSelector:markAppSel]) return NO; return [jrsAppKitAWTClass performSelector:markAppSel] ? YES : NO; } + (void)appKitIsRunning:(id)arg { AWT_ASSERT_APPKIT_THREAD; AWT_STARTUP_LOG(@"About to message AppKit started"); // Signal that AppKit has started (or is already running). pthread_mutex_lock(&sAppKitStarted_mutex); sAppKitStarted = YES; pthread_cond_signal(&sAppKitStarted_cv); pthread_mutex_unlock(&sAppKitStarted_mutex); AWT_STARTUP_LOG(@"Finished messaging AppKit started"); } + (void)start:(BOOL)headless { // onMainThread is NOT the same at SWT mode! // If the JVM was started on the first thread for SWT, but the SWT loads the AWT on a secondary thread, // onMainThread here will be false but SWT mode will be true. If we are currently on the main thread, we don't // need to throw AWT startup over to another thread. BOOL onMainThread = [NSThread isMainThread]; NSString* msg = [NSString stringWithFormat:@"+[AWTStarter start headless:%d] { onMainThread:%d }", headless, onMainThread]; AWT_STARTUP_LOG(msg); if (!headless) { // Listen for the NSApp to start. This indicates that JNI_OnLoad can proceed. // It must wait because there is a chance that another java thread will grab // the AppKit lock before the +[NSApplication sharedApplication] returns. // See for an example. [[NSNotificationCenter defaultCenter] addObserver:[AWTStarter class] selector:@selector(appKitIsRunning:) name:NSApplicationDidFinishLaunchingNotification object:nil]; AWT_STARTUP_LOG(@"+[AWTStarter start:::]: registered NSApplicationDidFinishLaunchingNotification"); } [ThreadUtilities performOnMainThreadWaiting:NO block:^() { [AWTStarter starter:onMainThread headless:headless]; }]; if (!headless && !onMainThread) { AWT_STARTUP_LOG(@"about to wait on AppKit startup mutex"); // Wait here for AppKit to have started (or for AWT to have been loaded into // an already running NSApplication). pthread_mutex_lock(&sAppKitStarted_mutex); while (sAppKitStarted == NO) { pthread_cond_wait(&sAppKitStarted_cv, &sAppKitStarted_mutex); } pthread_mutex_unlock(&sAppKitStarted_mutex); // AWT gets here AFTER +[AWTStarter appKitIsRunning:] is called. AWT_STARTUP_LOG(@"got out of the AppKit startup mutex"); } if (!headless) { // Don't set the delegate until the NSApplication has been created and // its finishLaunching has initialized it. // ApplicationDelegate is the support code for com.apple.eawt. [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ id delegate = [ApplicationDelegate sharedDelegate]; if (delegate != nil) { OSXAPP_SetApplicationDelegate(delegate); } }]; } } + (void)starter:(BOOL)wasOnMainThread headless:(BOOL)headless { NSAutoreleasePool *pool = [NSAutoreleasePool new]; // Add the exception handler of last resort NSSetUncaughtExceptionHandler(AWT_NSUncaughtExceptionHandler); // Headless mode trumps either ordinary AWT or SWT-in-AWT mode. Declare us a daemon and return. if (headless) { // Note that we don't install run loop observers in headless mode // because we don't need them (see 7174704) if (!forceEmbeddedMode) { setUpAWTAppKit(false); } [AWTStarter markAppAsDaemon]; return; } if (forceEmbeddedMode) { AWT_STARTUP_LOG(@"in SWT or SWT/WebStart mode"); // Init a default NSApplication instance instead of the NSApplicationAWT. // Note that [NSApp isRunning] will return YES after that, though // this behavior isn't specified anywhere. We rely on that. NSApplicationLoad(); } // This will create a NSApplicationAWT for standalone AWT programs, unless there is // already a NSApplication instance. If there is already a NSApplication instance, // and -[NSApplication isRunning] returns YES, AWT is embedded inside another // AppKit Application. NSApplication *app = [NSApplicationAWT sharedApplication]; isEmbedded = ![NSApp isKindOfClass:[NSApplicationAWT class]]; if (!isEmbedded) { // Install run loop observers and set the AppKit Java thread name setUpAWTAppKit(true); } // AWT gets to this point BEFORE NSApplicationDidFinishLaunchingNotification is sent. if (![app isRunning]) { AWT_STARTUP_LOG(@"+[AWTStarter startAWT]: ![app isRunning]"); // This is where the AWT AppKit thread parks itself to process events. [NSApplicationAWT runAWTLoopWithApp: app]; } else { // We're either embedded, or showing a splash screen if (isEmbedded) { AWT_STARTUP_LOG(@"running embedded"); // We don't track if the runloop is busy, so set it free to let AWT finish when it needs setBusy(NO); } else { AWT_STARTUP_LOG(@"running after showing a splash screen"); } // Signal so that JNI_OnLoad can proceed. if (!wasOnMainThread) [AWTStarter appKitIsRunning:nil]; // Proceed to exit this call as there is no reason to run the NSApplication event loop. } [pool drain]; } @end /* * Class: sun_lwawt_macosx_LWCToolkit * Method: nativeSyncQueue * Signature: (J)Z */ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_nativeSyncQueue (JNIEnv *env, jobject self, jlong timeout) { int currentEventNum = [AWTToolkit getEventCount]; NSApplication* sharedApp = [NSApplication sharedApplication]; if ([sharedApp isKindOfClass:[NSApplicationAWT class]]) { NSApplicationAWT* theApp = (NSApplicationAWT*)sharedApp; [theApp postDummyEvent]; [theApp waitForDummyEvent]; } else { // could happen if we are embedded inside SWT application, // in this case just spin a single empty block through // the event loop to give it a chance to process pending events [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){}]; } if (([AWTToolkit getEventCount] - currentEventNum) != 0) { return JNI_TRUE; } return JNI_FALSE; } /* * Class: sun_lwawt_macosx_LWCToolkit * Method: flushNativeSelectors * Signature: ()J */ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_flushNativeSelectors (JNIEnv *env, jclass clz) { JNF_COCOA_ENTER(env); [ThreadUtilities performOnMainThreadWaiting:YES block:^(){}]; JNF_COCOA_EXIT(env); } /* * Class: sun_lwawt_macosx_LWCToolkit * Method: beep * Signature: ()V */ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_beep (JNIEnv *env, jobject self) { NSBeep(); // produces both sound and visual flash, if configured in System Preferences } static UInt32 RGB(NSColor *c) { c = [c colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; if (c == nil) { return -1; // opaque white } CGFloat r, g, b, a; [c getRed:&r green:&g blue:&b alpha:&a]; UInt32 ir = (UInt32) (r*255+0.5), ig = (UInt32) (g*255+0.5), ib = (UInt32) (b*255+0.5), ia = (UInt32) (a*255+0.5); // NSLog(@"%@ %d, %d, %d", c, ir, ig, ib); return ((ia & 0xFF) << 24) | ((ir & 0xFF) << 16) | ((ig & 0xFF) << 8) | ((ib & 0xFF) << 0); } BOOL doLoadNativeColors(JNIEnv *env, jintArray jColors, BOOL useAppleColors) { jint len = (*env)->GetArrayLength(env, jColors); UInt32 colorsArray[len]; UInt32 *colors = colorsArray; [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ NSUInteger i; for (i = 0; i < len; i++) { colors[i] = RGB([CSystemColors getColor:i useAppleColor:useAppleColors]); } }]; jint *_colors = (*env)->GetPrimitiveArrayCritical(env, jColors, 0); if (_colors == NULL) { return NO; } memcpy(_colors, colors, len * sizeof(UInt32)); (*env)->ReleasePrimitiveArrayCritical(env, jColors, _colors, 0); return YES; } /** * Class: sun_lwawt_macosx_LWCToolkit * Method: loadNativeColors * Signature: ([I[I)V */ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_loadNativeColors (JNIEnv *env, jobject peer, jintArray jSystemColors, jintArray jAppleColors) { JNF_COCOA_ENTER(env); if (doLoadNativeColors(env, jSystemColors, NO)) { doLoadNativeColors(env, jAppleColors, YES); } JNF_COCOA_EXIT(env); } /* * Class: sun_lwawt_macosx_LWCToolkit * Method: createAWTRunLoopMediator * Signature: ()J */ JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_LWCToolkit_createAWTRunLoopMediator (JNIEnv *env, jclass clz) { AWT_ASSERT_APPKIT_THREAD; jlong result; JNF_COCOA_ENTER(env); // We double retain because this object is owned by both main thread and "other" thread // We release in both doAWTRunLoop and stopAWTRunLoop result = ptr_to_jlong([[[AWTRunLoopObject alloc] init] retain]); JNF_COCOA_EXIT(env); return result; } /* * Class: sun_lwawt_macosx_LWCToolkit * Method: doAWTRunLoopImpl * Signature: (JZZ)V */ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_doAWTRunLoopImpl (JNIEnv *env, jclass clz, jlong mediator, jboolean processEvents, jboolean inAWT) { AWT_ASSERT_APPKIT_THREAD; JNF_COCOA_ENTER(env); AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator); if (mediatorObject == nil) return; // Don't use acceptInputForMode because that doesn't setup autorelease pools properly BOOL isRunning = true; while (![mediatorObject shouldEndRunLoop] && isRunning) { isRunning = [[NSRunLoop currentRunLoop] runMode:(inAWT ? [JNFRunLoop javaRunLoopMode] : NSDefaultRunLoopMode) beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.010]]; if (processEvents) { //We do not spin a runloop here as date is nil, so does not matter which mode to use NSEvent *event; if ((event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES]) != nil) { [NSApp sendEvent:event]; } } } [mediatorObject release]; JNF_COCOA_EXIT(env); } /* * Class: sun_lwawt_macosx_LWCToolkit * Method: stopAWTRunLoop * Signature: (J)V */ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_stopAWTRunLoop (JNIEnv *env, jclass clz, jlong mediator) { JNF_COCOA_ENTER(env); AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator); [ThreadUtilities performOnMainThread:@selector(endRunLoop) on:mediatorObject withObject:nil waitUntilDone:NO]; [mediatorObject release]; JNF_COCOA_EXIT(env); } /* * Class: sun_lwawt_macosx_LWCToolkit * Method: performOnMainThreadAfterDelay * Signature: (Ljava/lang/Runnable;J)V */ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_performOnMainThreadAfterDelay (JNIEnv *env, jclass clz, jobject runnable, jlong delay) { JNF_COCOA_ENTER(env); jobject gRunnable = (*env)->NewGlobalRef(env, runnable); CHECK_NULL(gRunnable); [ThreadUtilities performOnMainThreadWaiting:NO block:^() { JavaRunnable* performer = [[JavaRunnable alloc] initWithRunnable:gRunnable]; [performer performSelector:@selector(perform) withObject:nil afterDelay:(delay/1000.0)]; }]; JNF_COCOA_EXIT(env); } /* * Class: sun_lwawt_macosx_LWCToolkit * Method: isCapsLockOn * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isCapsLockOn (JNIEnv *env, jobject self) { __block jboolean isOn = JNI_FALSE; [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ NSUInteger modifiers = [NSEvent modifierFlags]; isOn = (modifiers & NSAlphaShiftKeyMask) != 0; }]; return isOn; } /* * Class: sun_lwawt_macosx_LWCToolkit * Method: isApplicationActive * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isApplicationActive (JNIEnv *env, jclass clazz) { __block jboolean active = JNI_FALSE; JNF_COCOA_ENTER(env); [ThreadUtilities performOnMainThreadWaiting:YES block:^() { active = (jboolean)[NSRunningApplication currentApplication].active; }]; JNF_COCOA_EXIT(env); return active; } /* * Class: sun_lwawt_macosx_LWCToolkit * Method: activateApplicationIgnoringOtherApps * Signature: ()V */ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_activateApplicationIgnoringOtherApps (JNIEnv *env, jclass clazz) { JNF_COCOA_ENTER(env); [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ if(![NSApp isActive]){ [NSApp activateIgnoringOtherApps:YES]; } }]; JNF_COCOA_EXIT(env); } /* * Class: sun_awt_SunToolkit * Method: closeSplashScreen * Signature: ()V */ JNIEXPORT void JNICALL Java_sun_awt_SunToolkit_closeSplashScreen(JNIEnv *env, jclass cls) { void *hSplashLib = dlopen(0, RTLD_LAZY); if (!hSplashLib) return; void (*splashClose)() = dlsym(hSplashLib, "SplashClose"); if (splashClose) { splashClose(); } dlclose(hSplashLib); } // TODO: definitely doesn't belong here (copied from fontpath.c in the // solaris tree)... JNIEXPORT jstring JNICALL Java_sun_font_FontManager_getFontPath (JNIEnv *env, jclass obj, jboolean noType1) { return JNFNSToJavaString(env, @"/Library/Fonts"); } // This isn't yet used on unix, the implementation is added since shared // code calls this method in preparation for future use. JNIEXPORT void JNICALL Java_sun_font_FontManager_populateFontFileNameMap (JNIEnv *env, jclass obj, jobject fontToFileMap, jobject fontToFamilyMap, jobject familyToFontListMap, jobject locale) { } /* * Class: sun_lwawt_macosx_LWCToolkit * Method: initIDs * Signature: ()V */ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_initIDs (JNIEnv *env, jclass klass) { JNF_COCOA_ENTER(env) gNumberOfButtons = sun_lwawt_macosx_LWCToolkit_BUTTONS; jclass inputEventClazz = (*env)->FindClass(env, "java/awt/event/InputEvent"); CHECK_NULL(inputEventClazz); jmethodID getButtonDownMasksID = (*env)->GetStaticMethodID(env, inputEventClazz, "getButtonDownMasks", "()[I"); CHECK_NULL(getButtonDownMasksID); jintArray obj = (jintArray)(*env)->CallStaticObjectMethod(env, inputEventClazz, getButtonDownMasksID); jint * tmp = (*env)->GetIntArrayElements(env, obj, JNI_FALSE); CHECK_NULL(tmp); gButtonDownMasks = (jint*)SAFE_SIZE_ARRAY_ALLOC(malloc, sizeof(jint), gNumberOfButtons); if (gButtonDownMasks == NULL) { gNumberOfButtons = 0; (*env)->ReleaseIntArrayElements(env, obj, tmp, JNI_ABORT); JNU_ThrowOutOfMemoryError(env, NULL); return; } int i; for (i = 0; i < gNumberOfButtons; i++) { gButtonDownMasks[i] = tmp[i]; } (*env)->ReleaseIntArrayElements(env, obj, tmp, 0); (*env)->DeleteLocalRef(env, obj); JNF_COCOA_EXIT(env) } /* * Class: sun_lwawt_macosx_LWCToolkit * Method: initAppkit * Signature: (Ljava/lang/ThreadGroup;)V */ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_initAppkit (JNIEnv *env, jclass klass, jobject appkitThreadGroup, jboolean headless) { JNF_COCOA_ENTER(env) [ThreadUtilities setAppkitThreadGroup:(*env)->NewGlobalRef(env, appkitThreadGroup)]; // Launcher sets this env variable if -XstartOnFirstThread is specified char envVar[80]; snprintf(envVar, sizeof(envVar), "JAVA_STARTED_ON_FIRST_THREAD_%d", getpid()); if (getenv(envVar) != NULL) { forceEmbeddedMode = YES; unsetenv(envVar); } if (isSWTInWebStart(env)) { forceEmbeddedMode = YES; } [AWTStarter start:headless ? YES : NO]; JNF_COCOA_EXIT(env) } JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { OSXAPP_SetJavaVM(vm); // We need to let Foundation know that this is a multithreaded application, if it isn't already. if (![NSThread isMultiThreaded]) { [NSThread detachNewThreadSelector:nil toTarget:nil withObject:nil]; } return JNI_VERSION_1_4; } /* * Class: sun_lwawt_macosx_LWCToolkit * Method: isEmbedded * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isEmbedded (JNIEnv *env, jclass klass) { return isEmbedded ? JNI_TRUE : JNI_FALSE; }