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