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