1 /* 2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #import "common.h" 27 #import "com_sun_glass_ui_Application.h" 28 #import "com_sun_glass_ui_mac_MacApplication.h" 29 #import "com_sun_glass_events_KeyEvent.h" 30 31 32 #import "GlassMacros.h" 33 #import "GlassApplication.h" 34 #import "GlassHelper.h" 35 #import "GlassKey.h" 36 #import "GlassScreen.h" 37 #import "GlassWindow.h" 38 #import "GlassTouches.h" 39 #import "RemoteLayerSupport.h" 40 41 #import "ProcessInfo.h" 42 #import <Security/SecRequirement.h> 43 44 //#define VERBOSE 45 #ifndef VERBOSE 46 #define LOG(MSG, ...) 47 #else 48 #define LOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__); 49 #endif 50 51 //#define VERBOSE_LOAD 52 53 static BOOL shouldKeepRunningNestedLoop = YES; 54 static jobject nestedLoopReturnValue = NULL; 55 static BOOL isFullScreenExitingLoop = NO; 56 static NSMutableDictionary * keyCodeForCharMap = nil; 57 static BOOL isEmbedded = NO; 58 static BOOL disableSyncRendering = NO; 59 60 jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) 61 { 62 pthread_key_create(&GlassThreadDataKey, NULL); 63 64 memset(&javaIDs, 0, sizeof(javaIDs)); 65 MAIN_JVM = vm; 66 return JNI_VERSION_1_4; 67 } 68 69 #pragma mark --- GlassRunnable 70 71 @interface GlassRunnable : NSObject 72 { 73 jobject jRunnable; 74 } 75 76 - (id)initWithRunnable:(jobject)runnable; 77 - (void)run; 78 79 @end 80 81 @implementation GlassRunnable 82 83 - (id)initWithRunnable:(jobject)runnable 84 { 85 self->jRunnable = runnable; 86 return self; 87 } 88 89 - (void)run 90 { 91 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 92 { 93 assert(pthread_main_np() == 1); 94 JNIEnv *env = jEnv; 95 if (env != NULL) 96 { 97 (*env)->CallVoidMethod(env, self->jRunnable, jRunnableRun); 98 GLASS_CHECK_EXCEPTION(env); 99 } 100 101 [self release]; 102 } 103 [pool drain]; 104 } 105 106 - (void)dealloc 107 { 108 assert(pthread_main_np() == 1); 109 JNIEnv *env = jEnv; 110 if (env != NULL) 111 { 112 (*env)->DeleteGlobalRef(env, self->jRunnable); 113 } 114 self->jRunnable = NULL; 115 116 [super dealloc]; 117 } 118 119 @end 120 121 #pragma mark --- GlassApplication 122 123 @implementation GlassApplication 124 125 - (id)initWithEnv:(JNIEnv*)env application:(jobject)application launchable:(jobject)launchable taskbarApplication:(jboolean)isTaskbarApplication classLoader:(jobject)classLoader 126 { 127 self = [super init]; 128 if (self != nil) 129 { 130 self->started = NO; 131 self->jTaskBarApp = isTaskbarApplication; 132 133 self->jApplication = (*env)->NewGlobalRef(env, application); 134 if (launchable != NULL) 135 { 136 self->jLaunchable = (*env)->NewGlobalRef(env, launchable); 137 } 138 139 if (classLoader != NULL) 140 { 141 [GlassHelper SetGlassClassLoader:classLoader withEnv:env]; 142 } 143 } 144 return self; 145 } 146 147 #pragma mark --- delegate methods 148 149 - (void)GlassApplicationDidChangeScreenParameters 150 { 151 LOG("GlassApplicationDidChangeScreenParameters"); 152 153 GET_MAIN_JENV; 154 GlassScreenDidChangeScreenParameters(env); 155 } 156 157 - (void)applicationWillFinishLaunching:(NSNotification *)aNotification 158 { 159 LOG("GlassApplication:applicationWillFinishLaunching"); 160 161 GET_MAIN_JENV; 162 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 163 { 164 if (self->jLaunchable != NULL) 165 { 166 jclass runnableClass = [GlassHelper ClassForName:"java.lang.Runnable" withEnv:jEnv]; 167 if ((*env)->ExceptionCheck(env) == JNI_TRUE) 168 { 169 (*env)->ExceptionDescribe(env); 170 (*env)->ExceptionClear(env); 171 } 172 173 jmethodID runMethod = (*env)->GetMethodID(env, runnableClass, "run", "()V"); 174 if ((*env)->ExceptionCheck(env) == JNI_TRUE) 175 { 176 (*env)->ExceptionDescribe(env); 177 (*env)->ExceptionClear(env); 178 } 179 180 if ((runnableClass != 0) && (runMethod != 0)) 181 { 182 (*env)->CallVoidMethod(env, self->jLaunchable, runMethod); 183 if ((*env)->ExceptionCheck(env) == JNI_TRUE) 184 { 185 (*env)->ExceptionDescribe(env); 186 (*env)->ExceptionClear(env); 187 } 188 else 189 { 190 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(GlassApplicationDidChangeScreenParameters) name:NSApplicationDidChangeScreenParametersNotification object:nil]; 191 } 192 } 193 else if (runnableClass == 0) 194 { 195 NSLog(@"ERROR: Glass could not find Runnable class\n"); 196 } 197 else //if (runMethod == 0) 198 { 199 NSLog(@"ERROR: Glass could not find run() method\n"); 200 } 201 } 202 203 (*env)->CallVoidMethod(env, self->jApplication, [GlassHelper ApplicationNotifyWillFinishLaunchingMethod]); 204 205 self->started = YES; 206 } 207 [pool drain]; 208 GLASS_CHECK_EXCEPTION(env); 209 } 210 211 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 212 { 213 LOG("GlassApplication:applicationDidFinishLaunching"); 214 215 GET_MAIN_JENV; 216 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 217 { 218 (*env)->CallVoidMethod(env, self->jApplication, [GlassHelper ApplicationNotifyDidFinishLaunchingMethod]); 219 } 220 [pool drain]; 221 GLASS_CHECK_EXCEPTION(env); 222 } 223 224 - (void)applicationWillBecomeActive:(NSNotification *)aNotification 225 { 226 LOG("GlassApplication:applicationWillBecomeActive"); 227 228 GET_MAIN_JENV; 229 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 230 { 231 (*env)->CallVoidMethod(env, self->jApplication, [GlassHelper ApplicationNotifyWillBecomeActiveMethod]); 232 } 233 [pool drain]; 234 GLASS_CHECK_EXCEPTION(env); 235 } 236 237 - (void)applicationDidBecomeActive:(NSNotification *)aNotification 238 { 239 LOG("GlassApplication:applicationDidBecomeActive"); 240 241 GET_MAIN_JENV; 242 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 243 { 244 (*env)->CallVoidMethod(env, self->jApplication, [GlassHelper ApplicationNotifyDidBecomeActiveMethod]); 245 } 246 [pool drain]; 247 GLASS_CHECK_EXCEPTION(env); 248 } 249 250 - (void)applicationWillResignActive:(NSNotification *)aNotification 251 { 252 LOG("GlassApplication:applicationWillResignActive"); 253 254 GET_MAIN_JENV; 255 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 256 { 257 (*env)->CallVoidMethod(env, self->jApplication, [GlassHelper ApplicationNotifyWillResignActiveMethod]); 258 } 259 [pool drain]; 260 GLASS_CHECK_EXCEPTION(env); 261 } 262 263 - (void)applicationDidResignActive:(NSNotification *)aNotification 264 { 265 LOG("GlassApplication:applicationDidResignActive"); 266 267 GET_MAIN_JENV; 268 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 269 { 270 (*env)->CallVoidMethod(env, self->jApplication, [GlassHelper ApplicationNotifyDidResignActiveMethod]); 271 } 272 [pool drain]; 273 GLASS_CHECK_EXCEPTION(env); 274 } 275 276 - (void)applicationWillHide:(NSNotification *)aNotification 277 { 278 LOG("GlassApplication:applicationWillHide"); 279 280 GET_MAIN_JENV; 281 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 282 { 283 (*env)->CallVoidMethod(env, self->jApplication, [GlassHelper ApplicationNotifyWillHideMethod]); 284 } 285 [pool drain]; 286 GLASS_CHECK_EXCEPTION(env); 287 } 288 289 - (void)applicationDidHide:(NSNotification *)aNotification 290 { 291 LOG("GlassApplication:applicationDidHide"); 292 293 GET_MAIN_JENV; 294 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 295 { 296 (*env)->CallVoidMethod(env, self->jApplication, [GlassHelper ApplicationNotifyDidHideMethod]); 297 } 298 [pool drain]; 299 GLASS_CHECK_EXCEPTION(env); 300 } 301 302 - (void)applicationWillUnhide:(NSNotification *)aNotification 303 { 304 LOG("GlassApplication:applicationWillUnhide"); 305 306 GET_MAIN_JENV; 307 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 308 { 309 (*env)->CallVoidMethod(env, self->jApplication, [GlassHelper ApplicationNotifyWillUnhideMethod]); 310 } 311 [pool drain]; 312 GLASS_CHECK_EXCEPTION(env); 313 } 314 315 - (void)applicationDidUnhide:(NSNotification *)aNotification 316 { 317 LOG("GlassApplication:applicationDidUnhide"); 318 319 GET_MAIN_JENV; 320 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 321 { 322 (*env)->CallVoidMethod(env, self->jApplication, [GlassHelper ApplicationNotifyDidUnhideMethod]); 323 } 324 [pool drain]; 325 GLASS_CHECK_EXCEPTION(env); 326 } 327 328 - (void)application:(NSApplication *)theApplication openFiles:(NSArray *)filenames 329 { 330 LOG("GlassApplication:application:openFiles"); 331 332 GET_MAIN_JENV; 333 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 334 { 335 NSUInteger count = [filenames count]; 336 jobjectArray files = (*env)->NewObjectArray(env, (jsize)count, [GlassHelper ClassForName:"java.lang.String" withEnv:env], NULL); 337 GLASS_CHECK_EXCEPTION(env); 338 for (NSUInteger i=0; i<count; i++) 339 { 340 NSString *file = [filenames objectAtIndex:i]; 341 if (file != nil) 342 { 343 (*env)->SetObjectArrayElement(env, files, (jsize)i, (*env)->NewStringUTF(env, [file UTF8String])); 344 GLASS_CHECK_EXCEPTION(env); 345 } 346 } 347 (*env)->CallVoidMethod(env, self->jApplication, [GlassHelper ApplicationNotifyOpenFilesMethod], files); 348 } 349 [pool drain]; 350 GLASS_CHECK_EXCEPTION(env); 351 352 [theApplication replyToOpenOrPrint:NSApplicationDelegateReplySuccess]; 353 } 354 355 - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename 356 { 357 LOG("GlassApplication:application:openFile"); 358 359 // controlled by Info.plist -NSOpenfileName 360 // http://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPRuntimeConfig/Articles/ConfigApplications.html 361 [self application:theApplication openFiles:[NSArray arrayWithObject:filename]]; 362 363 return YES; 364 } 365 366 - (BOOL)application:(id)theApplication openFileWithoutUI:(NSString *)filename 367 { 368 LOG("GlassApplication:application:openFileWithoutUI"); 369 370 // programmaticaly called by the client (even though GlassApplication does not currently call it, let's wire it in just in case) 371 [self application:theApplication openFiles:[NSArray arrayWithObject:filename]]; 372 373 return YES; 374 } 375 376 - (BOOL)application:(NSApplication *)theApplication openTempFile:(NSString *)filename 377 { 378 LOG("GlassApplication:application:openTempFile"); 379 380 // controlled by Info.plist -NSOpenTempfileName 381 // http://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPRuntimeConfig/Articles/ConfigApplications.html 382 // NOP 383 384 return YES; 385 } 386 387 - (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender 388 { 389 LOG("GlassApplication:applicationShouldOpenUntitledFile"); 390 391 // don't want 392 393 return NO; 394 } 395 396 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender 397 { 398 LOG("GlassApplication:applicationShouldTerminate"); 399 400 GET_MAIN_JENV; 401 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 402 { 403 (*env)->CallVoidMethod(env, self->jApplication, [GlassHelper ApplicationNotifyWillQuitMethod]); 404 } 405 [pool drain]; 406 GLASS_CHECK_EXCEPTION(env); 407 408 return NSTerminateCancel; 409 } 410 411 412 - (BOOL)applicationOpenUntitledFile:(NSApplication *)theApplication 413 { 414 LOG("GlassApplication:applicationOpenUntitledFile"); 415 416 // NOP (should never be called because applicationShouldOpenUntitledFile returns NO) 417 418 return YES; 419 } 420 421 #pragma mark --- Glass support 422 423 - (void)runLoop:(id)selector 424 { 425 LOG("GlassApplication:runLoop ENTER"); 426 427 NSAutoreleasePool *pool1 = [[NSAutoreleasePool alloc] init]; 428 429 jint error = (*jVM)->AttachCurrentThread(jVM, (void **)&jEnv, NULL); 430 //jint error = (*jVM)->AttachCurrentThreadAsDaemon(jVM, (void **)&jEnv, NULL); 431 if (error == 0) 432 { 433 NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init]; 434 435 if ([[NSThread currentThread] name] == nil) 436 { 437 [[NSThread currentThread] setName:@"Main Cocoa (UI) Thread"]; 438 } 439 440 GlassApplication *glassApp = (GlassApplication *)selector; 441 442 // Load MacApplication class using the glass classloader 443 jclass cls = [GlassHelper ClassForName:"com.sun.glass.ui.mac.MacApplication" withEnv:jEnv]; 444 if (!cls) 445 { 446 NSLog(@"ERROR: can't find the MacApplication class"); 447 } 448 else 449 { 450 jmethodID setEventThreadMID = (*jEnv)->GetMethodID(jEnv, cls, "setEventThread", "()V"); 451 if (!setEventThreadMID) 452 { 453 NSLog(@"ERROR: can't get MacApplication.setEventThread() method ID"); 454 } 455 else 456 { 457 (*jEnv)->CallVoidMethod(jEnv, glassApp->jApplication, setEventThreadMID); 458 } 459 } 460 GLASS_CHECK_EXCEPTION(jEnv); 461 462 NSBundle *mainBundle = [NSBundle mainBundle]; 463 { 464 NSString *appName = [mainBundle objectForInfoDictionaryKey:@"CFBundleDisplayName"]; 465 466 if (appName == nil) { 467 appName = [mainBundle objectForInfoDictionaryKey:@"CFBundleName"]; 468 } 469 470 if (appName) { 471 // make the name available to Java side, before Launchable.fnishLaunching callback 472 jstring jname = (*jEnv)->NewStringUTF(jEnv, [appName UTF8String]); 473 jmethodID setNameMethod = (*jEnv)->GetMethodID(jEnv, cls, "setName", "(Ljava/lang/String;)V"); 474 GLASS_CHECK_EXCEPTION(jEnv); 475 if (setNameMethod != NULL) { 476 (*jEnv)->CallVoidMethod(jEnv, glassApp->jApplication, setNameMethod, jname); 477 } 478 GLASS_CHECK_EXCEPTION(jEnv); 479 } 480 } 481 482 // Determine if we're running embedded (in AWT, SWT, elsewhere) 483 NSApplication *app = [NSApplication sharedApplication]; 484 isEmbedded = [app isRunning]; 485 486 if (!isEmbedded) 487 { 488 if (self->jTaskBarApp == JNI_TRUE) 489 { 490 // move process from background only to full on app with visible Dock icon 491 ProcessSerialNumber psn; 492 if (GetCurrentProcess(&psn) == noErr) 493 { 494 TransformProcessType(&psn, kProcessTransformToForegroundApplication); 495 } 496 497 NSString *CFBundleIconFile = [mainBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]; 498 NSString *iconPath = nil; 499 if (CFBundleIconFile != nil) 500 { 501 iconPath = [mainBundle pathForResource:[CFBundleIconFile stringByDeletingPathExtension] ofType:[CFBundleIconFile pathExtension]]; 502 } 503 504 // -Xdock:icon can override CFBundleIconFile (but only if it actually points to a valid icon) 505 NSString *property = [NSString stringWithFormat:@"APP_ICON_%d", [[NSProcessInfo processInfo] processIdentifier]]; 506 char *path = getenv([property UTF8String]); 507 if (path != NULL) 508 { 509 NSString *overridenPath = [NSString stringWithFormat:@"%s", path]; 510 if ([[NSFileManager defaultManager] fileExistsAtPath:overridenPath isDirectory:NO] == YES) 511 { 512 iconPath = overridenPath; 513 } 514 } 515 if ([[NSFileManager defaultManager] fileExistsAtPath:iconPath isDirectory:NO] == NO) 516 { 517 // try again using Java generic icon (this icon might go away eventually ?) 518 iconPath = [NSString stringWithFormat:@"%s", "/System/Library/Frameworks/JavaVM.framework/Resources/GenericApp.icns"]; 519 } 520 521 NSImage *image = nil; 522 { 523 if ([[NSFileManager defaultManager] fileExistsAtPath:iconPath isDirectory:NO] == YES) 524 { 525 image = [[NSImage alloc] initWithContentsOfFile:iconPath]; 526 } 527 if (image == nil) 528 { 529 // last resort - if still no icon, then ask for an empty standard app icon, which is guranteed to exist 530 image = [[NSImage imageNamed:@"NSApplicationIcon"] retain]; 531 } 532 } 533 [app setApplicationIconImage:image]; 534 [image release]; 535 536 // Install a hidden Window menu. This allows the dock icon 537 // menu to show the list of open windows (NSWindow instances) 538 NSMenu *myMenu = [[NSMenu alloc] initWithTitle:@"Window"]; 539 [app setWindowsMenu:myMenu]; 540 [myMenu release]; 541 542 [app setDelegate:self]; 543 544 // [app activateIgnoringOtherApps:YES] won't activate the menu bar on OS X 10.9, so instead we do this: 545 [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateIgnoringOtherApps | NSApplicationActivateAllWindows)]; 546 } 547 else 548 { 549 // allow background processes to change the cursor (10.8 only API so we'll have to dynamically call it if available) 550 { 551 BOOL yes = YES; 552 [GlassHelper InvokeSelectorIfAvailable:@selector(javaSetAllowsCursorSetInBackground:) forClass:[NSCursor class] withArgument:&yes withReturnValue:NULL]; 553 } 554 555 // http://developer.apple.com/library/ios/#documentation/DeveloperTools/Conceptual/cross_development/Using/using.html 556 if (floor(NSAppKitVersionNumber) >= 1138) // NSAppKitVersionNumber10_7 557 { 558 // 10.7 or later: move process from background only process to a limited app with active windows, 559 // but no Dock icon 560 ProcessSerialNumber psn; 561 if (GetCurrentProcess(&psn) == noErr) 562 { 563 TransformProcessType(&psn, 4); // kProcessTransformToUIElementApplication 564 } 565 } 566 else 567 { 568 // 10.6 or earlier: applets are not officially supported on 10.6 and earlier 569 // so they will have limited applet functionality (no active windows) 570 } 571 [app setDelegate:self]; 572 } 573 574 #if defined(VERBOSE_LOAD) 575 jclass BooleanClass = [GlassHelper ClassForName:"java.lang.Boolean" withEnv:jEnv]; 576 if (BooleanClass != 0) 577 { 578 jmethodID getBooleanMethod = (*jEnv)->GetStaticMethodID(jEnv, BooleanClass, "getBoolean", "(Ljava/lang/String;)Z"); 579 if (getBooleanMethod != 0) 580 { 581 jstring flag = (*jEnv)->NewStringUTF(jEnv, "glassload.verbose"); 582 jboolean verbose = (*jEnv)->CallStaticBooleanMethod(jEnv, BooleanClass, getBooleanMethod, flag); 583 if (verbose == JNI_TRUE) 584 { 585 printLoadedLibraries(stderr); 586 printLoadedFiles(stderr); 587 } 588 } 589 } 590 #endif 591 592 // drain the pool before entering runloop 593 [pool2 drain]; 594 595 // enter runloop, this will not return until terminated 596 [NSApp run]; 597 598 // Abort listerning to global touch input events 599 [GlassTouches terminate]; 600 601 GLASS_CHECK_EXCEPTION(jEnv); 602 603 (*jEnv)->CallVoidMethod(jEnv, self->jApplication, javaIDs.MacApplication.notifyApplicationDidTerminate); 604 GLASS_CHECK_EXCEPTION(jEnv); 605 606 jint err = (*jVM)->DetachCurrentThread(jVM); 607 if (err < 0) 608 { 609 NSLog(@"Unable to detach from JVM. Error code: %d\n", (int)err); 610 } 611 612 jEnv = NULL; 613 } 614 else // event loop is not started 615 { 616 if ([NSThread isMainThread] == YES) { 617 [glassApp applicationWillFinishLaunching: NULL]; 618 } else { 619 [glassApp performSelectorOnMainThread:@selector(applicationWillFinishLaunching:) withObject:NULL waitUntilDone:NO]; 620 } 621 GLASS_CHECK_EXCEPTION(jEnv); 622 623 [pool2 drain]; 624 } 625 } 626 else // attaching to JVM failed 627 { 628 NSLog(@"ERROR: Glass could not attach to VM, result:%d\n", (int)error); 629 } 630 631 [pool1 drain]; 632 633 LOG("GlassApplication:runLoop EXIT"); 634 } 635 636 - (BOOL)started 637 { 638 return self->started; 639 } 640 641 + (jobject)enterNestedEventLoopWithEnv:(JNIEnv*)env 642 { 643 jobject ret = NULL; 644 645 NSRunLoop *theRL = [NSRunLoop currentRunLoop]; 646 NSApplication * app = [NSApplication sharedApplication]; 647 shouldKeepRunningNestedLoop = YES; 648 // Cannot use [NSDate distantFuture] because the period is big the app could hang in a runloop 649 // if the event came before entering the RL 650 while (shouldKeepRunningNestedLoop && [theRL runMode:NSDefaultRunLoopMode 651 beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.010]]) 652 { 653 NSEvent * event = [app nextEventMatchingMask: 0xFFFFFFFF untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES]; 654 655 if (event != nil) { 656 [app sendEvent: event]; 657 } 658 } 659 660 if (nestedLoopReturnValue != NULL) { 661 ret = (*env)->NewLocalRef(env, nestedLoopReturnValue); 662 (*env)->DeleteGlobalRef(env, nestedLoopReturnValue); 663 nestedLoopReturnValue = NULL; 664 } 665 666 shouldKeepRunningNestedLoop = YES; 667 668 return ret; 669 } 670 671 + (void)leaveNestedEventLoopWithEnv:(JNIEnv*)env retValue:(jobject)retValue 672 { 673 if (retValue != NULL) { 674 nestedLoopReturnValue = (*env)->NewGlobalRef(env, retValue); 675 } 676 shouldKeepRunningNestedLoop = NO; 677 } 678 679 + (void)enterFullScreenExitingLoop 680 { 681 isFullScreenExitingLoop = YES; 682 GET_MAIN_JENV; 683 (*env)->CallStaticObjectMethod(env, jApplicationClass, 684 javaIDs.Application.enterNestedEventLoop); 685 isFullScreenExitingLoop = NO; 686 } 687 688 + (void)leaveFullScreenExitingLoopIfNeeded 689 { 690 if (!isFullScreenExitingLoop) { 691 return; 692 } 693 GET_MAIN_JENV; 694 (*env)->CallStaticVoidMethod(env, jApplicationClass, 695 javaIDs.Application.leaveNestedEventLoop, (jobject)NULL); 696 } 697 698 + (void)registerKeyEvent:(NSEvent*)event 699 { 700 if (!keyCodeForCharMap) { 701 keyCodeForCharMap = [[NSMutableDictionary alloc] initWithCapacity:100]; 702 // Note: it's never released, just like, say, the jApplication reference... 703 } 704 [keyCodeForCharMap setObject:[NSNumber numberWithUnsignedShort:[event keyCode]] forKey:[event characters]]; 705 } 706 707 + (jint)getKeyCodeForChar:(jchar)c; 708 { 709 id v = [keyCodeForCharMap objectForKey:[NSString stringWithCharacters: (UniChar *)&c length:1]]; 710 if (!v) { 711 return com_sun_glass_events_KeyEvent_VK_UNDEFINED; 712 } else { 713 return GetJavaKeyCodeFor([v unsignedShortValue]); 714 } 715 } 716 717 + (BOOL)syncRenderingDisabled { 718 return disableSyncRendering; 719 } 720 721 + (BOOL)isSandboxed 722 { 723 static int isSandboxed = -1; 724 725 if (isSandboxed == -1) { 726 isSandboxed = 0; 727 728 NSBundle *mainBundle = [NSBundle mainBundle]; 729 NSURL *url = [mainBundle bundleURL]; 730 SecStaticCodeRef staticCodeRef = NULL; 731 SecStaticCodeCreateWithPath((CFURLRef)url, kSecCSDefaultFlags, &staticCodeRef); 732 733 if (staticCodeRef) { 734 // Check if the app is signed 735 OSStatus res_signed = SecStaticCodeCheckValidityWithErrors(staticCodeRef, kSecCSBasicValidateOnly, NULL, NULL); 736 if (res_signed == errSecSuccess) { 737 // It is signed, now check if it's sandboxed 738 SecRequirementRef sandboxRequirementRef = NULL; 739 SecRequirementCreateWithString(CFSTR("entitlement[\"com.apple.security.app-sandbox\"] exists"), kSecCSDefaultFlags, &sandboxRequirementRef); 740 741 if (sandboxRequirementRef) { 742 OSStatus res_sandboxed = SecStaticCodeCheckValidityWithErrors(staticCodeRef, kSecCSBasicValidateOnly, sandboxRequirementRef, NULL); 743 if (res_sandboxed == errSecSuccess) { 744 // Yep, sandboxed 745 isSandboxed = 1; 746 } 747 748 CFRelease(sandboxRequirementRef); 749 } 750 } 751 752 CFRelease(staticCodeRef); 753 } 754 } 755 756 return isSandboxed == 1 ? YES : NO; 757 } 758 759 @end 760 761 #pragma mark --- JNI 762 763 /* 764 * Class: com_sun_glass_ui_mac_MacApplication 765 * Method: _initIDs 766 * Signature: ()V 767 */ 768 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1initIDs 769 (JNIEnv *env, jclass jClass, jboolean jDisableSyncRendering) 770 { 771 LOG("Java_com_sun_glass_ui_mac_MacApplication__1initIDs"); 772 773 disableSyncRendering = jDisableSyncRendering ? YES : NO; 774 775 jApplicationClass = (*env)->NewGlobalRef(env, jClass); 776 777 javaIDs.Application.createPixels = (*env)->GetStaticMethodID( 778 env, jClass, "createPixels", "(II[IF)Lcom/sun/glass/ui/Pixels;"); 779 if ((*env)->ExceptionCheck(env)) return; 780 781 javaIDs.Application.getScaleFactor = (*env)->GetStaticMethodID( 782 env, jClass, "getScaleFactor", "(IIII)F"); 783 if ((*env)->ExceptionCheck(env)) return; 784 785 javaIDs.Application.reportException = (*env)->GetStaticMethodID( 786 env, jClass, "reportException", "(Ljava/lang/Throwable;)V"); 787 if ((*env)->ExceptionCheck(env)) return; 788 789 javaIDs.Application.enterNestedEventLoop = (*env)->GetStaticMethodID( 790 env, jClass, "enterNestedEventLoop", "()Ljava/lang/Object;"); 791 if ((*env)->ExceptionCheck(env)) return; 792 793 javaIDs.Application.leaveNestedEventLoop = (*env)->GetStaticMethodID( 794 env, jClass, "leaveNestedEventLoop", "(Ljava/lang/Object;)V"); 795 if ((*env)->ExceptionCheck(env)) return; 796 797 javaIDs.MacApplication.notifyApplicationDidTerminate = (*env)->GetMethodID( 798 env, jClass, "notifyApplicationDidTerminate", "()V"); 799 if ((*env)->ExceptionCheck(env)) return; 800 801 if (jRunnableRun == NULL) 802 { 803 jclass jcls = (*env)->FindClass(env, "java/lang/Runnable"); 804 if ((*env)->ExceptionCheck(env)) return; 805 jRunnableRun = (*env)->GetMethodID(env, jcls, "run", "()V"); 806 if ((*env)->ExceptionCheck(env)) return; 807 } 808 } 809 810 /* 811 * Class: com_sun_glass_ui_mac_MacApplication 812 * Method: _runLoop 813 * Signature: (Ljava/lang/ClassLoader;Ljava/lang/Runnable;Z)V 814 */ 815 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1runLoop 816 (JNIEnv *env, jobject japplication, jobject classLoader, 817 jobject jlaunchable, jboolean isTaskbarApplication) 818 { 819 LOG("Java_com_sun_glass_ui_mac_MacApplication__1runLoop"); 820 821 NSAutoreleasePool *glasspool = [[NSAutoreleasePool alloc] init]; 822 { 823 if ([NSThread isMainThread] == YES) 824 { 825 // fprintf(stderr, "\nWARNING: Glass was started on 1st thread and will block this thread.\nYou most likely do not want to do this - please remove \"-XstartOnFirstThread\" from VM arguments.\n\n"); 826 } 827 else 828 { 829 if ([[NSThread currentThread] name] == nil) 830 { 831 [[NSThread currentThread] setName:@"Main Java Thread"]; 832 } 833 } 834 835 GlassApplication *glass = [[GlassApplication alloc] initWithEnv:env application:japplication launchable:jlaunchable taskbarApplication:isTaskbarApplication classLoader:classLoader]; 836 if ([NSThread isMainThread] == YES) { 837 [glass runLoop: glass]; 838 } else { 839 [glass performSelectorOnMainThread:@selector(runLoop:) withObject:glass waitUntilDone:[NSThread isMainThread]]; 840 841 // wait for Cocoa to enter its UI runloop 842 while ([glass started] == NO) 843 { 844 LOG(" waiting for [glass started]"); 845 usleep(10000); 846 } 847 } 848 849 // at this point Java main thread is allowed to proceed, but Cocoa's UI thread entered its runloop, so the VM will not quit 850 } 851 [glasspool drain]; glasspool=nil; 852 GLASS_CHECK_EXCEPTION(env); 853 } 854 855 /* 856 * Class: com_sun_glass_ui_mac_MacApplication 857 * Method: _finishTerminating 858 * Signature: ()V 859 */ 860 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1finishTerminating 861 (JNIEnv *env, jobject japplication) 862 { 863 LOG("Java_com_sun_glass_ui_mac_MacApplication__1finishTerminating"); 864 865 if (isEmbedded) { 866 return; 867 } 868 869 NSAutoreleasePool *glasspool = [[NSAutoreleasePool alloc] init]; 870 { 871 [NSApp stop:nil]; 872 [NSApp hide:nil]; 873 874 // wake up the runloop one last time so that it can process the stop: 875 // request, even if the app is inactive currently 876 NSTimeInterval dummyEventTimestamp = [NSProcessInfo processInfo].systemUptime; 877 NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined 878 location: NSMakePoint(0,0) 879 modifierFlags: 0 880 timestamp: dummyEventTimestamp 881 windowNumber: 0 882 context: nil 883 subtype: 0 884 data1: 0 885 data2: 0]; 886 [NSApp postEvent: event atStart: NO]; 887 } 888 [glasspool drain]; glasspool=nil; 889 GLASS_CHECK_EXCEPTION(env); 890 } 891 892 /* 893 * Class: com_sun_glass_ui_mac_MacApplication 894 * Method: _enterNestedEventLoopImpl 895 * Signature: ()Ljava/lang/Object; 896 */ 897 JNIEXPORT jobject JNICALL Java_com_sun_glass_ui_mac_MacApplication__1enterNestedEventLoopImpl 898 (JNIEnv *env, jobject japplication) 899 { 900 LOG("Java_com_sun_glass_ui_mac_MacApplication__1enterNestedEventLoopImpl"); 901 902 jobject ret; 903 904 NSAutoreleasePool *glasspool = [[NSAutoreleasePool alloc] init]; 905 { 906 ret = [GlassApplication enterNestedEventLoopWithEnv:env]; 907 } 908 [glasspool drain]; glasspool=nil; 909 GLASS_CHECK_EXCEPTION(env); 910 911 return ret; 912 } 913 914 /* 915 * Class: com_sun_glass_ui_mac_MacApplication 916 * Method: _leaveNestedEventLoopImpl 917 * Signature: (Ljava/lang/Object;)V 918 */ 919 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1leaveNestedEventLoopImpl 920 (JNIEnv *env, jobject japplication, jobject retValue) 921 { 922 LOG("Java_com_sun_glass_ui_mac_MacApplication__1leaveNestedEventLoopImpl"); 923 924 NSAutoreleasePool *glasspool = [[NSAutoreleasePool alloc] init]; 925 { 926 [GlassApplication leaveNestedEventLoopWithEnv:env retValue:retValue]; 927 } 928 [glasspool drain]; glasspool=nil; 929 GLASS_CHECK_EXCEPTION(env); 930 } 931 932 /* 933 * Class: com_sun_glass_ui_Application 934 * Method: _submitForLaterInvocation 935 * Signature: (Ljava/lang/Runnable;)V 936 */ 937 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1submitForLaterInvocation 938 (JNIEnv *env, jobject japplication, jobject jRunnable) 939 { 940 //LOG("Java_com_sun_glass_ui_mac_MacApplication_submitForLaterInvocation"); 941 942 GLASS_ASSERT_MAIN_JAVA_THREAD(env); 943 if (jEnv != NULL) 944 { 945 GlassRunnable *runnable = [[GlassRunnable alloc] initWithRunnable:(*env)->NewGlobalRef(env, jRunnable)]; 946 [runnable performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:NO]; 947 } 948 } 949 950 /* 951 * Class: com_sun_glass_ui_Application 952 * Method: _invokeAndWait 953 * Signature: (Ljava/lang/Runnable;)V 954 */ 955 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1invokeAndWait 956 (JNIEnv *env, jobject japplication, jobject jRunnable) 957 { 958 LOG("Java_com_sun_glass_ui_mac_MacApplication__1invokeAndWait"); 959 960 GLASS_ASSERT_MAIN_JAVA_THREAD(env); 961 if (jEnv != NULL) 962 { 963 GlassRunnable *runnable = [[GlassRunnable alloc] initWithRunnable:(*env)->NewGlobalRef(env, jRunnable)]; 964 [runnable performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:YES]; 965 } 966 } 967 968 /* 969 * Class: com_sun_glass_ui_mac_MacApplication 970 * Method: _getRemoteLayerServerName 971 * Signature: ()Ljava/lang/String; 972 */ 973 JNIEXPORT jstring JNICALL Java_com_sun_glass_ui_mac_MacApplication__1getRemoteLayerServerName 974 (JNIEnv *env, jobject japplication) 975 { 976 LOG("Java_com_sun_glass_ui_mac_MacPasteboard__1getName"); 977 978 jstring name = NULL; 979 980 GLASS_ASSERT_MAIN_JAVA_THREAD(env); 981 GLASS_POOL_ENTER; 982 { 983 static mach_port_t remoteLayerServerPort = MACH_PORT_NULL; 984 if (remoteLayerServerPort == MACH_PORT_NULL) 985 { 986 remoteLayerServerPort = RemoteLayerStartServer(); 987 } 988 NSString *remoteLayerServerName = RemoteLayerGetServerName(remoteLayerServerPort); 989 name = (*env)->NewStringUTF(env, [remoteLayerServerName UTF8String]); 990 } 991 GLASS_POOL_EXIT; 992 GLASS_CHECK_EXCEPTION(env); 993 994 return name; 995 } 996 997 /* 998 * Class: com_sun_glass_ui_mac_MacApplication 999 * Method: staticScreen_getVideoRefreshPeriod 1000 * Signature: ()D 1001 */ 1002 JNIEXPORT jdouble JNICALL 1003 Java_com_sun_glass_ui_mac_MacApplication_staticScreen_1getVideoRefreshPeriod 1004 (JNIEnv *env, jobject jApplication) 1005 { 1006 LOG("Java_com_sun_glass_ui_mac_MacApplication__1getVideoRefreshPeriod"); 1007 1008 if (GlassDisplayLink != NULL) 1009 { 1010 double outRefresh = CVDisplayLinkGetActualOutputVideoRefreshPeriod(GlassDisplayLink); 1011 LOG("CVDisplayLinkGetActualOutputVideoRefreshPeriod: %f", outRefresh); 1012 return (outRefresh * 1000.0); // to millis 1013 } 1014 else 1015 { 1016 return 0.0; 1017 } 1018 } 1019 1020 /* 1021 * Class: com_sun_glass_ui_mac_MacApplication 1022 * Method: staticScreen_getScreens 1023 * Signature: ()[Lcom/sun/glass/ui/Screen; 1024 */ 1025 JNIEXPORT jobjectArray JNICALL Java_com_sun_glass_ui_mac_MacApplication_staticScreen_1getScreens 1026 (JNIEnv *env, jobject jApplication) 1027 { 1028 LOG("Java_com_sun_glass_ui_mac_MacApplication__1getScreens"); 1029 1030 jobjectArray screenArray = nil; 1031 1032 GLASS_POOL_ENTER; 1033 { 1034 screenArray = createJavaScreens(env); 1035 } 1036 GLASS_POOL_EXIT; 1037 GLASS_CHECK_EXCEPTION(env); 1038 1039 return screenArray; 1040 } 1041 1042 1043 /* 1044 * Class: com_sun_glass_ui_mac_MacApplication 1045 * Method: _supportsSystemMenu 1046 * Signature: ()Z; 1047 */ 1048 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_mac_MacApplication__1supportsSystemMenu 1049 (JNIEnv *env, jobject japplication) 1050 { 1051 return !isEmbedded; 1052 } 1053 1054 /* 1055 * Class: com_sun_glass_ui_mac_MacApplication 1056 * Method: _hide 1057 * Signature: ()V; 1058 */ 1059 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1hide 1060 (JNIEnv *env, jobject japplication) 1061 { 1062 [NSApp hide:NSApp]; 1063 } 1064 1065 /* 1066 * Class: com_sun_glass_ui_mac_MacApplication 1067 * Method: _hideOtherApplications 1068 * Signature: ()V; 1069 */ 1070 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1hideOtherApplications 1071 (JNIEnv *env, jobject japplication) 1072 { 1073 [NSApp hideOtherApplications:NSApp]; 1074 } 1075 1076 /* 1077 * Class: com_sun_glass_ui_mac_MacApplication 1078 * Method: _unhideAllApplications 1079 * Signature: ()V; 1080 */ 1081 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1unhideAllApplications 1082 (JNIEnv *env, jobject japplication) 1083 { 1084 [NSApp unhideAllApplications:NSApp]; 1085 } 1086 1087 /* 1088 * Class: com_sun_glass_ui_mac_MacApplication 1089 * Method: _getDataDirectory 1090 * Signature: ()Ljava/lang/String; 1091 */ 1092 JNIEXPORT jstring JNICALL Java_com_sun_glass_ui_mac_MacApplication__1getDataDirectory 1093 (JNIEnv * env, jobject japplication) 1094 { 1095 jstring string = nil; 1096 1097 GLASS_ASSERT_MAIN_JAVA_THREAD(env); 1098 GLASS_POOL_ENTER; 1099 { 1100 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); 1101 if (paths && [paths count] > 0) { 1102 string = (*env)->NewStringUTF(jEnv, [[paths lastObject] UTF8String]); 1103 } 1104 } 1105 GLASS_POOL_EXIT; 1106 GLASS_CHECK_EXCEPTION(env); 1107 1108 return string; 1109 } 1110 1111 /* 1112 * Class: com_sun_glass_ui_mac_MacApplication 1113 * Method: _getMacKey 1114 * Signature: (I)I 1115 */ 1116 JNIEXPORT jint JNICALL Java_com_sun_glass_ui_mac_MacApplication__1getMacKey 1117 (JNIEnv *env, jclass jClass, jint code) 1118 { 1119 unsigned short macCode = 0; 1120 GetMacKey(code, &macCode); 1121 return (macCode & 0xFFFF); 1122 }