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