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