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