1 /*
   2  * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #import "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     isFullScreenExitingLoop = YES;
 708     GET_MAIN_JENV;
 709     (*env)->CallStaticObjectMethod(env, jApplicationClass,
 710             javaIDs.Application.enterNestedEventLoop);
 711     if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
 712         (*env)->ExceptionDescribe(env);
 713         (*env)->ExceptionClear(env);
 714     }
 715     isFullScreenExitingLoop = NO;
 716 }
 717 
 718 + (void)leaveFullScreenExitingLoopIfNeeded
 719 {
 720     if (!isFullScreenExitingLoop) {
 721         return;
 722     }
 723     GET_MAIN_JENV;
 724     (*env)->CallStaticVoidMethod(env, jApplicationClass,
 725             javaIDs.Application.leaveNestedEventLoop, (jobject)NULL);
 726 }
 727 
 728 + (void)registerKeyEvent:(NSEvent*)event
 729 {
 730     if (!keyCodeForCharMap) {
 731         keyCodeForCharMap = [[NSMutableDictionary alloc] initWithCapacity:100];
 732         // Note: it's never released, just like, say, the jApplication reference...
 733     }
 734     [keyCodeForCharMap setObject:[NSNumber numberWithUnsignedShort:[event keyCode]] forKey:[event characters]];
 735 }
 736 
 737 + (jint)getKeyCodeForChar:(jchar)c;
 738 {
 739     id v = [keyCodeForCharMap objectForKey:[NSString stringWithCharacters: (UniChar *)&c length:1]];
 740     if (!v) {
 741         return com_sun_glass_events_KeyEvent_VK_UNDEFINED;
 742     } else {
 743         return GetJavaKeyCodeFor([v unsignedShortValue]);
 744     }
 745 }
 746 
 747 + (BOOL)syncRenderingDisabled {
 748     return disableSyncRendering;
 749 }
 750 
 751 + (BOOL)isSandboxed
 752 {
 753     static int isSandboxed = -1;
 754 
 755     if (isSandboxed == -1) {
 756         isSandboxed = 0;
 757 
 758         NSBundle *mainBundle = [NSBundle mainBundle];
 759         NSURL *url = [mainBundle bundleURL];
 760         SecStaticCodeRef staticCodeRef = NULL;
 761         SecStaticCodeCreateWithPath((CFURLRef)url, kSecCSDefaultFlags, &staticCodeRef);
 762 
 763         if (staticCodeRef) {
 764             // Check if the app is signed
 765             OSStatus res_signed = SecStaticCodeCheckValidityWithErrors(staticCodeRef, kSecCSBasicValidateOnly, NULL, NULL);
 766             if (res_signed == errSecSuccess) {
 767                 // It is signed, now check if it's sandboxed
 768                 SecRequirementRef sandboxRequirementRef = NULL;
 769                 SecRequirementCreateWithString(CFSTR("entitlement[\"com.apple.security.app-sandbox\"] exists"), kSecCSDefaultFlags, &sandboxRequirementRef);
 770 
 771                 if (sandboxRequirementRef) {
 772                     OSStatus res_sandboxed = SecStaticCodeCheckValidityWithErrors(staticCodeRef, kSecCSBasicValidateOnly, sandboxRequirementRef, NULL);
 773                     if (res_sandboxed == errSecSuccess) {
 774                         // Yep, sandboxed
 775                         isSandboxed = 1;
 776                     }
 777 
 778                     CFRelease(sandboxRequirementRef);
 779                 }
 780             }
 781 
 782             CFRelease(staticCodeRef);
 783         }
 784     }
 785 
 786     return isSandboxed == 1 ? YES : NO;
 787 }
 788 
 789 @end
 790 
 791 #pragma mark --- JNI
 792 
 793 /*
 794  * Class:     com_sun_glass_ui_mac_MacApplication
 795  * Method:    _initIDs
 796  * Signature: ()V
 797  */
 798 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1initIDs
 799 (JNIEnv *env, jclass jClass, jboolean jDisableSyncRendering)
 800 {
 801     LOG("Java_com_sun_glass_ui_mac_MacApplication__1initIDs");
 802 
 803     disableSyncRendering = jDisableSyncRendering ? YES : NO;
 804 
 805     jApplicationClass = (*env)->NewGlobalRef(env, jClass);
 806 
 807     javaIDs.Application.createPixels = (*env)->GetStaticMethodID(
 808             env, jClass, "createPixels", "(II[IFF)Lcom/sun/glass/ui/Pixels;");
 809     if ((*env)->ExceptionCheck(env)) return;
 810 
 811     javaIDs.Application.getScaleFactor = (*env)->GetStaticMethodID(
 812             env, jClass, "getScaleFactor", "(IIII)F");
 813     if ((*env)->ExceptionCheck(env)) return;
 814 
 815     javaIDs.Application.reportException = (*env)->GetStaticMethodID(
 816             env, jClass, "reportException", "(Ljava/lang/Throwable;)V");
 817     if ((*env)->ExceptionCheck(env)) return;
 818 
 819     javaIDs.Application.enterNestedEventLoop = (*env)->GetStaticMethodID(
 820             env, jClass, "enterNestedEventLoop", "()Ljava/lang/Object;");
 821     if ((*env)->ExceptionCheck(env)) return;
 822 
 823     javaIDs.Application.leaveNestedEventLoop = (*env)->GetStaticMethodID(
 824             env, jClass, "leaveNestedEventLoop", "(Ljava/lang/Object;)V");
 825     if ((*env)->ExceptionCheck(env)) return;
 826 
 827     javaIDs.MacApplication.notifyApplicationDidTerminate = (*env)->GetMethodID(
 828             env, jClass, "notifyApplicationDidTerminate", "()V");
 829     if ((*env)->ExceptionCheck(env)) return;
 830 
 831     if (jRunnableRun == NULL)
 832     {
 833         jclass jcls = (*env)->FindClass(env, "java/lang/Runnable");
 834         if ((*env)->ExceptionCheck(env)) return;
 835         jRunnableRun = (*env)->GetMethodID(env, jcls, "run", "()V");
 836         if ((*env)->ExceptionCheck(env)) return;
 837     }
 838 }
 839 
 840 /*
 841  * Class:     com_sun_glass_ui_mac_MacApplication
 842  * Method:    _runLoop
 843  * Signature: (Ljava/lang/ClassLoader;Ljava/lang/Runnable;Z)V
 844  */
 845 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1runLoop
 846 (JNIEnv *env, jobject japplication, jobject classLoader,
 847  jobject jlaunchable, jboolean isTaskbarApplication)
 848 {
 849     LOG("Java_com_sun_glass_ui_mac_MacApplication__1runLoop");
 850 
 851     NSAutoreleasePool *glasspool = [[NSAutoreleasePool alloc] init];
 852     {
 853         if ([NSThread isMainThread] == YES)
 854         {
 855             //            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");
 856         }
 857         else
 858         {
 859             if ([[NSThread currentThread] name] == nil)
 860             {
 861                 [[NSThread currentThread] setName:@"Main Java Thread"];
 862             }
 863         }
 864 
 865         GlassApplication *glass = [[GlassApplication alloc] initWithEnv:env application:japplication launchable:jlaunchable taskbarApplication:isTaskbarApplication classLoader:classLoader];
 866         if ([NSThread isMainThread] == YES) {
 867             [glass runLoop: glass];
 868         } else {
 869             [glass performSelectorOnMainThread:@selector(runLoop:) withObject:glass waitUntilDone:[NSThread isMainThread]];
 870 
 871             // wait for Cocoa to enter its UI runloop
 872             while ([glass started] == NO)
 873             {
 874                 LOG("        waiting for [glass started]");
 875                 usleep(10000);
 876             }
 877         }
 878 
 879         // at this point Java main thread is allowed to proceed, but Cocoa's UI thread entered its runloop, so the VM will not quit
 880     }
 881     [glasspool drain]; glasspool=nil;
 882     GLASS_CHECK_EXCEPTION(env);
 883 }
 884 
 885 /*
 886  * Class:     com_sun_glass_ui_mac_MacApplication
 887  * Method:    _finishTerminating
 888  * Signature: ()V
 889  */
 890 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1finishTerminating
 891 (JNIEnv *env, jobject japplication)
 892 {
 893     LOG("Java_com_sun_glass_ui_mac_MacApplication__1finishTerminating");
 894 
 895     if (isEmbedded) {
 896         return;
 897     }
 898 
 899     NSAutoreleasePool *glasspool = [[NSAutoreleasePool alloc] init];
 900     {
 901         [NSApp stop:nil];
 902         [NSApp hide:nil];
 903 
 904         // wake up the runloop one last time so that it can process the stop:
 905         // request, even if the app is inactive currently
 906         NSTimeInterval dummyEventTimestamp = [NSProcessInfo processInfo].systemUptime;
 907         NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
 908                                             location: NSMakePoint(0,0)
 909                                        modifierFlags: 0
 910                                            timestamp: dummyEventTimestamp
 911                                         windowNumber: 0
 912                                              context: nil
 913                                              subtype: 0
 914                                                data1: 0
 915                                                data2: 0];
 916         [NSApp postEvent: event atStart: NO];
 917     }
 918     [glasspool drain]; glasspool=nil;
 919     GLASS_CHECK_EXCEPTION(env);
 920 }
 921 
 922 /*
 923  * Class:     com_sun_glass_ui_mac_MacApplication
 924  * Method:    _enterNestedEventLoopImpl
 925  * Signature: ()Ljava/lang/Object;
 926  */
 927 JNIEXPORT jobject JNICALL Java_com_sun_glass_ui_mac_MacApplication__1enterNestedEventLoopImpl
 928 (JNIEnv *env, jobject japplication)
 929 {
 930     LOG("Java_com_sun_glass_ui_mac_MacApplication__1enterNestedEventLoopImpl");
 931 
 932     jobject ret;
 933 
 934     NSAutoreleasePool *glasspool = [[NSAutoreleasePool alloc] init];
 935     {
 936         ret = [GlassApplication enterNestedEventLoopWithEnv:env];
 937     }
 938     [glasspool drain]; glasspool=nil;
 939     GLASS_CHECK_EXCEPTION(env);
 940 
 941     return ret;
 942 }
 943 
 944 /*
 945  * Class:     com_sun_glass_ui_mac_MacApplication
 946  * Method:    _leaveNestedEventLoopImpl
 947  * Signature: (Ljava/lang/Object;)V
 948  */
 949 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1leaveNestedEventLoopImpl
 950 (JNIEnv *env, jobject japplication, jobject retValue)
 951 {
 952     LOG("Java_com_sun_glass_ui_mac_MacApplication__1leaveNestedEventLoopImpl");
 953 
 954     NSAutoreleasePool *glasspool = [[NSAutoreleasePool alloc] init];
 955     {
 956         [GlassApplication leaveNestedEventLoopWithEnv:env retValue:retValue];
 957     }
 958     [glasspool drain]; glasspool=nil;
 959     GLASS_CHECK_EXCEPTION(env);
 960 }
 961 
 962 /*
 963  * Class:     com_sun_glass_ui_Application
 964  * Method:    _submitForLaterInvocation
 965  * Signature: (Ljava/lang/Runnable;)V
 966  */
 967 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1submitForLaterInvocation
 968 (JNIEnv *env, jobject japplication, jobject jRunnable)
 969 {
 970     //LOG("Java_com_sun_glass_ui_mac_MacApplication_submitForLaterInvocation");
 971 
 972     GLASS_ASSERT_MAIN_JAVA_THREAD(env);
 973     if (jEnv != NULL)
 974     {
 975         GlassRunnable *runnable = [[GlassRunnable alloc] initWithRunnable:(*env)->NewGlobalRef(env, jRunnable)];
 976         [runnable performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:NO];
 977     }
 978 }
 979 
 980 /*
 981  * Class:     com_sun_glass_ui_Application
 982  * Method:    _invokeAndWait
 983  * Signature: (Ljava/lang/Runnable;)V
 984  */
 985 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1invokeAndWait
 986 (JNIEnv *env, jobject japplication, jobject jRunnable)
 987 {
 988     LOG("Java_com_sun_glass_ui_mac_MacApplication__1invokeAndWait");
 989 
 990     GLASS_ASSERT_MAIN_JAVA_THREAD(env);
 991     if (jEnv != NULL)
 992     {
 993         GlassRunnable *runnable = [[GlassRunnable alloc] initWithRunnable:(*env)->NewGlobalRef(env, jRunnable)];
 994         [runnable performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:YES];
 995     }
 996 }
 997 
 998 /*
 999  * Class:     com_sun_glass_ui_mac_MacApplication
1000  * Method:    _getRemoteLayerServerName
1001  * Signature: ()Ljava/lang/String;
1002  */
1003 JNIEXPORT jstring JNICALL Java_com_sun_glass_ui_mac_MacApplication__1getRemoteLayerServerName
1004 (JNIEnv *env, jobject japplication)
1005 {
1006     LOG("Java_com_sun_glass_ui_mac_MacPasteboard__1getName");
1007 
1008     jstring name = NULL;
1009 
1010     GLASS_ASSERT_MAIN_JAVA_THREAD(env);
1011     GLASS_POOL_ENTER;
1012     {
1013         static mach_port_t remoteLayerServerPort = MACH_PORT_NULL;
1014         if (remoteLayerServerPort == MACH_PORT_NULL)
1015         {
1016             remoteLayerServerPort = RemoteLayerStartServer();
1017         }
1018         NSString *remoteLayerServerName = RemoteLayerGetServerName(remoteLayerServerPort);
1019         name = (*env)->NewStringUTF(env, [remoteLayerServerName UTF8String]);
1020     }
1021     GLASS_POOL_EXIT;
1022     GLASS_CHECK_EXCEPTION(env);
1023 
1024     return name;
1025 }
1026 
1027 /*
1028  * Class:     com_sun_glass_ui_mac_MacApplication
1029  * Method:    staticScreen_getVideoRefreshPeriod
1030  * Signature: ()D
1031  */
1032 JNIEXPORT jdouble JNICALL
1033 Java_com_sun_glass_ui_mac_MacApplication_staticScreen_1getVideoRefreshPeriod
1034 (JNIEnv *env, jobject jApplication)
1035 {
1036     LOG("Java_com_sun_glass_ui_mac_MacApplication__1getVideoRefreshPeriod");
1037 
1038     if (GlassDisplayLink != NULL)
1039     {
1040         double outRefresh = CVDisplayLinkGetActualOutputVideoRefreshPeriod(GlassDisplayLink);
1041         LOG("CVDisplayLinkGetActualOutputVideoRefreshPeriod: %f", outRefresh);
1042         return (outRefresh * 1000.0); // to millis
1043     }
1044     else
1045     {
1046         return 0.0;
1047     }
1048 }
1049 
1050 /*
1051  * Class:     com_sun_glass_ui_mac_MacApplication
1052  * Method:    staticScreen_getScreens
1053  * Signature: ()[Lcom/sun/glass/ui/Screen;
1054  */
1055 JNIEXPORT jobjectArray JNICALL Java_com_sun_glass_ui_mac_MacApplication_staticScreen_1getScreens
1056 (JNIEnv *env, jobject jApplication)
1057 {
1058     LOG("Java_com_sun_glass_ui_mac_MacApplication__1getScreens");
1059 
1060     jobjectArray screenArray = nil;
1061 
1062     GLASS_POOL_ENTER;
1063     {
1064         screenArray = createJavaScreens(env);
1065     }
1066     GLASS_POOL_EXIT;
1067     GLASS_CHECK_EXCEPTION(env);
1068 
1069     return screenArray;
1070 }
1071 
1072 
1073 /*
1074  * Class:     com_sun_glass_ui_mac_MacApplication
1075  * Method:    _supportsSystemMenu
1076  * Signature: ()Z;
1077  */
1078 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_mac_MacApplication__1supportsSystemMenu
1079 (JNIEnv *env, jobject japplication)
1080 {
1081     return !isEmbedded;
1082 }
1083 
1084 /*
1085  * Class:     com_sun_glass_ui_mac_MacApplication
1086  * Method:    _hide
1087  * Signature: ()V;
1088  */
1089 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1hide
1090 (JNIEnv *env, jobject japplication)
1091 {
1092     [NSApp hide:NSApp];
1093 }
1094 
1095 /*
1096  * Class:     com_sun_glass_ui_mac_MacApplication
1097  * Method:    _hideOtherApplications
1098  * Signature: ()V;
1099  */
1100 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1hideOtherApplications
1101 (JNIEnv *env, jobject japplication)
1102 {
1103     [NSApp hideOtherApplications:NSApp];
1104 }
1105 
1106 /*
1107  * Class:     com_sun_glass_ui_mac_MacApplication
1108  * Method:    _unhideAllApplications
1109  * Signature: ()V;
1110  */
1111 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacApplication__1unhideAllApplications
1112 (JNIEnv *env, jobject japplication)
1113 {
1114     [NSApp unhideAllApplications:NSApp];
1115 }
1116 
1117 /*
1118  * Class:     com_sun_glass_ui_mac_MacApplication
1119  * Method:    _getDataDirectory
1120  * Signature: ()Ljava/lang/String;
1121  */
1122 JNIEXPORT jstring JNICALL Java_com_sun_glass_ui_mac_MacApplication__1getDataDirectory
1123 (JNIEnv * env, jobject japplication)
1124 {
1125     jstring string = nil;
1126 
1127     GLASS_ASSERT_MAIN_JAVA_THREAD(env);
1128     GLASS_POOL_ENTER;
1129     {
1130     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
1131     if (paths && [paths count] > 0) {
1132         string = (*env)->NewStringUTF(jEnv, [[paths lastObject] UTF8String]);
1133     }
1134     }
1135     GLASS_POOL_EXIT;
1136     GLASS_CHECK_EXCEPTION(env);
1137 
1138     return string;
1139 }
1140 
1141 /*
1142  * Class:     com_sun_glass_ui_mac_MacApplication
1143  * Method:    _getMacKey
1144  * Signature: (I)I
1145  */
1146 JNIEXPORT jint JNICALL Java_com_sun_glass_ui_mac_MacApplication__1getMacKey
1147 (JNIEnv *env, jclass jClass, jint code)
1148 {
1149     unsigned short macCode = 0;
1150     GetMacKey(code, &macCode);
1151     return (macCode & 0xFFFF);
1152 }