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