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