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