1/* 2 * Copyright (c) 2011, 2013, 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 <Cocoa/Cocoa.h> 27 28#import "QueuingApplicationDelegate.h" 29 30@interface NSBundle (EAWTOverrides) 31- (BOOL)_hasEAWTOverride:(NSString *)key; 32@end 33 34 35@implementation NSBundle (EAWTOverrides) 36 37- (BOOL)_hasEAWTOverride:(NSString *)key { 38 return [[[[self objectForInfoDictionaryKey:@"Java"] objectForKey:@"EAWTOverride"] objectForKey:key] boolValue]; 39} 40 41@end 42 43@implementation QueuingApplicationDelegate 44 45@synthesize realDelegate; 46@synthesize queue; 47 48+ (QueuingApplicationDelegate*) sharedDelegate 49{ 50 static QueuingApplicationDelegate * qad = nil; 51 52 if (!qad) { 53 qad = [QueuingApplicationDelegate new]; 54 } 55 56 return qad; 57} 58 59- (id) init 60{ 61 self = [super init]; 62 if (!self) { 63 return self; 64 } 65 66 self.queue = [NSMutableArray arrayWithCapacity: 0]; 67 68 // If the java application has a bundle with an Info.plist file with 69 // a CFBundleDocumentTypes entry, then it is set up to handle Open Doc 70 // and Print Doc commands for these files. Therefore java AWT will 71 // cache Open Doc and Print Doc events that are sent prior to a 72 // listener being installed by the client java application. 73 NSBundle *bundle = [NSBundle mainBundle]; 74 fHandlesDocumentTypes = [bundle objectForInfoDictionaryKey:@"CFBundleDocumentTypes"] != nil || [bundle _hasEAWTOverride:@"DocumentHandler"]; 75 fHandlesURLTypes = [bundle objectForInfoDictionaryKey:@"CFBundleURLTypes"] != nil || [bundle _hasEAWTOverride:@"URLHandler"]; 76 if (fHandlesURLTypes) { 77 [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self 78 andSelector:@selector(_handleOpenURLEvent:withReplyEvent:) 79 forEventClass:kInternetEventClass 80 andEventID:kAEGetURL]; 81 } 82 83 NSNotificationCenter *ctr = [NSNotificationCenter defaultCenter]; 84 [ctr addObserver:self selector:@selector(_willFinishLaunching) name:NSApplicationWillFinishLaunchingNotification object:nil]; 85 [ctr addObserver:self selector:@selector(_systemWillPowerOff) name:NSWorkspaceWillPowerOffNotification object:nil]; 86 [ctr addObserver:self selector:@selector(_appDidActivate) name:NSApplicationDidBecomeActiveNotification object:nil]; 87 [ctr addObserver:self selector:@selector(_appDidDeactivate) name:NSApplicationDidResignActiveNotification object:nil]; 88 [ctr addObserver:self selector:@selector(_appDidHide) name:NSApplicationDidHideNotification object:nil]; 89 [ctr addObserver:self selector:@selector(_appDidUnhide) name:NSApplicationDidUnhideNotification object:nil]; 90 91 return self; 92} 93 94- (void)dealloc 95{ 96 if (fHandlesURLTypes) { 97 [[NSAppleEventManager sharedAppleEventManager] removeEventHandlerForEventClass: kInternetEventClass andEventID:kAEGetURL]; 98 } 99 100 NSNotificationCenter *ctr = [NSNotificationCenter defaultCenter]; 101 Class clz = [QueuingApplicationDelegate class]; 102 [ctr removeObserver:clz]; 103 104 self.queue = nil; 105 self.realDelegate = nil; 106 107 [super dealloc]; 108} 109 110 111- (void)_handleOpenURLEvent:(NSAppleEventDescriptor *)openURLEvent withReplyEvent:(NSAppleEventDescriptor *)replyEvent 112{ 113 // Make an explicit copy of the passed events as they may be invalidated by the time they're processed 114 NSAppleEventDescriptor *openURLEventCopy = [openURLEvent copy]; 115 NSAppleEventDescriptor *replyEventCopy = [replyEvent copy]; 116 117 [self.queue addObject:[^(){ 118 [self.realDelegate _handleOpenURLEvent:openURLEventCopy withReplyEvent:replyEventCopy]; 119 [openURLEventCopy release]; 120 [replyEventCopy release]; 121 } copy]]; 122} 123 124- (void)application:(NSApplication *)theApplication openFiles:(NSArray *)fileNames 125{ 126 [self.queue addObject:[^(){ 127 [self.realDelegate application:theApplication openFiles:fileNames]; 128 } copy]]; 129} 130 131- (NSApplicationPrintReply)application:(NSApplication *)application printFiles:(NSArray *)fileNames withSettings:(NSDictionary *)printSettings showPrintPanels:(BOOL)showPrintPanels 132{ 133 if (!fHandlesDocumentTypes) { 134 return NSPrintingCancelled; 135 } 136 137 [self.queue addObject:[^(){ 138 [self.realDelegate application:application printFiles:fileNames withSettings:printSettings showPrintPanels:showPrintPanels]; 139 } copy]]; 140 141 // well, a bit premature, but what else can we do?.. 142 return NSPrintingSuccess; 143} 144 145- (void)_willFinishLaunching 146{ 147 [self.queue addObject:[^(){ 148 [[self.realDelegate class] _willFinishLaunching]; 149 } copy]]; 150} 151 152- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag 153{ 154 [self.queue addObject:[^(){ 155 [self.realDelegate applicationShouldHandleReopen:theApplication hasVisibleWindows:flag]; 156 } copy]]; 157 return YES; 158} 159 160- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app 161{ 162 [self.queue addObject:[^(){ 163 [self.realDelegate applicationShouldTerminate:app]; 164 } copy]]; 165 return NSTerminateLater; 166} 167 168- (void)_systemWillPowerOff 169{ 170 [self.queue addObject:[^(){ 171 [[self.realDelegate class] _systemWillPowerOff]; 172 } copy]]; 173} 174 175- (void)_appDidActivate 176{ 177 [self.queue addObject:[^(){ 178 [[self.realDelegate class] _appDidActivate]; 179 } copy]]; 180} 181 182- (void)_appDidDeactivate 183{ 184 [self.queue addObject:[^(){ 185 [[self.realDelegate class] _appDidDeactivate]; 186 } copy]]; 187} 188 189- (void)_appDidHide 190{ 191 [self.queue addObject:[^(){ 192 [[self.realDelegate class] _appDidHide]; 193 } copy]]; 194} 195 196- (void)_appDidUnhide 197{ 198 [self.queue addObject:[^(){ 199 [[self.realDelegate class] _appDidUnhide]; 200 } copy]]; 201} 202 203- (void)processQueuedEventsWithTargetDelegate:(id <NSApplicationDelegate>)delegate 204{ 205 self.realDelegate = delegate; 206 207 NSUInteger i; 208 NSUInteger count = [self.queue count]; 209 210 for (i = 0; i < count; i++) { 211 void (^event)() = (void (^)())[self.queue objectAtIndex: i]; 212 event(); 213 [event release]; 214 } 215 216 [self.queue removeAllObjects]; 217} 218 219@end 220 221