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