1 /*
   2  * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #import <dlfcn.h>
  27 #import <pthread.h>
  28 #import <objc/runtime.h>
  29 #import <Cocoa/Cocoa.h>
  30 #import <Security/AuthSession.h>
  31 #import <JavaNativeFoundation/JavaNativeFoundation.h>
  32 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
  33 
  34 #include "jni_util.h"
  35 #import "CMenuBar.h"
  36 #import "InitIDs.h"
  37 #import "LWCToolkit.h"
  38 #import "ThreadUtilities.h"
  39 #import "AWT_debug.h"
  40 #import "CSystemColors.h"
  41 #import  "NSApplicationAWT.h"
  42 #import "PropertiesUtilities.h"
  43 #import "ApplicationDelegate.h"
  44 
  45 #import "sun_lwawt_macosx_LWCToolkit.h"
  46 
  47 #import "sizecalc.h"
  48 
  49 int gNumberOfButtons;
  50 jint* gButtonDownMasks;
  51 
  52 // Indicates that the app has been started with -XstartOnFirstThread
  53 // (directly or via WebStart settings), and AWT should not run its
  54 // own event loop in this mode. Even if a loop isn't running yet,
  55 // we expect an embedder (e.g. SWT) to start it some time later.
  56 static BOOL forceEmbeddedMode = NO;
  57 
  58 // Indicates if awt toolkit is embedded into another UI toolkit
  59 static BOOL isEmbedded = NO;
  60 
  61 // This is the data necessary to have JNI_OnLoad wait for AppKit to start.
  62 static BOOL sAppKitStarted = NO;
  63 static pthread_mutex_t sAppKitStarted_mutex = PTHREAD_MUTEX_INITIALIZER;
  64 static pthread_cond_t sAppKitStarted_cv = PTHREAD_COND_INITIALIZER;
  65 
  66 @implementation AWTToolkit
  67 
  68 static long eventCount;
  69 
  70 + (long) getEventCount{
  71     return eventCount;
  72 }
  73 
  74 + (void) eventCountPlusPlus{
  75     eventCount++;
  76 }
  77 
  78 @end
  79 
  80 
  81 @interface AWTRunLoopObject : NSObject {
  82     BOOL _shouldEndRunLoop;
  83 }
  84 @end
  85 
  86 @implementation AWTRunLoopObject
  87 
  88 - (id) init {
  89     self = [super init];
  90     if (self != nil) {
  91         _shouldEndRunLoop = NO;
  92     }
  93     return self;
  94 }
  95 
  96 - (BOOL) shouldEndRunLoop {
  97     return _shouldEndRunLoop;
  98 }
  99 
 100 - (void) endRunLoop {
 101     _shouldEndRunLoop = YES;
 102 }
 103 
 104 @end
 105 
 106 @interface JavaRunnable : NSObject { }
 107 @property jobject runnable;
 108 - (id)initWithRunnable:(jobject)gRunnable;
 109 - (void)perform;
 110 @end
 111 
 112 @implementation JavaRunnable
 113 @synthesize runnable = _runnable;
 114 
 115 - (id)initWithRunnable:(jobject)gRunnable {
 116     if (self = [super init]) {
 117         self.runnable = gRunnable;
 118     }
 119     return self;
 120 }
 121 
 122 - (void)dealloc {
 123     JNIEnv *env = [ThreadUtilities getJNIEnv];
 124     if (self.runnable) {
 125         (*env)->DeleteGlobalRef(env, self.runnable);
 126     }
 127     [super dealloc];
 128 }
 129 
 130 - (void)perform {
 131     JNIEnv* env = [ThreadUtilities getJNIEnv];
 132     static JNF_CLASS_CACHE(sjc_Runnable, "java/lang/Runnable");
 133     static JNF_MEMBER_CACHE(jm_Runnable_run, sjc_Runnable, "run", "()V");
 134     JNFCallVoidMethod(env, self.runnable, jm_Runnable_run);
 135     [self release];
 136 }
 137 @end
 138 
 139 void setBusy(BOOL busy) {
 140     AWT_ASSERT_APPKIT_THREAD;
 141 
 142     JNIEnv *env = [ThreadUtilities getJNIEnv];
 143     static JNF_CLASS_CACHE(jc_AWTAutoShutdown, "sun/awt/AWTAutoShutdown");
 144 
 145     if (busy) {
 146         static JNF_STATIC_MEMBER_CACHE(jm_notifyBusyMethod, jc_AWTAutoShutdown, "notifyToolkitThreadBusy", "()V");
 147         JNFCallStaticVoidMethod(env, jm_notifyBusyMethod);
 148     } else {
 149         static JNF_STATIC_MEMBER_CACHE(jm_notifyFreeMethod, jc_AWTAutoShutdown, "notifyToolkitThreadFree", "()V");
 150         JNFCallStaticVoidMethod(env, jm_notifyFreeMethod);
 151     }
 152 }
 153 
 154 static void setUpAWTAppKit(BOOL installObservers)
 155 {
 156     if (installObservers) {
 157         AWT_STARTUP_LOG(@"Setting up busy observers");
 158 
 159         // Add CFRunLoopObservers to call into AWT so that AWT knows that the
 160         //  AWT thread (which is the AppKit main thread) is alive. This way AWT
 161         //  will not automatically shutdown.
 162         CFRunLoopObserverRef busyObserver = CFRunLoopObserverCreateWithHandler(
 163                                                NULL,                        // CFAllocator
 164                                                kCFRunLoopAfterWaiting,      // CFOptionFlags
 165                                                true,                        // repeats
 166                                                NSIntegerMax,                // order
 167                                                ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
 168                                                    setBusy(YES);
 169                                                });
 170 
 171         CFRunLoopObserverRef notBusyObserver = CFRunLoopObserverCreateWithHandler(
 172                                                 NULL,                        // CFAllocator
 173                                                 kCFRunLoopBeforeWaiting,     // CFOptionFlags
 174                                                 true,                        // repeats
 175                                                 NSIntegerMin,                // order
 176                                                 ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
 177                                                     setBusy(NO);
 178                                                 });
 179 
 180         CFRunLoopRef runLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
 181         CFRunLoopAddObserver(runLoop, busyObserver, kCFRunLoopDefaultMode);
 182         CFRunLoopAddObserver(runLoop, notBusyObserver, kCFRunLoopDefaultMode);
 183 
 184         CFRelease(busyObserver);
 185         CFRelease(notBusyObserver);
 186 
 187         setBusy(YES);
 188     }
 189 
 190     JNIEnv* env = [ThreadUtilities getJNIEnv];
 191     static JNF_CLASS_CACHE(jc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit");
 192     static JNF_STATIC_MEMBER_CACHE(jsm_installToolkitThreadInJava, jc_LWCToolkit, "installToolkitThreadInJava", "()V");
 193     JNFCallStaticVoidMethod(env, jsm_installToolkitThreadInJava);
 194 }
 195 
 196 BOOL isSWTInWebStart(JNIEnv* env) {
 197     NSString *swtWebStart = [PropertiesUtilities javaSystemPropertyForKey:@"com.apple.javaws.usingSWT" withEnv:env];
 198     return [@"true" isCaseInsensitiveLike:swtWebStart];
 199 }
 200 
 201 static void AWT_NSUncaughtExceptionHandler(NSException *exception) {
 202     NSLog(@"Apple AWT Internal Exception: %@", [exception description]);
 203 }
 204 
 205 @interface AWTStarter : NSObject
 206 + (void)start:(BOOL)headless;
 207 + (void)starter:(BOOL)onMainThread headless:(BOOL)headless;
 208 + (void)appKitIsRunning:(id)arg;
 209 @end
 210 
 211 @implementation AWTStarter
 212 
 213 + (BOOL) isConnectedToWindowServer {
 214     SecuritySessionId session_id;
 215     SessionAttributeBits session_info;
 216     OSStatus status = SessionGetInfo(callerSecuritySession, &session_id, &session_info);
 217     if (status != noErr) return NO;
 218     if (!(session_info & sessionHasGraphicAccess)) return NO;
 219     return YES;
 220 }
 221 
 222 + (BOOL) markAppAsDaemon {
 223     id jrsAppKitAWTClass = objc_getClass("JRSAppKitAWT");
 224     SEL markAppSel = @selector(markAppIsDaemon);
 225     if (![jrsAppKitAWTClass respondsToSelector:markAppSel]) return NO;
 226     return [jrsAppKitAWTClass performSelector:markAppSel] ? YES : NO;
 227 }
 228 
 229 + (void)appKitIsRunning:(id)arg {
 230     AWT_ASSERT_APPKIT_THREAD;
 231     AWT_STARTUP_LOG(@"About to message AppKit started");
 232 
 233     // Signal that AppKit has started (or is already running).
 234     pthread_mutex_lock(&sAppKitStarted_mutex);
 235     sAppKitStarted = YES;
 236     pthread_cond_signal(&sAppKitStarted_cv);
 237     pthread_mutex_unlock(&sAppKitStarted_mutex);
 238 
 239     AWT_STARTUP_LOG(@"Finished messaging AppKit started");
 240 }
 241 
 242 + (void)start:(BOOL)headless
 243 {
 244     // onMainThread is NOT the same at SWT mode!
 245     // If the JVM was started on the first thread for SWT, but the SWT loads the AWT on a secondary thread,
 246     // onMainThread here will be false but SWT mode will be true.  If we are currently on the main thread, we don't
 247     // need to throw AWT startup over to another thread.
 248     BOOL onMainThread = [NSThread isMainThread];
 249 
 250     NSString* msg = [NSString stringWithFormat:@"+[AWTStarter start headless:%d] { onMainThread:%d }", headless, onMainThread];
 251     AWT_STARTUP_LOG(msg);
 252 
 253     if (!headless)
 254     {
 255         // Listen for the NSApp to start. This indicates that JNI_OnLoad can proceed.
 256         //  It must wait because there is a chance that another java thread will grab
 257         //  the AppKit lock before the +[NSApplication sharedApplication] returns.
 258         //  See <rdar://problem/3492666> for an example.
 259         [[NSNotificationCenter defaultCenter] addObserver:[AWTStarter class]
 260                                                  selector:@selector(appKitIsRunning:)
 261                                                      name:NSApplicationDidFinishLaunchingNotification
 262                                                    object:nil];
 263 
 264         AWT_STARTUP_LOG(@"+[AWTStarter start:::]: registered NSApplicationDidFinishLaunchingNotification");
 265     }
 266 
 267     [ThreadUtilities performOnMainThreadWaiting:NO block:^() {
 268         [AWTStarter starter:onMainThread headless:headless];
 269     }];
 270 
 271 
 272     if (!headless && !onMainThread) {
 273 
 274         AWT_STARTUP_LOG(@"about to wait on AppKit startup mutex");
 275 
 276         // Wait here for AppKit to have started (or for AWT to have been loaded into
 277         //  an already running NSApplication).
 278         pthread_mutex_lock(&sAppKitStarted_mutex);
 279         while (sAppKitStarted == NO) {
 280             pthread_cond_wait(&sAppKitStarted_cv, &sAppKitStarted_mutex);
 281         }
 282         pthread_mutex_unlock(&sAppKitStarted_mutex);
 283 
 284         // AWT gets here AFTER +[AWTStarter appKitIsRunning:] is called.
 285         AWT_STARTUP_LOG(@"got out of the AppKit startup mutex");
 286     }
 287 
 288     if (!headless) {
 289         // Don't set the delegate until the NSApplication has been created and
 290         // its finishLaunching has initialized it.
 291         //  ApplicationDelegate is the support code for com.apple.eawt.
 292         [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 293             id<NSApplicationDelegate> delegate = [ApplicationDelegate sharedDelegate];
 294             if (delegate != nil) {
 295                 OSXAPP_SetApplicationDelegate(delegate);
 296             }
 297         }];
 298     }
 299 }
 300 
 301 + (void)starter:(BOOL)wasOnMainThread headless:(BOOL)headless {
 302     NSAutoreleasePool *pool = [NSAutoreleasePool new];
 303     // Add the exception handler of last resort
 304     NSSetUncaughtExceptionHandler(AWT_NSUncaughtExceptionHandler);
 305 
 306     // Headless mode trumps either ordinary AWT or SWT-in-AWT mode.  Declare us a daemon and return.
 307     if (headless) {
 308         // Note that we don't install run loop observers in headless mode
 309         // because we don't need them (see 7174704)
 310         if (!forceEmbeddedMode) {
 311             setUpAWTAppKit(false);
 312         }
 313         [AWTStarter markAppAsDaemon];
 314         return;
 315     }
 316 
 317     if (forceEmbeddedMode) {
 318         AWT_STARTUP_LOG(@"in SWT or SWT/WebStart mode");
 319 
 320         // Init a default NSApplication instance instead of the NSApplicationAWT.
 321         // Note that [NSApp isRunning] will return YES after that, though
 322         // this behavior isn't specified anywhere. We rely on that.
 323         NSApplicationLoad();
 324     }
 325 
 326     // This will create a NSApplicationAWT for standalone AWT programs, unless there is
 327     //  already a NSApplication instance. If there is already a NSApplication instance,
 328     //  and -[NSApplication isRunning] returns YES, AWT is embedded inside another
 329     //  AppKit Application.
 330     NSApplication *app = [NSApplicationAWT sharedApplication];
 331     isEmbedded = ![NSApp isKindOfClass:[NSApplicationAWT class]];
 332 
 333     if (!isEmbedded) {
 334         // Install run loop observers and set the AppKit Java thread name
 335         setUpAWTAppKit(true);
 336     }
 337 
 338     // AWT gets to this point BEFORE NSApplicationDidFinishLaunchingNotification is sent.
 339     if (![app isRunning]) {
 340         AWT_STARTUP_LOG(@"+[AWTStarter startAWT]: ![app isRunning]");
 341         // This is where the AWT AppKit thread parks itself to process events.
 342         [NSApplicationAWT runAWTLoopWithApp: app];
 343     } else {
 344         // We're either embedded, or showing a splash screen
 345         if (isEmbedded) {
 346             AWT_STARTUP_LOG(@"running embedded");
 347 
 348             // We don't track if the runloop is busy, so set it free to let AWT finish when it needs
 349             setBusy(NO);
 350         } else {
 351             AWT_STARTUP_LOG(@"running after showing a splash screen");
 352         }
 353 
 354         // Signal so that JNI_OnLoad can proceed.
 355         if (!wasOnMainThread) [AWTStarter appKitIsRunning:nil];
 356 
 357         // Proceed to exit this call as there is no reason to run the NSApplication event loop.
 358     }
 359 
 360     [pool drain];
 361 }
 362 
 363 @end
 364 
 365 /*
 366  * Class:     sun_lwawt_macosx_LWCToolkit
 367  * Method:    nativeSyncQueue
 368  * Signature: (J)Z
 369  */
 370 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_nativeSyncQueue
 371 (JNIEnv *env, jobject self, jlong timeout)
 372 {
 373     long currentEventNum = [AWTToolkit getEventCount];
 374 
 375     NSApplication* sharedApp = [NSApplication sharedApplication];
 376     if ([sharedApp isKindOfClass:[NSApplicationAWT class]]) {
 377         NSApplicationAWT* theApp = (NSApplicationAWT*)sharedApp;
 378         // We use two different API to post events to the application,
 379         //  - [NSApplication postEvent]
 380         //  - CGEventPost(), see CRobot.m
 381         // It was found that if we post an event via CGEventPost in robot and
 382         // immediately after this we will post the second event via
 383         // [NSApp postEvent] then sometimes the second event will be handled
 384         // first. The opposite isn't proved, but we use both here to be safer.
 385         [theApp postDummyEvent:false];
 386         [theApp waitForDummyEvent:timeout / 2.0];
 387         [theApp postDummyEvent:true];
 388         [theApp waitForDummyEvent:timeout / 2.0];
 389 
 390     } else {
 391         // could happen if we are embedded inside SWT application,
 392         // in this case just spin a single empty block through
 393         // the event loop to give it a chance to process pending events
 394         [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){}];
 395     }
 396 
 397     if (([AWTToolkit getEventCount] - currentEventNum) != 0) {
 398         return JNI_TRUE;
 399     }
 400 
 401     return JNI_FALSE;
 402 }
 403 
 404 /*
 405  * Class:     sun_lwawt_macosx_LWCToolkit
 406  * Method:    flushNativeSelectors
 407  * Signature: ()J
 408  */
 409 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_flushNativeSelectors
 410 (JNIEnv *env, jclass clz)
 411 {
 412 JNF_COCOA_ENTER(env);
 413         [ThreadUtilities performOnMainThreadWaiting:YES block:^(){}];
 414 JNF_COCOA_EXIT(env);
 415 }
 416 
 417 /*
 418  * Class:     sun_lwawt_macosx_LWCToolkit
 419  * Method:    beep
 420  * Signature: ()V
 421  */
 422 JNIEXPORT void JNICALL
 423 Java_sun_lwawt_macosx_LWCToolkit_beep
 424 (JNIEnv *env, jobject self)
 425 {
 426     NSBeep(); // produces both sound and visual flash, if configured in System Preferences
 427 }
 428 
 429 static UInt32 RGB(NSColor *c) {
 430     c = [c colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
 431     if (c == nil)
 432     {
 433         return -1; // opaque white
 434     }
 435 
 436     CGFloat r, g, b, a;
 437     [c getRed:&r green:&g blue:&b alpha:&a];
 438 
 439     UInt32 ir = (UInt32) (r*255+0.5),
 440     ig = (UInt32) (g*255+0.5),
 441     ib = (UInt32) (b*255+0.5),
 442     ia = (UInt32) (a*255+0.5);
 443 
 444     //    NSLog(@"%@ %d, %d, %d", c, ir, ig, ib);
 445 
 446     return ((ia & 0xFF) << 24) | ((ir & 0xFF) << 16) | ((ig & 0xFF) << 8) | ((ib & 0xFF) << 0);
 447 }
 448 
 449 BOOL doLoadNativeColors(JNIEnv *env, jintArray jColors, BOOL useAppleColors) {
 450     jint len = (*env)->GetArrayLength(env, jColors);
 451 
 452     UInt32 colorsArray[len];
 453     UInt32 *colors = colorsArray;
 454 
 455     [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
 456         NSUInteger i;
 457         for (i = 0; i < len; i++) {
 458             colors[i] = RGB([CSystemColors getColor:i useAppleColor:useAppleColors]);
 459         }
 460     }];
 461 
 462     jint *_colors = (*env)->GetPrimitiveArrayCritical(env, jColors, 0);
 463     if (_colors == NULL) {
 464         return NO;
 465     }
 466     memcpy(_colors, colors, len * sizeof(UInt32));
 467     (*env)->ReleasePrimitiveArrayCritical(env, jColors, _colors, 0);
 468     return YES;
 469 }
 470 
 471 /**
 472  * Class:     sun_lwawt_macosx_LWCToolkit
 473  * Method:    loadNativeColors
 474  * Signature: ([I[I)V
 475  */
 476 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_loadNativeColors
 477 (JNIEnv *env, jobject peer, jintArray jSystemColors, jintArray jAppleColors)
 478 {
 479 JNF_COCOA_ENTER(env);
 480     if (doLoadNativeColors(env, jSystemColors, NO)) {
 481         doLoadNativeColors(env, jAppleColors, YES);
 482     }
 483 JNF_COCOA_EXIT(env);
 484 }
 485 
 486 /*
 487  * Class:     sun_lwawt_macosx_LWCToolkit
 488  * Method:    createAWTRunLoopMediator
 489  * Signature: ()J
 490  */
 491 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_LWCToolkit_createAWTRunLoopMediator
 492 (JNIEnv *env, jclass clz)
 493 {
 494 AWT_ASSERT_APPKIT_THREAD;
 495 
 496     jlong result;
 497 
 498 JNF_COCOA_ENTER(env);
 499     // We double retain because this object is owned by both main thread and "other" thread
 500     // We release in both doAWTRunLoop and stopAWTRunLoop
 501     result = ptr_to_jlong([[[AWTRunLoopObject alloc] init] retain]);
 502 JNF_COCOA_EXIT(env);
 503 
 504     return result;
 505 }
 506 
 507 /*
 508  * Class:     sun_lwawt_macosx_LWCToolkit
 509  * Method:    doAWTRunLoopImpl
 510  * Signature: (JZZ)V
 511  */
 512 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_doAWTRunLoopImpl
 513 (JNIEnv *env, jclass clz, jlong mediator, jboolean processEvents, jboolean inAWT)
 514 {
 515 AWT_ASSERT_APPKIT_THREAD;
 516 JNF_COCOA_ENTER(env);
 517 
 518     AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator);
 519 
 520     if (mediatorObject == nil) return;
 521 
 522     // Don't use acceptInputForMode because that doesn't setup autorelease pools properly
 523     BOOL isRunning = true;
 524     while (![mediatorObject shouldEndRunLoop] && isRunning) {
 525         isRunning = [[NSRunLoop currentRunLoop] runMode:(inAWT ? [JNFRunLoop javaRunLoopMode] : NSDefaultRunLoopMode)
 526                                              beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.010]];
 527         if (processEvents) {
 528             //We do not spin a runloop here as date is nil, so does not matter which mode to use
 529             // Processing all events excluding NSApplicationDefined which need to be processed
 530             // on the main loop only (those events are intended for disposing resources)
 531             NSEvent *event;
 532             if ((event = [NSApp nextEventMatchingMask:(NSAnyEventMask & ~NSApplicationDefined)
 533                                            untilDate:nil
 534                                               inMode:NSDefaultRunLoopMode
 535                                              dequeue:YES]) != nil) {
 536                 [NSApp sendEvent:event];
 537             }
 538 
 539         }
 540     }
 541     [mediatorObject release];
 542 JNF_COCOA_EXIT(env);
 543 }
 544 
 545 /*
 546  * Class:     sun_lwawt_macosx_LWCToolkit
 547  * Method:    stopAWTRunLoop
 548  * Signature: (J)V
 549  */
 550 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_stopAWTRunLoop
 551 (JNIEnv *env, jclass clz, jlong mediator)
 552 {
 553 JNF_COCOA_ENTER(env);
 554 
 555     AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator);
 556 
 557     [ThreadUtilities performOnMainThread:@selector(endRunLoop) on:mediatorObject withObject:nil waitUntilDone:NO];
 558 
 559     [mediatorObject release];
 560 
 561 JNF_COCOA_EXIT(env);
 562 }
 563 
 564 /*
 565  * Class:     sun_lwawt_macosx_LWCToolkit
 566  * Method:    performOnMainThreadAfterDelay
 567  * Signature: (Ljava/lang/Runnable;J)V
 568  */
 569 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_performOnMainThreadAfterDelay
 570 (JNIEnv *env, jclass clz, jobject runnable, jlong delay)
 571 {
 572 JNF_COCOA_ENTER(env);
 573     jobject gRunnable = (*env)->NewGlobalRef(env, runnable);
 574     CHECK_NULL(gRunnable);
 575     [ThreadUtilities performOnMainThreadWaiting:NO block:^() {
 576         JavaRunnable* performer = [[JavaRunnable alloc] initWithRunnable:gRunnable];
 577         [performer performSelector:@selector(perform) withObject:nil afterDelay:(delay/1000.0)];
 578     }];
 579 JNF_COCOA_EXIT(env);
 580 }
 581 
 582 
 583 /*
 584  * Class:     sun_lwawt_macosx_LWCToolkit
 585  * Method:    isCapsLockOn
 586  * Signature: ()Z
 587  */
 588 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isCapsLockOn
 589 (JNIEnv *env, jobject self)
 590 {
 591     __block jboolean isOn = JNI_FALSE;
 592     [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
 593         NSUInteger modifiers = [NSEvent modifierFlags];
 594         isOn = (modifiers & NSAlphaShiftKeyMask) != 0;
 595     }];
 596 
 597     return isOn;
 598 }
 599 
 600 /*
 601  * Class:     sun_lwawt_macosx_LWCToolkit
 602  * Method:    isApplicationActive
 603  * Signature: ()Z
 604  */
 605 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isApplicationActive
 606 (JNIEnv *env, jclass clazz)
 607 {
 608     __block jboolean active = JNI_FALSE;
 609 
 610 JNF_COCOA_ENTER(env);
 611 
 612     [ThreadUtilities performOnMainThreadWaiting:YES block:^() {
 613         active = (jboolean)[NSRunningApplication currentApplication].active;
 614     }];
 615 
 616 JNF_COCOA_EXIT(env);
 617 
 618     return active;
 619 }
 620 
 621 /*
 622  * Class:     sun_lwawt_macosx_LWCToolkit
 623  * Method:    activateApplicationIgnoringOtherApps
 624  * Signature: ()V
 625  */
 626 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_activateApplicationIgnoringOtherApps
 627 (JNIEnv *env, jclass clazz)
 628 {
 629     JNF_COCOA_ENTER(env);
 630     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 631         if(![NSApp isActive]){
 632             [NSApp activateIgnoringOtherApps:YES];
 633         }
 634     }];
 635     JNF_COCOA_EXIT(env);
 636 }
 637 
 638 
 639 /*
 640  * Class:     sun_awt_SunToolkit
 641  * Method:    closeSplashScreen
 642  * Signature: ()V
 643  */
 644 JNIEXPORT void JNICALL
 645 Java_sun_awt_SunToolkit_closeSplashScreen(JNIEnv *env, jclass cls)
 646 {
 647     void *hSplashLib = dlopen(0, RTLD_LAZY);
 648     if (!hSplashLib) return;
 649 
 650     void (*splashClose)() = dlsym(hSplashLib, "SplashClose");
 651     if (splashClose) {
 652         splashClose();
 653     }
 654     dlclose(hSplashLib);
 655 }
 656 
 657 
 658 // TODO: definitely doesn't belong here (copied from fontpath.c in the
 659 // solaris tree)...
 660 
 661 JNIEXPORT jstring JNICALL
 662 Java_sun_font_FontManager_getFontPath
 663 (JNIEnv *env, jclass obj, jboolean noType1)
 664 {
 665     return JNFNSToJavaString(env, @"/Library/Fonts");
 666 }
 667 
 668 // This isn't yet used on unix, the implementation is added since shared
 669 // code calls this method in preparation for future use.
 670 JNIEXPORT void JNICALL
 671 Java_sun_font_FontManager_populateFontFileNameMap
 672 (JNIEnv *env, jclass obj, jobject fontToFileMap, jobject fontToFamilyMap, jobject familyToFontListMap, jobject locale)
 673 {
 674 
 675 }
 676 
 677 /*
 678  * Class:     sun_lwawt_macosx_LWCToolkit
 679  * Method:    initIDs
 680  * Signature: ()V
 681  */
 682 JNIEXPORT void JNICALL
 683 Java_sun_lwawt_macosx_LWCToolkit_initIDs
 684 (JNIEnv *env, jclass klass) {
 685 
 686     JNF_COCOA_ENTER(env)
 687 
 688     gNumberOfButtons = sun_lwawt_macosx_LWCToolkit_BUTTONS;
 689 
 690     jclass inputEventClazz = (*env)->FindClass(env, "java/awt/event/InputEvent");
 691     CHECK_NULL(inputEventClazz);
 692     jmethodID getButtonDownMasksID = (*env)->GetStaticMethodID(env, inputEventClazz, "getButtonDownMasks", "()[I");
 693     CHECK_NULL(getButtonDownMasksID);
 694     jintArray obj = (jintArray)(*env)->CallStaticObjectMethod(env, inputEventClazz, getButtonDownMasksID);
 695     jint * tmp = (*env)->GetIntArrayElements(env, obj, JNI_FALSE);
 696     CHECK_NULL(tmp);
 697 
 698     gButtonDownMasks = (jint*)SAFE_SIZE_ARRAY_ALLOC(malloc, sizeof(jint), gNumberOfButtons);
 699     if (gButtonDownMasks == NULL) {
 700         gNumberOfButtons = 0;
 701         (*env)->ReleaseIntArrayElements(env, obj, tmp, JNI_ABORT);
 702         JNU_ThrowOutOfMemoryError(env, NULL);
 703         return;
 704     }
 705 
 706     int i;
 707     for (i = 0; i < gNumberOfButtons; i++) {
 708         gButtonDownMasks[i] = tmp[i];
 709     }
 710 
 711     (*env)->ReleaseIntArrayElements(env, obj, tmp, 0);
 712     (*env)->DeleteLocalRef(env, obj);
 713 
 714     JNF_COCOA_EXIT(env)
 715 }
 716 
 717 /*
 718  * Class:     sun_lwawt_macosx_LWCToolkit
 719  * Method:    initAppkit
 720  * Signature: (Ljava/lang/ThreadGroup;)V
 721  */
 722 JNIEXPORT void JNICALL
 723 Java_sun_lwawt_macosx_LWCToolkit_initAppkit
 724 (JNIEnv *env, jclass klass, jobject appkitThreadGroup, jboolean headless) {
 725     JNF_COCOA_ENTER(env)
 726 
 727     [ThreadUtilities setAppkitThreadGroup:(*env)->NewGlobalRef(env, appkitThreadGroup)];
 728 
 729     // Launcher sets this env variable if -XstartOnFirstThread is specified
 730     char envVar[80];
 731     snprintf(envVar, sizeof(envVar), "JAVA_STARTED_ON_FIRST_THREAD_%d", getpid());
 732     if (getenv(envVar) != NULL) {
 733         forceEmbeddedMode = YES;
 734         unsetenv(envVar);
 735     }
 736 
 737     if (isSWTInWebStart(env)) {
 738         forceEmbeddedMode = YES;
 739     }
 740 
 741     [AWTStarter start:headless ? YES : NO];
 742 
 743     JNF_COCOA_EXIT(env)
 744 }
 745 
 746 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
 747     OSXAPP_SetJavaVM(vm);
 748 
 749     // We need to let Foundation know that this is a multithreaded application, if it isn't already.
 750     if (![NSThread isMultiThreaded]) {
 751         [NSThread detachNewThreadSelector:nil toTarget:nil withObject:nil];
 752     }
 753 
 754     return JNI_VERSION_1_4;
 755 }
 756 
 757 /*
 758  * Class:     sun_lwawt_macosx_LWCToolkit
 759  * Method:    isEmbedded
 760  * Signature: ()Z
 761  */
 762 JNIEXPORT jboolean JNICALL
 763 Java_sun_lwawt_macosx_LWCToolkit_isEmbedded
 764 (JNIEnv *env, jclass klass) {
 765     return isEmbedded ? JNI_TRUE : JNI_FALSE;
 766 }
 767