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