src/macosx/native/sun/awt/awt.m

Print this page

        

@@ -40,10 +40,13 @@
 
 
 // The symbol is defined in libosxapp.dylib (ThreadUtilities.m)
 extern JavaVM *jvm;
 
+// Indicates if AWT is running embedded (in SWT, FX, elsewhere)
+static BOOL isEmbedded = NO;
+
 static bool ShouldPrintVerboseDebugging() {
     static int debug = -1;
     if (debug == -1) {
         debug = (int)(getenv("JAVA_AWT_VERBOSE") != NULL) || (DEBUG != 0);
     }

@@ -61,17 +64,12 @@
 static void AWT_NSUncaughtExceptionHandler(NSException *exception);
 
 static CFRunLoopObserverRef busyObserver = NULL;
 static CFRunLoopObserverRef notBusyObserver = NULL;
 
-static void setUpAWTAppKit(BOOL swt_mode, BOOL headless) {
-AWT_ASSERT_APPKIT_THREAD;
-    BOOL verbose = ShouldPrintVerboseDebugging();
-    if (verbose) AWT_DEBUG_LOG(@"setting up busy observers");
-
-    JNIEnv *env = [ThreadUtilities getJNIEnv];
-
+static void setUpAWTAppKit(JNIEnv *env)
+{
     // 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.
     busyObserver = CFRunLoopObserverCreate(
                         NULL,                        // CFAllocator

@@ -94,18 +92,18 @@
     CFRunLoopAddObserver(runLoop, notBusyObserver, kCFRunLoopDefaultMode);
 
     CFRelease(busyObserver);
     CFRelease(notBusyObserver);
     
-    if (!headless) setBusy(YES);
+    setBusy(YES);
+
 
     // Set the java name of the AppKit main thread appropriately.
     jclass threadClass = NULL;
     jstring name = NULL;
     jobject curThread = NULL;
 
-    if (!swt_mode) {
         threadClass = (*env)->FindClass(env, "java/lang/Thread");
         if (threadClass == NULL || (*env)->ExceptionCheck(env)) goto cleanup;
         jmethodID currentThreadID = (*env)->GetStaticMethodID(env, threadClass, "currentThread", "()Ljava/lang/Thread;");
         if (currentThreadID == NULL || (*env)->ExceptionCheck(env)) goto cleanup;
         jmethodID setName = (*env)->GetMethodID(env, threadClass, "setName", "(Ljava/lang/String;)V");

@@ -115,11 +113,10 @@
         if (curThread == NULL || (*env)->ExceptionCheck(env)) goto cleanup;
         name = (*env)->NewStringUTF(env, "AWT-AppKit");
         if (name == NULL || (*env)->ExceptionCheck(env)) goto cleanup;
         (*env)->CallVoidMethod(env, curThread, setName, name); // AWT_THREADING Safe (known object)
         if ((*env)->ExceptionCheck(env)) goto cleanup;
-    }
 
 cleanup:
     if (threadClass != NULL) {
         (*env)->DeleteLocalRef(env, threadClass);
     }

@@ -131,34 +128,23 @@
     }
     if ((*env)->ExceptionCheck(env)) {
         (*env)->ExceptionDescribe(env);
         (*env)->ExceptionClear(env);
     }
-
-    // Add the exception handler of last resort
-    NSSetUncaughtExceptionHandler(AWT_NSUncaughtExceptionHandler);
-
-    if (verbose) AWT_DEBUG_LOG(@"finished setting thread name");
 }
 
 
-
 // Returns true if java believes it is running headless
 BOOL isHeadless(JNIEnv *env) {
     // Just access the property directly, instead of using GraphicsEnvironment.isHeadless.
     //  This is because this may be called while AWT is being loaded, and calling AWT
     //  while it is being loaded will deadlock.
     static JNF_CLASS_CACHE(jc_Toolkit, "java/awt/GraphicsEnvironment");
     static JNF_STATIC_MEMBER_CACHE(jm_isHeadless, jc_Toolkit, "isHeadless", "()Z");
     return JNFCallStaticBooleanMethod(env, jm_isHeadless);
 }
 
-BOOL isSWTInWebStart(JNIEnv* env) {
-    NSString *swtWebStart = [PropertiesUtilities javaSystemPropertyForKey:@"com.apple.javaws.usingSWT" withEnv:env];
-    return [@"true" isCaseInsensitiveLike:swtWebStart];
-}
-
 void setBusy(BOOL busy) {
 AWT_ASSERT_APPKIT_THREAD;
 
     JNIEnv *env = [ThreadUtilities getJNIEnv];
     static JNF_CLASS_CACHE(jc_AWTAutoShutdown, "sun/awt/AWTAutoShutdown");

@@ -198,11 +184,11 @@
     NSLog(@"Apple AWT Internal Exception: %@", [exception description]);
 }
 
 // This is an empty Obj-C object just so that -peformSelectorOnMainThread can be used.
 @interface AWTStarter : NSObject { }
-+ (void)start:(BOOL)headless swtMode:(BOOL)swtMode swtModeForWebStart:(BOOL)swtModeForWebStart;
++ (void)start:(BOOL)headless;
 - (void)starter:(NSArray*)args;
 + (void)appKitIsRunning:(id)arg;
 @end
 
 @implementation AWTStarter

@@ -240,11 +226,11 @@
     pthread_mutex_unlock(&sAppKitStarted_mutex);
 
     if (verbose) AWT_DEBUG_LOG(@"finished messaging AppKit started");
 }
 
-+ (void)start:(BOOL)headless swtMode:(BOOL)swtMode swtModeForWebStart:(BOOL)swtModeForWebStart
++ (void)start:(BOOL)headless
 {
     BOOL verbose = ShouldPrintVerboseDebugging();
 
     // Headless: BOTH
     // Embedded: BOTH

@@ -256,11 +242,11 @@
     // 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 = (pthread_main_np() != 0);
 
     if (verbose) {
-        NSString *msg = [NSString stringWithFormat:@"+[AWTStarter start headless:%d swtMode:%d swtModeForWebStart:%d] { onMainThread:%d }", headless, swtMode, swtModeForWebStart, onMainThread];
+        NSString *msg = [NSString stringWithFormat:@"+[AWTStarter start headless:%d] { onMainThread:%d }", headless, onMainThread];
         AWT_DEBUG_LOG(msg);
     }
 
     if (!headless)
     {

@@ -278,13 +264,11 @@
 
     id st = [[AWTStarter alloc] init];
 
     NSArray * args = [NSArray arrayWithObjects:
                       [NSNumber numberWithBool: onMainThread],
-                      [NSNumber numberWithBool: swtMode],
                       [NSNumber numberWithBool: headless],
-                      [NSNumber numberWithBool: swtModeForWebStart],
                       [NSNumber numberWithBool: verbose],
                       nil];
 
     if (onMainThread) {
         [st starter:args];

@@ -322,57 +306,67 @@
 
 - (void)starter:(NSArray*)args {
     NSAutoreleasePool *pool = [NSAutoreleasePool new];
 
     BOOL onMainThread = [[args objectAtIndex:0] boolValue];
-    BOOL swtMode = [[args objectAtIndex:1] boolValue];
-    BOOL headless = [[args objectAtIndex:2] boolValue];
-    BOOL swtModeForWebStart = [[args objectAtIndex:3] boolValue];
-    BOOL verbose = [[args objectAtIndex:4] boolValue];
+    BOOL headless = [[args objectAtIndex:1] boolValue];
+    BOOL verbose = [[args objectAtIndex:2] boolValue];
 
     BOOL wasOnMainThread = onMainThread;
 
-    setUpAWTAppKit(swtMode, headless);
+    // 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) {
         BOOL didBecomeDaemon = [AWTStarter markAppAsDaemon];
         return;
     }
 
-    if (swtMode || swtModeForWebStart) {
-        if (verbose) NSLog(@"in SWT or SWT/WebStart mode");
-
-        // The SWT should call NSApplicationLoad, but they don't know a priori that they will be using the AWT, so they don't.
-        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]];
+
+    JNIEnv *env = [ThreadUtilities getJNIEnv];
+    if (isEmbedded) {
+        static JNF_CLASS_CACHE(jc_AWTKeepAlive, "sun/lwawt/macosx/AWTKeepAlive");
+        static JNF_STATIC_MEMBER_CACHE(jm_activate, jc_AWTKeepAlive, "activate", "()V");
+
+        // This will send native events every 0.5 s, thus letting the embedder know
+        // that AWT is alive. The events are only sent while there are active
+        // AWT windows present.
+        JNFCallStaticVoidMethod(env, jm_activate);
+    } else {
+        // Install run loop observers and set the AppKit Java thread name
+        setUpAWTAppKit(env);
+    }
 
     // AWT gets to this point BEFORE NSApplicationDidFinishLaunchingNotification is sent.
     if (![app isRunning]) {
         if (verbose) AWT_DEBUG_LOG(@"+[AWTStarter startAWT]: ![app isRunning]");
 
+        // Note that in theory we can get here even if we're embedded and an
+        // embedder isn't running an event loop yet for some reason.  However,
+        // it seems to be very unlikely. In any case, the runAWTLoopWithApp is
+        // able to deal with it anyway.  Whether the embedder can deal with
+        // this is unknown.  Also, it's unclear how the event loop is going to
+        // be terminated in this case. Setting up observers is not an option
+        // since the embedder could force termination. We wouldn't know and
+        // could crash when calling to Java.
+
         // 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 (![NSApp isKindOfClass:[NSApplicationAWT class]]) {
+        if (isEmbedded) {
             if (verbose) AWT_DEBUG_LOG(@"running embedded");
 
-            // Since we're embedded, no need to be swamping the runloop with the observers.
-            CFRunLoopRef runLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
-            CFRunLoopRemoveObserver(runLoop, busyObserver, kCFRunLoopDefaultMode);
-            CFRunLoopRemoveObserver(runLoop, notBusyObserver, kCFRunLoopDefaultMode);
             // We don't track if the runloop is busy, so set it free to let AWT finish when it needs
             setBusy(NO);
-            busyObserver = NULL;
-            notBusyObserver = NULL;
         } else {
             if (verbose) AWT_DEBUG_LOG(@"running after showing a splash screen");
         }
 
         // Signal so that JNI_OnLoad can proceed.

@@ -406,53 +400,28 @@
     if (status != JNI_OK || env == NULL) {
         AWT_DEBUG_LOG(@"Can't get JNIEnv");
         return JNI_VERSION_1_4;
     }
 
-    // The following is true when AWT is attempting to connect to the window server
-    // when it isn't set up properly to do so.
-    // BOOL AWTLoadFailure = YES;    For now we are skipping this check so i'm commenting out this variable as unused
 JNF_COCOA_ENTER(env);
 
-    // If -XstartOnFirstThread was used at invocation time, an environment variable will be set.
-    // (See java_md.c for the matching setenv call.) When that happens, we assume the SWT will be in use.
-    BOOL swt_compatible_mode = NO;
-
     char envVar[80];
     snprintf(envVar, sizeof(envVar), "JAVA_STARTED_ON_FIRST_THREAD_%d", getpid());
     if (getenv(envVar) != NULL) {
-        swt_compatible_mode = YES;
+        // If we don't need this in the long term, it makes sense to not set
+        // this env variable in the launcher code in the first place
         unsetenv(envVar);
     }
 
-    BOOL swt_in_webstart = isSWTInWebStart(env);
     BOOL headless = isHeadless(env);
 
-    // Make sure we're on the right thread.  If not, we still need the JNIEnv to throw an exception.
-    if (pthread_main_np() != 0 && !swt_compatible_mode && !headless) {
-        AWT_DEBUG_LOG(@"Apple AWT Java VM was loaded on first thread -- can't start AWT.");
-        [JNFException raise:env as:kInternalError reason:"Can't start the AWT because Java was started on the first thread.  Make sure StartOnFirstThread is "
-         "not specified in your application's Info.plist or on the command line"];
-        return JNI_VERSION_1_4;
-    }
-
     // 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];
     }
 
-//    if (swt_compatible_mode || headless || [AWTStarter isConnectedToWindowServer] || [AWTStarter isRemoteSession]) {
-// No need in this check - we will try to launch AWTStarter anyways - to be able to run GUI application remotely
-//        AWTLoadFailure = NO;
-
-    [AWTStarter start:headless swtMode:swt_compatible_mode swtModeForWebStart:swt_in_webstart];
-
-//    }
-
-/*    if (AWTLoadFailure) { // We will not reach this code anyways
-        [JNFException raise:env as:kInternalError reason:"Can't connect to window server - not enough permissions."];
-    } */
+    [AWTStarter start:headless];
 
 JNF_COCOA_EXIT(env);
 
     if (verbose) AWT_DEBUG_LOG(@"exiting JNI_OnLoad");