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