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 "ApplicationDelegate.h"
  27 
  28 #import "com_apple_eawt_Application.h"
  29 #import "com_apple_eawt__AppDockIconHandler.h"
  30 #import "com_apple_eawt__AppEventHandler.h"
  31 #import "com_apple_eawt__AppMenuBarHandler.h"
  32 #import "com_apple_eawt__AppMenuBarHandler.h"
  33 #import "com_apple_eawt__AppMiscHandlers.h"
  34 
  35 #import "CPopupMenu.h"
  36 #import "ThreadUtilities.h"
  37 #import "NSApplicationAWT.h"
  38 #import "JNIUtilities.h"
  39 
  40 
  41 #pragma mark App Menu helpers
  42 
  43 // The following is a AWT convention?
  44 #define PREFERENCES_TAG  42
  45 
  46 static void addMenuItem(NSMenuItem* menuItem, NSInteger index) {
  47 AWT_ASSERT_APPKIT_THREAD;
  48 
  49     NSMenu *menuBar = [[NSApplication sharedApplication] mainMenu];
  50     NSMenu *appMenu = [[menuBar itemAtIndex:0] submenu];
  51 
  52     [appMenu insertItem:menuItem atIndex:index];
  53     [appMenu insertItem:[NSMenuItem separatorItem] atIndex:index + 1]; // Add the following separator
  54 }
  55 
  56 static void removeMenuItem(NSMenuItem* menuItem) {
  57 AWT_ASSERT_APPKIT_THREAD;
  58 
  59     NSMenu *menuBar = [[NSApplication sharedApplication] mainMenu];
  60     NSMenu *appMenu = [[menuBar itemAtIndex:0] submenu];
  61 
  62     NSInteger index = [appMenu indexOfItem:menuItem];
  63     if (index < 0) return; // something went wrong
  64 
  65     [appMenu removeItemAtIndex:index + 1]; // Get the following separator
  66     [appMenu removeItem:menuItem];
  67 }
  68 
  69 @interface NSBundle (EAWTOverrides)
  70 - (BOOL)_hasEAWTOverride:(NSString *)key;
  71 @end
  72 
  73 
  74 @implementation NSBundle (EAWTOverrides)
  75 
  76 - (BOOL)_hasEAWTOverride:(NSString *)key {
  77     return [[[[self objectForInfoDictionaryKey:@"Java"] objectForKey:@"EAWTOverride"] objectForKey:key] boolValue];
  78 }
  79 
  80 @end
  81 
  82 
  83 // used by JavaRuntimeSupport.framework's [JRSAppKitAWT awtAppDelegate]
  84 // to expose our app delegate to the SWT or other apps that have knoledge
  85 // of Java's AWT and want to install their own app delegate that will delegate
  86 // to the AWT for some operations
  87 
  88 @interface JavaAWTAppDelegateLoader : NSObject { }
  89 @end
  90 
  91 @implementation JavaAWTAppDelegateLoader
  92 + (ApplicationDelegate *) awtAppDelegate {
  93     return [ApplicationDelegate sharedDelegate];
  94 }
  95 @end
  96 
  97 
  98 @implementation ApplicationDelegate
  99 
 100 @synthesize fPreferencesMenu;
 101 @synthesize fAboutMenu;
 102 @synthesize fProgressIndicator;
 103 
 104 @synthesize fDockMenu;
 105 @synthesize fDefaultMenuBar;
 106 
 107 
 108 + (ApplicationDelegate *)sharedDelegate {
 109     static ApplicationDelegate *sApplicationDelegate = nil;
 110     static BOOL checked = NO;
 111 
 112     if (sApplicationDelegate != nil) return sApplicationDelegate;
 113     if (checked) return nil;
 114 
 115 AWT_ASSERT_APPKIT_THREAD;
 116 
 117     // don't install the EAWT delegate if another kind of NSApplication is installed, like say, Safari
 118     BOOL shouldInstall = NO;
 119     if (NSApp != nil) {
 120         if ([NSApp isMemberOfClass:[NSApplication class]]) shouldInstall = YES;
 121         if ([NSApp isKindOfClass:[NSApplicationAWT class]]) shouldInstall = YES;
 122     }
 123     checked = YES;
 124     if (!shouldInstall) return nil;
 125 
 126     sApplicationDelegate = [[ApplicationDelegate alloc] init];
 127     return sApplicationDelegate;
 128 }
 129 
 130 - (void)_updatePreferencesMenu:(BOOL)prefsAvailable enabled:(BOOL)prefsEnabled {
 131 AWT_ASSERT_APPKIT_THREAD;
 132 
 133     if (prefsAvailable) {
 134         // Make sure Prefs is around
 135         if ([self.fPreferencesMenu menu] == nil) {
 136             // Position of Prefs depends upon About availability.
 137             NSInteger index = ([self.fAboutMenu menu] != nil) ? 2 : 0;
 138 
 139             addMenuItem(self.fPreferencesMenu, index);
 140         }
 141 
 142         if (prefsEnabled) {
 143             [self.fPreferencesMenu setEnabled:YES];
 144             [self.fPreferencesMenu setTarget:self];
 145             [self.fPreferencesMenu setAction:@selector(_preferencesMenuHandler)];
 146         } else {
 147             [self.fPreferencesMenu setEnabled:NO];
 148             [self.fPreferencesMenu setTarget:nil];
 149             [self.fPreferencesMenu setAction:nil];
 150         }
 151     } else {
 152         if ([self.fPreferencesMenu menu] == nil) return;
 153 
 154         // Remove the preferences item
 155         removeMenuItem(self.fPreferencesMenu);
 156     }
 157 }
 158 
 159 - (void)_updateAboutMenu:(BOOL)aboutAvailable enabled:(BOOL)aboutEnabled {
 160 AWT_ASSERT_APPKIT_THREAD;
 161 
 162     if (aboutAvailable) {
 163         // Make sure About is around
 164         if ([self.fAboutMenu menu] == nil) {
 165             addMenuItem(self.fAboutMenu, 0);
 166         }
 167 
 168         if (aboutEnabled) {
 169             [self.fAboutMenu setEnabled:YES];
 170             [self.fAboutMenu setTarget:self];
 171             [self.fAboutMenu setAction:@selector(_aboutMenuHandler)];
 172         } else {
 173             [self.fAboutMenu setEnabled:NO];
 174             [self.fAboutMenu setTarget:nil];
 175             [self.fAboutMenu setAction:nil];
 176         }
 177     } else {
 178         if ([self.fAboutMenu menu] == nil) return;
 179 
 180         // Remove About item.
 181         removeMenuItem(self.fAboutMenu);
 182     }
 183 }
 184 
 185 - (id) init {
 186 AWT_ASSERT_APPKIT_THREAD;
 187 
 188     self = [super init];
 189     if (!self) return self;
 190 
 191     // Prep for about and preferences menu
 192     BOOL usingDefaultNib = YES;
 193     if ([NSApp isKindOfClass:[NSApplicationAWT class]]) {
 194         usingDefaultNib = [NSApp usingDefaultNib];
 195     }
 196     if (!usingDefaultNib) return self;
 197 
 198     NSMenu *menuBar = [[NSApplication sharedApplication] mainMenu];
 199     NSMenu *appMenu = [[menuBar itemAtIndex:0] submenu];
 200 
 201     self.fPreferencesMenu = (NSMenuItem*)[appMenu itemWithTag:PREFERENCES_TAG];
 202     self.fAboutMenu = (NSMenuItem*)[appMenu itemAtIndex:0];
 203     
 204     NSDockTile *dockTile = [NSApp dockTile];
 205     self.fProgressIndicator = [[NSProgressIndicator alloc]
 206                                 initWithFrame:NSMakeRect(3.f, 0.f, dockTile.size.width - 6.f, 20.f)];
 207     
 208     [fProgressIndicator setStyle:NSProgressIndicatorBarStyle];
 209     [fProgressIndicator setIndeterminate:NO];
 210     [[dockTile contentView] addSubview:fProgressIndicator];
 211     [fProgressIndicator setMinValue:0];
 212     [fProgressIndicator setMaxValue:100];
 213     [fProgressIndicator setHidden:YES];
 214     [fProgressIndicator release];
 215 
 216     // If the java application has a bundle with an Info.plist file with
 217     //  a CFBundleDocumentTypes entry, then it is set up to handle Open Doc
 218     //  and Print Doc commands for these files. Therefore java AWT will
 219     //  cache Open Doc and Print Doc events that are sent prior to a
 220     //  listener being installed by the client java application.
 221     NSBundle *bundle = [NSBundle mainBundle];
 222     fHandlesDocumentTypes = [bundle objectForInfoDictionaryKey:@"CFBundleDocumentTypes"] != nil || [bundle _hasEAWTOverride:@"DocumentHandler"];
 223     fHandlesURLTypes = [bundle objectForInfoDictionaryKey:@"CFBundleURLTypes"] != nil || [bundle _hasEAWTOverride:@"URLHandler"];
 224     if (fHandlesURLTypes) {
 225         [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self
 226                                                            andSelector:@selector(_handleOpenURLEvent:withReplyEvent:)
 227                                                          forEventClass:kInternetEventClass
 228                                                             andEventID:kAEGetURL];
 229     }
 230 
 231     // By HIG, Preferences are not available unless there is a handler. By default in Mac OS X,
 232     //  there is not a handler, but it is in the nib file for convenience.
 233     removeMenuItem(self.fPreferencesMenu);
 234 
 235     [self _updateAboutMenu:YES enabled:YES];
 236 
 237     // Now that the AppKit objects are known and set up, initialize the model data
 238     BOOL aboutAvailable = ([self.fAboutMenu menu] != nil);
 239     BOOL aboutEnabled = (aboutAvailable && [self.fAboutMenu isEnabled] && ([self.fAboutMenu target] != nil));
 240 
 241     BOOL prefsAvailable = ([self.fPreferencesMenu menu] != nil);
 242     BOOL prefsEnabled = (prefsAvailable && [self.fPreferencesMenu isEnabled] && ([self.fPreferencesMenu target] != nil));
 243 
 244     JNIEnv *env = [ThreadUtilities getJNIEnv];
 245     DECLARE_CLASS_RETURN(sjc_AppMenuBarHandler, "com/apple/eawt/_AppMenuBarHandler", NULL);
 246     DECLARE_STATIC_METHOD_RETURN(sjm_initMenuStates, sjc_AppMenuBarHandler, "initMenuStates", "(ZZZZ)V", NULL);
 247     (*env)->CallStaticVoidMethod(env, sjc_AppMenuBarHandler, sjm_initMenuStates,
 248                                  aboutAvailable, aboutEnabled, prefsAvailable, prefsEnabled);
 249     CHECK_EXCEPTION();
 250 
 251     // register for the finish launching and system power off notifications by default
 252     NSNotificationCenter *ctr = [NSNotificationCenter defaultCenter];
 253     Class clz = [ApplicationDelegate class];
 254     [ctr addObserver:clz selector:@selector(_willFinishLaunching) name:NSApplicationWillFinishLaunchingNotification object:nil];
 255     [ctr addObserver:clz selector:@selector(_systemWillPowerOff) name:NSWorkspaceWillPowerOffNotification object:nil];
 256     [ctr addObserver:clz selector:@selector(_appDidActivate) name:NSApplicationDidBecomeActiveNotification object:nil];
 257     [ctr addObserver:clz selector:@selector(_appDidDeactivate) name:NSApplicationDidResignActiveNotification object:nil];
 258     [ctr addObserver:clz selector:@selector(_appDidHide) name:NSApplicationDidHideNotification object:nil];
 259     [ctr addObserver:clz selector:@selector(_appDidUnhide) name:NSApplicationDidUnhideNotification object:nil];
 260 
 261     return self;
 262 }
 263 
 264 - (void)dealloc {
 265     self.fPreferencesMenu = nil;
 266     self.fAboutMenu = nil;
 267     self.fDockMenu = nil;
 268     self.fDefaultMenuBar = nil;
 269     self.fProgressIndicator = nil;
 270 
 271     [super dealloc];
 272 }
 273 
 274 #pragma mark Callbacks from AppKit
 275 
 276 static jclass sjc_AppEventHandler = NULL;
 277 #define GET_APPEVENTHANDLER_CLASS() \
 278     GET_CLASS(sjc_AppEventHandler, "com/apple/eawt/_AppEventHandler");
 279 
 280 #define GET_APPEVENTHANDLER_CLASS_RETURN(ret) \
 281     GET_CLASS_RETURN(sjc_AppEventHandler, "com/apple/eawt/_AppEventHandler", ret);
 282 
 283 - (void)_handleOpenURLEvent:(NSAppleEventDescriptor *)openURLEvent withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
 284 AWT_ASSERT_APPKIT_THREAD;
 285     if (!fHandlesURLTypes) return;
 286 
 287     NSString *url = [[openURLEvent paramDescriptorForKeyword:keyDirectObject] stringValue];
 288 
 289     //fprintf(stderr,"jm_handleOpenURL\n");
 290     JNIEnv *env = [ThreadUtilities getJNIEnv];
 291     jstring jURL = NSStringToJavaString(env, url);
 292     GET_APPEVENTHANDLER_CLASS();
 293     DECLARE_STATIC_METHOD(jm_handleOpenURI, sjc_AppEventHandler, "handleOpenURI", "(Ljava/lang/String;)V");
 294     (*env)->CallStaticVoidMethod(env, sjc_AppEventHandler, jm_handleOpenURI, jURL);
 295     CHECK_EXCEPTION();
 296     (*env)->DeleteLocalRef(env, jURL);
 297 
 298     [replyEvent insertDescriptor:[NSAppleEventDescriptor nullDescriptor] atIndex:0];
 299 }
 300 
 301 // Helper for both open file and print file methods
 302 // Creates a Java list of files from a native list of files
 303 - (jobject)_createFilePathArrayFrom:(NSArray *)filenames withEnv:(JNIEnv *)env {
 304     static jclass sjc_ArrayList = NULL;
 305     if (sjc_ArrayList == NULL) {
 306         sjc_ArrayList = (*env)->FindClass(env, "java/util/ArrayList");
 307         if (sjc_ArrayList != NULL) sjc_ArrayList = (*env)->NewGlobalRef(env, sjc_ArrayList); \
 308     }
 309     CHECK_NULL_RETURN(sjc_ArrayList, NULL);
 310     DECLARE_METHOD_RETURN(jm_ArrayList_ctor, sjc_ArrayList, "<init>", "(I)V", NULL);
 311     DECLARE_METHOD_RETURN(jm_ArrayList_add, sjc_ArrayList, "add", "(Ljava/lang/Object;)Z", NULL);
 312 
 313     jobject jFileNamesArray = (*env)->NewObject(env, sjc_ArrayList, jm_ArrayList_ctor, (jint)[filenames count]);
 314     CHECK_EXCEPTION_NULL_RETURN(jFileNamesArray, NULL);
 315 
 316     for (NSString *filename in filenames) {
 317         jstring jFileName = NormalizedPathJavaStringFromNSString(env, filename);
 318         (*env)->CallVoidMethod(env, jFileNamesArray, jm_ArrayList_add, jFileName);
 319         CHECK_EXCEPTION();
 320     }
 321 
 322     return jFileNamesArray;
 323 }
 324 
 325 // Open file handler
 326 - (void)application:(NSApplication *)theApplication openFiles:(NSArray *)fileNames {
 327 AWT_ASSERT_APPKIT_THREAD;
 328     if (!fHandlesDocumentTypes) {
 329         [theApplication replyToOpenOrPrint:NSApplicationDelegateReplyCancel];
 330         return;
 331     }
 332 
 333     //fprintf(stderr,"jm_handleOpenFile\n");
 334     JNIEnv *env = [ThreadUtilities getJNIEnv];
 335 
 336     // if these files were opened from a Spotlight query, try to get the search text from the current AppleEvent
 337     NSAppleEventDescriptor *currentEvent = [[NSAppleEventManager sharedAppleEventManager] currentAppleEvent];
 338     NSString *searchString = [[currentEvent paramDescriptorForKeyword:keyAESearchText] stringValue];
 339     jstring jSearchString = NSStringToJavaString(env, searchString);
 340 
 341     // convert the file names array
 342     jobject jFileNamesArray = [self _createFilePathArrayFrom:fileNames withEnv:env];
 343 
 344     GET_APPEVENTHANDLER_CLASS();
 345     DECLARE_STATIC_METHOD(jm_handleOpenFiles, sjc_AppEventHandler,
 346                               "handleOpenFiles", "(Ljava/util/List;Ljava/lang/String;)V");
 347     (*env)->CallStaticVoidMethod(env, sjc_AppEventHandler, jm_handleOpenFiles, jFileNamesArray, jSearchString);
 348     CHECK_EXCEPTION();
 349     (*env)->DeleteLocalRef(env, jFileNamesArray);
 350     (*env)->DeleteLocalRef(env, jSearchString);
 351 
 352     [theApplication replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
 353 }
 354 
 355 // Print handler
 356 - (NSApplicationPrintReply)application:(NSApplication *)application printFiles:(NSArray *)fileNames withSettings:(NSDictionary *)printSettings showPrintPanels:(BOOL)showPrintPanels {
 357 AWT_ASSERT_APPKIT_THREAD;
 358     if (!fHandlesDocumentTypes) return NSPrintingCancelled;
 359 
 360     //fprintf(stderr,"jm_handlePrintFile\n");
 361     JNIEnv *env = [ThreadUtilities getJNIEnv];
 362     jobject jFileNamesArray = [self _createFilePathArrayFrom:fileNames withEnv:env];
 363     GET_APPEVENTHANDLER_CLASS_RETURN(NSPrintingCancelled);
 364     DECLARE_STATIC_METHOD_RETURN(jm_handlePrintFile, sjc_AppEventHandler,
 365                               "handlePrintFiles", "(Ljava/util/List;)V", NSPrintingCancelled);
 366     (*env)->CallStaticVoidMethod(env, sjc_AppEventHandler, jm_handlePrintFile, jFileNamesArray);
 367     CHECK_EXCEPTION();
 368     (*env)->DeleteLocalRef(env, jFileNamesArray);
 369 
 370     return NSPrintingSuccess;
 371 }
 372 
 373 // Open app handler, registered in -init
 374 + (void)_notifyJava:(jint)notificationType {
 375 AWT_ASSERT_APPKIT_THREAD;
 376 
 377     //fprintf(stderr,"jm_handleOpenApplication\n");
 378     JNIEnv *env = [ThreadUtilities getJNIEnv];
 379     GET_APPEVENTHANDLER_CLASS();
 380     DECLARE_STATIC_METHOD(jm_handleNativeNotification, sjc_AppEventHandler, "handleNativeNotification", "(I)V");
 381     (*env)->CallStaticVoidMethod(env, sjc_AppEventHandler, jm_handleNativeNotification, notificationType);
 382     CHECK_EXCEPTION();
 383 }
 384 
 385 // About menu handler
 386 - (void)_aboutMenuHandler {
 387     [ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_ABOUT];
 388 }
 389 
 390 // Preferences handler
 391 - (void)_preferencesMenuHandler {
 392     [ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_PREFS];
 393 }
 394 
 395 // Open app handler, registered in -init
 396 + (void)_willFinishLaunching {
 397     [self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_OPEN_APP];
 398 }
 399 
 400 // ReOpen app handler
 401 - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag {
 402     [ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_REOPEN_APP];
 403     return YES;
 404 }
 405 
 406 // Quit handler
 407 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app {
 408     [ApplicationDelegate _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_QUIT];
 409     return NSTerminateLater;
 410 }
 411 
 412 + (void)_systemWillPowerOff {
 413     [self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SHUTDOWN];
 414 }
 415 
 416 + (void)_appDidActivate {
 417     [self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_ACTIVE_APP_GAINED];
 418 }
 419 
 420 + (void)_appDidDeactivate {
 421     [self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_ACTIVE_APP_LOST];
 422 }
 423 
 424 + (void)_appDidHide {
 425     [self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_APP_HIDDEN];
 426 }
 427 
 428 + (void)_appDidUnhide {
 429     [self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_APP_SHOWN];
 430 }
 431 
 432 + (void)_sessionDidActivate {
 433     [self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_USER_SESSION_ACTIVE];
 434 }
 435 
 436 + (void)_sessionDidDeactivate {
 437     [self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_USER_SESSION_INACTIVE];
 438 }
 439 
 440 + (void)_screenDidSleep {
 441     [self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SCREEN_SLEEP];
 442 }
 443 
 444 + (void)_screenDidWake {
 445     [self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SCREEN_WAKE];
 446 }
 447 
 448 + (void)_systemDidSleep {
 449     [self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SYSTEM_SLEEP];
 450 }
 451 
 452 + (void)_systemDidWake {
 453     [self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SYSTEM_WAKE];
 454 }
 455 
 456 + (void)_registerForNotification:(NSNumber *)notificationTypeNum {
 457     NSNotificationCenter *ctr = [[NSWorkspace sharedWorkspace] notificationCenter];
 458     Class clz = [ApplicationDelegate class];
 459 
 460     jint notificationType = [notificationTypeNum intValue];
 461     switch (notificationType) {
 462         case com_apple_eawt__AppEventHandler_REGISTER_USER_SESSION:
 463             [ctr addObserver:clz selector:@selector(_sessionDidActivate) name:NSWorkspaceSessionDidBecomeActiveNotification object:nil];
 464             [ctr addObserver:clz selector:@selector(_sessionDidDeactivate) name:NSWorkspaceSessionDidResignActiveNotification object:nil];
 465             break;
 466         case com_apple_eawt__AppEventHandler_REGISTER_SCREEN_SLEEP:
 467             [ctr addObserver:clz selector:@selector(_screenDidSleep) name:NSWorkspaceScreensDidSleepNotification object:nil];
 468             [ctr addObserver:clz selector:@selector(_screenDidWake) name:NSWorkspaceScreensDidWakeNotification object:nil];
 469             break;
 470         case com_apple_eawt__AppEventHandler_REGISTER_SYSTEM_SLEEP:
 471             [ctr addObserver:clz selector:@selector(_systemDidSleep) name:NSWorkspaceWillSleepNotification object:nil];
 472             [ctr addObserver:clz selector:@selector(_systemDidWake) name:NSWorkspaceDidWakeNotification object:nil];
 473             break;
 474         default:
 475             NSLog(@"EAWT attempting to register for unknown notification: %d", (int)notificationType);
 476             break;
 477     }
 478 }
 479 
 480 // Retrieves the menu to be attached to the Dock icon (AppKit callback)
 481 - (NSMenu *)applicationDockMenu:(NSApplication *)sender {
 482 AWT_ASSERT_APPKIT_THREAD;
 483     return self.fDockMenu;
 484 }
 485 
 486 - (CMenuBar *)defaultMenuBar {
 487     return [[self.fDefaultMenuBar retain] autorelease];
 488 }
 489 
 490 
 491 #pragma mark Helpers called on the main thread from Java
 492 
 493 // Sets a new NSImageView on the Dock tile
 494 + (void)_setDockIconImage:(NSImage *)image {
 495 AWT_ASSERT_APPKIT_THREAD;
 496 
 497     NSDockTile *dockTile = [NSApp dockTile];
 498     if (image == nil) {
 499         [dockTile setContentView:nil];
 500         return;
 501     }
 502 
 503     // setup an image view for the dock tile
 504     NSRect frame = NSMakeRect(0, 0, dockTile.size.width, dockTile.size.height);
 505     NSImageView *dockImageView = [[NSImageView alloc] initWithFrame: frame];
 506     [dockImageView setImageScaling:NSImageScaleProportionallyUpOrDown];
 507     [dockImageView setImage:image];
 508 
 509     [[ApplicationDelegate sharedDelegate].fProgressIndicator removeFromSuperview];
 510     [dockImageView addSubview:[ApplicationDelegate sharedDelegate].fProgressIndicator];
 511 
 512     // add it to the NSDockTile
 513     [dockTile setContentView: dockImageView];
 514     [dockTile display];
 515 
 516     [dockImageView release];
 517 }
 518 
 519 + (void)_setDockIconProgress:(NSNumber *)value {
 520 AWT_ASSERT_APPKIT_THREAD;
 521 
 522     ApplicationDelegate *delegate = [ApplicationDelegate sharedDelegate];
 523     if ([value doubleValue] >= 0 && [value doubleValue] <=100) {
 524         [delegate.fProgressIndicator setDoubleValue:[value doubleValue]];
 525         [delegate.fProgressIndicator setHidden:NO];
 526     } else {
 527         [delegate.fProgressIndicator setHidden:YES];
 528     }
 529 
 530     [[NSApp dockTile] display];
 531 }
 532 
 533 // Obtains the image of the Dock icon, either manually set, a drawn copy, or the default NSApplicationIcon
 534 + (NSImage *)_dockIconImage {
 535 AWT_ASSERT_APPKIT_THREAD;
 536 
 537     NSDockTile *dockTile = [NSApp dockTile];
 538     NSView *view = [dockTile contentView];
 539 
 540     if ([view isKindOfClass:[NSImageView class]]) {
 541         NSImage *img = [((NSImageView *)view) image];
 542         if (img) return img;
 543     }
 544 
 545     if (view == nil) {
 546         return [NSImage imageNamed:@"NSApplicationIcon"];
 547     }
 548 
 549     NSRect frame = [view frame];
 550     NSImage *image = [[NSImage alloc] initWithSize:frame.size];
 551     [image lockFocus];
 552     [view drawRect:frame];
 553     [image unlockFocus];
 554     [image autorelease];
 555     return image;
 556 }
 557 
 558 @end
 559 
 560 
 561 #pragma mark Native JNI calls
 562 
 563 /*
 564  * Class:     com_apple_eawt_Application
 565  * Method:    nativeInitializeApplicationDelegate
 566  * Signature: ()V
 567  */
 568 JNIEXPORT void JNICALL Java_com_apple_eawt_Application_nativeInitializeApplicationDelegate
 569 (JNIEnv *env, jclass clz)
 570 {
 571 JNI_COCOA_ENTER(env);
 572     // Force initialization to happen on AppKit thread!
 573     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 574         [ApplicationDelegate sharedDelegate];
 575     }];
 576 JNI_COCOA_EXIT(env);
 577 }
 578 
 579 /*
 580  * Class:     com_apple_eawt__AppEventHandler
 581  * Method:    nativeOpenCocoaAboutWindow
 582  * Signature: ()V
 583  */
 584 JNIEXPORT void JNICALL Java_com_apple_eawt__1AppEventHandler_nativeOpenCocoaAboutWindow
 585 (JNIEnv *env, jclass clz)
 586 {
 587 JNI_COCOA_ENTER(env);
 588 
 589     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 590         [NSApp orderFrontStandardAboutPanel:nil];
 591     }];
 592 
 593 JNI_COCOA_EXIT(env);
 594 }
 595 
 596 /*
 597  * Class:     com_apple_eawt__AppEventHandler
 598  * Method:    nativeReplyToAppShouldTerminate
 599  * Signature: (Z)V
 600  */
 601 JNIEXPORT void JNICALL Java_com_apple_eawt__1AppEventHandler_nativeReplyToAppShouldTerminate
 602 (JNIEnv *env, jclass clz, jboolean doTerminate)
 603 {
 604 JNI_COCOA_ENTER(env);
 605 
 606     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 607         [NSApp replyToApplicationShouldTerminate:doTerminate];
 608     }];
 609 
 610 JNI_COCOA_EXIT(env);
 611 }
 612 
 613 /*
 614  * Class:     com_apple_eawt__AppEventHandler
 615  * Method:    nativeRegisterForNotification
 616  * Signature: (I)V
 617  */
 618 JNIEXPORT void JNICALL Java_com_apple_eawt__1AppEventHandler_nativeRegisterForNotification
 619 (JNIEnv *env, jclass clz, jint notificationType)
 620 {
 621 JNI_COCOA_ENTER(env);
 622     [ThreadUtilities performOnMainThread:@selector(_registerForNotification:)
 623                                       on:[ApplicationDelegate class]
 624                               withObject:[NSNumber numberWithInt:notificationType]
 625                            waitUntilDone:NO];
 626 JNI_COCOA_EXIT(env);
 627 }
 628 
 629 /*
 630  * Class:     com_apple_eawt__AppDockIconHandler
 631  * Method:    nativeSetDockMenu
 632  * Signature: (J)V
 633  */
 634 JNIEXPORT void JNICALL Java_com_apple_eawt__1AppDockIconHandler_nativeSetDockMenu
 635 (JNIEnv *env, jclass clz, jlong nsMenuPtr)
 636 {
 637 JNI_COCOA_ENTER(env);
 638 
 639     NSMenu *menu = (NSMenu *)jlong_to_ptr(nsMenuPtr);
 640     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 641         [ApplicationDelegate sharedDelegate].fDockMenu = menu;
 642     }];
 643 
 644 JNI_COCOA_EXIT(env);
 645 }
 646 
 647 /*
 648  * Class:     com_apple_eawt__AppDockIconHandler
 649  * Method:    nativeSetDockIconImage
 650  * Signature: (J)V
 651  */
 652 JNIEXPORT void JNICALL Java_com_apple_eawt__1AppDockIconHandler_nativeSetDockIconImage
 653 (JNIEnv *env, jclass clz, jlong nsImagePtr)
 654 {
 655 JNI_COCOA_ENTER(env);
 656 
 657     NSImage *_image = (NSImage *)jlong_to_ptr(nsImagePtr);
 658     [ThreadUtilities performOnMainThread:@selector(_setDockIconImage:)
 659                                       on:[ApplicationDelegate class]
 660                               withObject:_image
 661                            waitUntilDone:NO];
 662 
 663 JNI_COCOA_EXIT(env);
 664 }
 665 
 666 /*
 667  * Class:     com_apple_eawt__AppDockIconHandler
 668  * Method:    nativeSetDockIconProgress
 669  * Signature: (I)V
 670  */
 671 JNIEXPORT void JNICALL Java_com_apple_eawt__1AppDockIconHandler_nativeSetDockIconProgress
 672   (JNIEnv *env, jclass clz, jint value)
 673 {
 674     JNI_COCOA_ENTER(env);
 675 
 676      [ThreadUtilities performOnMainThread:@selector(_setDockIconProgress:)
 677                                        on:[ApplicationDelegate class]
 678                                withObject:[NSNumber numberWithInt:value]
 679                             waitUntilDone:NO];
 680 
 681     JNI_COCOA_EXIT(env);
 682 }
 683 
 684 /*
 685  * Class:     com_apple_eawt__AppDockIconHandler
 686  * Method:    nativeGetDockIconImage
 687  * Signature: ()J
 688  */
 689 JNIEXPORT jlong JNICALL Java_com_apple_eawt__1AppDockIconHandler_nativeGetDockIconImage
 690 (JNIEnv *env, jclass clz)
 691 {
 692     __block NSImage *image = nil;
 693 
 694 JNI_COCOA_ENTER(env);
 695 
 696     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 697         image = [[ApplicationDelegate _dockIconImage] retain];
 698     }];
 699 
 700 JNI_COCOA_EXIT(env);
 701 
 702     return ptr_to_jlong(image);
 703 }
 704 
 705 /*
 706  * Class:     com_apple_eawt__AppDockIconHandler
 707  * Method:    nativeSetDockIconBadge
 708  * Signature: (Ljava/lang/String;)V
 709  */
 710 JNIEXPORT void JNICALL Java_com_apple_eawt__1AppDockIconHandler_nativeSetDockIconBadge
 711 (JNIEnv *env, jclass clz, jstring badge)
 712 {
 713 JNI_COCOA_ENTER(env);
 714 
 715     NSString *badgeString = JavaStringToNSString(env, badge);
 716     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 717         NSDockTile *dockTile = [NSApp dockTile];
 718         [dockTile setBadgeLabel:badgeString];
 719         [dockTile display];
 720     }];
 721 
 722 JNI_COCOA_EXIT(env);
 723 }
 724 
 725 /*
 726  * Class:     com_apple_eawt__AppMiscHandlers
 727  * Method:    nativeRequestActivation
 728  * Signature: (Z)V
 729  */
 730 JNIEXPORT void JNICALL Java_com_apple_eawt__1AppMiscHandlers_nativeRequestActivation
 731 (JNIEnv *env, jclass clz, jboolean allWindows)
 732 {
 733 JNI_COCOA_ENTER(env);
 734 
 735     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 736         NSApplicationActivationOptions options = allWindows ? NSApplicationActivateAllWindows : 0;
 737         options |= NSApplicationActivateIgnoringOtherApps; // without this, nothing happens!
 738         [[NSRunningApplication currentApplication] activateWithOptions:options];
 739     }];
 740 
 741 JNI_COCOA_EXIT(env);
 742 }
 743 
 744 /*
 745  * Class:     com_apple_eawt__AppMiscHandlers
 746  * Method:    nativeRequestUserAttention
 747  * Signature: (Z)V
 748  */
 749 JNIEXPORT void JNICALL Java_com_apple_eawt__1AppMiscHandlers_nativeRequestUserAttention
 750 (JNIEnv *env, jclass clz, jboolean critical)
 751 {
 752 JNI_COCOA_ENTER(env);
 753 
 754     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 755         [NSApp requestUserAttention:critical ? NSCriticalRequest : NSInformationalRequest];
 756     }];
 757 
 758 JNI_COCOA_EXIT(env);
 759 }
 760 
 761 /*
 762  * Class:     com_apple_eawt__AppMiscHandlers
 763  * Method:    nativeOpenHelpViewer
 764  * Signature: ()V
 765  */
 766 JNIEXPORT void JNICALL Java_com_apple_eawt__1AppMiscHandlers_nativeOpenHelpViewer
 767 (JNIEnv *env, jclass clz)
 768 {
 769 JNI_COCOA_ENTER(env);
 770 
 771     [ThreadUtilities performOnMainThread:@selector(showHelp:)
 772                                       on:NSApp
 773                               withObject:nil
 774                            waitUntilDone:NO];
 775 
 776 JNI_COCOA_EXIT(env);
 777 }
 778 
 779 /*
 780  * Class:     com_apple_eawt__AppMiscHandlers
 781  * Method:    nativeEnableSuddenTermination
 782  * Signature: ()V
 783  */
 784 JNIEXPORT void JNICALL Java_com_apple_eawt__1AppMiscHandlers_nativeEnableSuddenTermination
 785 (JNIEnv *env, jclass clz)
 786 {
 787 JNI_COCOA_ENTER(env);
 788 
 789     [[NSProcessInfo processInfo] enableSuddenTermination]; // Foundation thread-safe
 790 
 791 JNI_COCOA_EXIT(env);
 792 }
 793 
 794 /*
 795  * Class:     com_apple_eawt__AppMiscHandlers
 796  * Method:    nativeDisableSuddenTermination
 797  * Signature: ()V
 798  */
 799 JNIEXPORT void JNICALL Java_com_apple_eawt__1AppMiscHandlers_nativeDisableSuddenTermination
 800 (JNIEnv *env, jclass clz)
 801 {
 802 JNI_COCOA_ENTER(env);
 803 
 804     [[NSProcessInfo processInfo] disableSuddenTermination]; // Foundation thread-safe
 805 
 806 JNI_COCOA_EXIT(env);
 807 }
 808 
 809 /*
 810  * Class:     com_apple_eawt__AppMenuBarHandler
 811  * Method:    nativeSetMenuState
 812  * Signature: (IZZ)V
 813  */
 814 JNIEXPORT void JNICALL Java_com_apple_eawt__1AppMenuBarHandler_nativeSetMenuState
 815 (JNIEnv *env, jclass clz, jint menuID, jboolean visible, jboolean enabled)
 816 {
 817 JNI_COCOA_ENTER(env);
 818 
 819     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 820         ApplicationDelegate *delegate = [ApplicationDelegate sharedDelegate];
 821         switch (menuID) {
 822             case com_apple_eawt__AppMenuBarHandler_MENU_ABOUT:
 823                 [delegate _updateAboutMenu:visible enabled:enabled];
 824                 break;
 825             case com_apple_eawt__AppMenuBarHandler_MENU_PREFS:
 826                 [delegate _updatePreferencesMenu:visible enabled:enabled];
 827                 break;
 828         }
 829     }];
 830 
 831 JNI_COCOA_EXIT(env);
 832 }
 833 
 834 /*
 835  * Class:     com_apple_eawt__AppMenuBarHandler
 836  * Method:    nativeSetDefaultMenuBar
 837  * Signature: (J)V
 838  */
 839 JNIEXPORT void JNICALL Java_com_apple_eawt__1AppMenuBarHandler_nativeSetDefaultMenuBar
 840 (JNIEnv *env, jclass clz, jlong cMenuBarPtr)
 841 {
 842 JNI_COCOA_ENTER(env);
 843 
 844     CMenuBar *menu = (CMenuBar *)jlong_to_ptr(cMenuBarPtr);
 845     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 846         [ApplicationDelegate sharedDelegate].fDefaultMenuBar = menu;
 847     }];
 848 
 849 JNI_COCOA_EXIT(env);
 850 }