Bug 691662 - Update shipped Growl framework to 1.2.2 for compatibility with Growl 1.3. r=smichaud
authorMarkus Stange <mstange@themasta.com>
Sun, 13 Nov 2011 09:02:52 +0100
changeset 80206 11ed523f1ea2df581b9f8913478d480721c658b9
parent 80205 2da841d9692593db16236bba80ab0c6f53c49843
child 80207 4eb3558c97ada411f9a6e9750d02868c56c1d503
push id323
push userrcampbell@mozilla.com
push dateTue, 15 Nov 2011 21:58:36 +0000
treeherderfx-team@3ea216303184 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmichaud
bugs691662
milestone11.0a1
Bug 691662 - Update shipped Growl framework to 1.2.2 for compatibility with Growl 1.3. r=smichaud
toolkit/components/alerts/mac/growl/CFGrowlAdditions.c
toolkit/components/alerts/mac/growl/CFGrowlAdditions.h
toolkit/components/alerts/mac/growl/GrowlApplicationBridge.m
toolkit/components/alerts/mac/growl/GrowlDefinesInternal.h
toolkit/components/alerts/mac/growl/GrowlPathUtilities.m
--- a/toolkit/components/alerts/mac/growl/CFGrowlAdditions.c
+++ b/toolkit/components/alerts/mac/growl/CFGrowlAdditions.c
@@ -1,13 +1,13 @@
 //
 //  CFGrowlAdditions.c
 //  Growl
 //
-//  Created by Mac-arena the Bored Zo on Wed Jun 18 2004.
+//  Created by Peter Hosey on Wed Jun 18 2004.
 //  Copyright 2005-2006 The Growl Project.
 //
 // This file is under the BSD License, refer to License.txt for details
 
 #include <Carbon/Carbon.h>
 #include <unistd.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
--- a/toolkit/components/alerts/mac/growl/CFGrowlAdditions.h
+++ b/toolkit/components/alerts/mac/growl/CFGrowlAdditions.h
@@ -1,13 +1,13 @@
 //
 //  CFGrowlAdditions.h
 //  Growl
 //
-//  Created by Mac-arena the Bored Zo on Wed Jun 18 2004.
+//  Created by Peter Hosey on Wed Jun 18 2004.
 //  Copyright 2005-2006 The Growl Project.
 //
 // This file is under the BSD License, refer to License.txt for details
 
 #ifndef HAVE_CFGROWLADDITIONS_H
 #define HAVE_CFGROWLADDITIONS_H
 
 #include "CFGrowlDefines.h"
--- a/toolkit/components/alerts/mac/growl/GrowlApplicationBridge.m
+++ b/toolkit/components/alerts/mac/growl/GrowlApplicationBridge.m
@@ -288,17 +288,17 @@ static BOOL		registerWhenGrowlIsReady = 
 																		 userInfo:userInfo
 															   deliverImmediately:NO];
 		}
 	} else {
 #ifdef GROWL_WITH_INSTALLER
 		/*if Growl launches, and the user hasn't already said NO to installing
 		 *	it, store this notification for posting
 		 */
-		if (!userChoseNotToInstallGrowl) {
+		if (!([self isGrowlInstalled] || userChoseNotToInstallGrowl)) {
 			if (!queuedGrowlNotifications)
 				queuedGrowlNotifications = [[NSMutableArray alloc] init];
 			[queuedGrowlNotifications addObject:userInfo];
 
 			//if we have not already asked the user to install Growl, do it now
 			if (!promptedToInstallGrowl) {
 				[GrowlInstallationPrompt showInstallationPrompt];
 				promptedToInstallGrowl = YES;
@@ -443,17 +443,17 @@ static BOOL		registerWhenGrowlIsReady = 
 				if (file_data) {
 					NSDictionary *location = [[NSDictionary alloc] initWithObjectsAndKeys:file_data, @"file-data", nil];
 					[file_data release];
 					[mRegDict setObject:location forKey:GROWL_APP_LOCATION];
 					[location release];
 				} else {
 					[mRegDict removeObjectForKey:GROWL_APP_LOCATION];
 				}
-				[myURL release];
+				[NSMakeCollectable(myURL) release];
 			}
 		}
 	}
 
 	if ((!keys) || [keys containsObject:GROWL_NOTIFICATIONS_DEFAULT]) {
 		if (![mRegDict objectForKey:GROWL_NOTIFICATIONS_DEFAULT]) {
 			NSArray *all = [mRegDict objectForKey:GROWL_NOTIFICATIONS_ALL];
 			if (all)
@@ -544,17 +544,17 @@ static BOOL		registerWhenGrowlIsReady = 
 		iconData = [regDict objectForKey:GROWL_APP_ICON];
 
 	if (iconData && [iconData isKindOfClass:[NSImage class]])
 		iconData = [(NSImage *)iconData TIFFRepresentation];
 
 	if (!iconData) {
 		NSURL *URL = copyCurrentProcessURL();
 		iconData = [copyIconDataForURL(URL) autorelease];
-		[URL release];
+		[NSMakeCollectable(URL) release];
 	}
 
 	return iconData;
 }
 
 /*Selector called when a growl notification is clicked.  This should never be
  *	called manually, and the calling observer should only be registered if the
  *	delegate responds to growlNotificationWasClicked:.
@@ -719,35 +719,106 @@ static BOOL		registerWhenGrowlIsReady = 
 		}
 	}
 	[infoDict release];
 }
 #endif
 
 #pragma mark -
 
++ (OSStatus) getPSN:(struct ProcessSerialNumber *)outAppPSN forAppWithBundleAtPath:(NSString *)appPath {
+	OSStatus err;
+	while ((err = GetNextProcess(outAppPSN)) == noErr) {
+		NSDictionary *dict = [NSMakeCollectable(ProcessInformationCopyDictionary(outAppPSN, kProcessDictionaryIncludeAllInformationMask)) autorelease];
+		NSString *bundlePath = [dict objectForKey:@"BundlePath"];
+		if ([bundlePath isEqualToString:appPath]) {
+			//Match!
+			break;
+		}
+	}
+	return err;
+}
+
++ (BOOL) launchApplicationWithBundleAtPath:(NSString *)appPath openDocumentURL:(NSURL *)regItemURL {
+	const struct LSLaunchURLSpec spec = {
+		.appURL = (CFURLRef)[NSURL fileURLWithPath:appPath],
+		.itemURLs = (CFArrayRef)(regItemURL ? [NSArray arrayWithObject:regItemURL] : nil),
+		.passThruParams = NULL,
+		.launchFlags = kLSLaunchDontAddToRecents | kLSLaunchDontSwitch | kLSLaunchNoParams | kLSLaunchAsync,
+		.asyncRefCon = NULL
+	};
+	OSStatus err = LSOpenFromURLSpec(&spec, NULL);
+	if (err != noErr) {
+		NSLog(@"Could not launch application at path %@ (with document %@) because LSOpenFromURLSpec returned %i (%s)", appPath, regItemURL, err, GetMacOSStatusCommentString(err));
+	}
+	return (err == noErr);
+}
++ (BOOL) sendOpenEventToProcessWithProcessSerialNumber:(struct ProcessSerialNumber *)appPSN openDocumentURL:(NSURL *)regItemURL {
+	OSStatus err;
+	BOOL success = NO;
+	AEStreamRef stream = AEStreamCreateEvent(kCoreEventClass, kAEOpenDocuments,
+											 //Target application
+											 typeProcessSerialNumber, appPSN, sizeof(*appPSN),
+											 kAutoGenerateReturnID, kAnyTransactionID);
+	if (!stream) {
+		NSLog(@"%@: Could not create open-document event to register this application with Growl", [self class]);
+	} else {
+		if (regItemURL) {
+			NSString *regItemURLString = [regItemURL absoluteString];
+			NSData *regItemURLUTF8Data = [regItemURLString dataUsingEncoding:NSUTF8StringEncoding];
+			err = AEStreamWriteKeyDesc(stream, keyDirectObject, typeFileURL, [regItemURLUTF8Data bytes], [regItemURLUTF8Data length]);
+			if (err != noErr) {
+				NSLog(@"%@: Could not set direct object of open-document event to register this application with Growl because AEStreamWriteKeyDesc returned %li/%s", [self class], (long)err, GetMacOSStatusCommentString(err));
+			}
+		}
+
+		AppleEvent event;
+		err = AEStreamClose(stream, &event);
+		if (err != noErr) {
+			NSLog(@"%@: Could not finish open-document event to register this application with Growl because AEStreamClose returned %li/%s", [self class], (long)err, GetMacOSStatusCommentString(err));
+		} else {
+			err = AESendMessage(&event, /*reply*/ NULL, kAENoReply | kAEDontReconnect | kAENeverInteract | kAEDontRecord, kAEDefaultTimeout);
+			if (err != noErr) {
+				NSLog(@"%@: Could not send open-document event to register this application with Growl because AESend returned %li/%s", [self class], (long)err, GetMacOSStatusCommentString(err));
+			}
+
+			AEDisposeDesc(&event);
+		}
+
+		success = (err == noErr);
+	}
+
+	return success;
+}
 + (BOOL) _launchGrowlIfInstalledWithRegistrationDictionary:(NSDictionary *)regDict {
 	BOOL success = NO;
-	NSBundle *growlPrefPaneBundle;
+	NSBundle *growlPrefPaneBundle = nil;
 	NSString *growlHelperAppPath;
 
-#ifdef DEBUG
-	//For a debug build, first look for a running GHA. It might not actually be within a Growl prefpane bundle.
+	//First look for a running GHA. It might not actually be within a Growl prefpane bundle.
 	growlHelperAppPath = [[GrowlPathUtilities runningHelperAppBundle] bundlePath];
+	if (growlHelperAppPath) {
+		//The GHA bundle path should be: .../Growl.prefPane/Contents/Resources/GrowlHelperApp.app
+		NSArray *growlHelperAppPathComponents = [growlHelperAppPath pathComponents];
+		NSString *growlPrefPaneBundlePath = [NSString pathWithComponents:[growlHelperAppPathComponents subarrayWithRange:(NSRange){ 0UL, [growlHelperAppPathComponents count] - 3UL }]];
+		growlPrefPaneBundle = [NSBundle bundleWithPath:growlPrefPaneBundlePath];
+		//Make sure we actually got a Growl.prefPane and not, say, a Growl project folder. (NSBundle can be liberal in its acceptance of a directory as a bundle at times.)
+		if (![[growlPrefPaneBundle bundleIdentifier] isEqualToString:GROWL_PREFPANE_BUNDLE_IDENTIFIER])
+			growlPrefPaneBundle = nil;
+	}
+	//If we didn't get a Growl prefpane bundle by finding the bundle that contained GHA, look it up directly.
+	if (!growlPrefPaneBundle) {
+		growlPrefPaneBundle = [GrowlPathUtilities growlPrefPaneBundle];
+	}
+	//If we don't already have the path to a running GHA, then…
 	if (!growlHelperAppPath) {
-		growlPrefPaneBundle = [GrowlPathUtilities growlPrefPaneBundle];
+		//Look for an installed-but-not-running GHA.
 		growlHelperAppPath = [growlPrefPaneBundle pathForResource:@"GrowlHelperApp"
 														   ofType:@"app"];
 	}
-	NSLog(@"Will use GrowlHelperApp at %@", growlHelperAppPath);
-#else
-	growlPrefPaneBundle = [GrowlPathUtilities growlPrefPaneBundle];
-	growlHelperAppPath = [growlPrefPaneBundle pathForResource:@"GrowlHelperApp"
-													   ofType:@"app"];
-#endif
 
 #ifdef GROWL_WITH_INSTALLER
 	if (growlPrefPaneBundle) {
 		/* Check against our current version number and ensure the installed Growl pane is the same or later */
 		[self _checkForPackagedUpdateForGrowlPrefPaneBundle:growlPrefPaneBundle];
 	}
 #endif
 
@@ -757,26 +828,22 @@ static BOOL		registerWhenGrowlIsReady = 
 		NSURL *appURL = [NSURL fileURLWithPath:growlHelperAppPath];
 		if (appURL) {
 			OSStatus err;
 
 			//Find the PSN for GrowlHelperApp. (We'll need this later.)
 			struct ProcessSerialNumber appPSN = {
 				0, kNoProcess
 			};
-			while ((err = GetNextProcess(&appPSN)) == noErr) {
-				NSDictionary *dict = [(id)ProcessInformationCopyDictionary(&appPSN, kProcessDictionaryIncludeAllInformationMask) autorelease];
-				NSString *bundlePath = [dict objectForKey:@"BundlePath"];
-				if ([bundlePath isEqualToString:growlHelperAppPath]) {
-					//Match!
-					break;
-				}
-			}
+			err = [self getPSN:&appPSN forAppWithBundleAtPath:growlHelperAppPath];
+			BOOL foundGrowlProcess = (err == noErr);
+			BOOL foundNoGrowlProcess = (err == procNotFound);
 
-			if (err == noErr) {
+			//If both of these are false, the process search failed with an error (and I don't mean procNotFound).
+			if (foundGrowlProcess || foundNoGrowlProcess) {
 				NSURL *regItemURL = nil;
 				BOOL passRegDict = NO;
 
 				if (regDict) {
 					NSString *regDictFileName;
 					NSString *regDictPath;
 
 					//Obtain a truly unique file name
@@ -809,45 +876,20 @@ static BOOL		registerWhenGrowlIsReady = 
 					}
 
 					if ([[NSFileManager defaultManager] fileExistsAtPath:regDictPath]) {
 						regItemURL = [NSURL fileURLWithPath:regDictPath];
 						passRegDict = YES;
 					}
 				}
 
-				AEStreamRef stream = AEStreamCreateEvent(kCoreEventClass, kAEOpenDocuments,
-					//Target application
-					typeProcessSerialNumber, &appPSN, sizeof(appPSN),
-					kAutoGenerateReturnID, kAnyTransactionID);
-				if (!stream) {
-					NSLog(@"%@: Could not create open-document event to register this application with Growl", [self class]);
-				} else {
-					if (passRegDict) {
-						NSString *regItemURLString = [regItemURL absoluteString];
-						NSData *regItemURLUTF8Data = [regItemURLString dataUsingEncoding:NSUTF8StringEncoding];
-						err = AEStreamWriteKeyDesc(stream, keyDirectObject, typeFileURL, [regItemURLUTF8Data bytes], [regItemURLUTF8Data length]);
-						if (err != noErr) {
-							NSLog(@"%@: Could not set direct object of open-document event to register this application with Growl because AEStreamWriteKeyDesc returned %li/%s", [self class], (long)err, GetMacOSStatusCommentString(err));
-						}
-					}
-
-					AppleEvent event;
-					err = AEStreamClose(stream, &event);
-					if (err != noErr) {
-						NSLog(@"%@: Could not finish open-document event to register this application with Growl because AEStreamClose returned %li/%s", [self class], (long)err, GetMacOSStatusCommentString(err));
-					} else {
-						err = AESendMessage(&event, /*reply*/ NULL, kAENoReply | kAEDontReconnect | kAENeverInteract | kAEDontRecord, kAEDefaultTimeout);
-						if (err != noErr) {
-							NSLog(@"%@: Could not send open-document event to register this application with Growl because AESend returned %li/%s", [self class], (long)err, GetMacOSStatusCommentString(err));
-						}
-					}
-					
-					success = (err == noErr);
-				}
+				if (foundNoGrowlProcess)
+					success = [self launchApplicationWithBundleAtPath:growlHelperAppPath openDocumentURL:(passRegDict ? regItemURL : nil)];
+				else
+					success = [self sendOpenEventToProcessWithProcessSerialNumber:&appPSN openDocumentURL:(passRegDict ? regItemURL : nil)];
 			}
 		}
 	}
 
 	return success;
 }
 
 /*	+ (BOOL)launchGrowlIfInstalled
--- a/toolkit/components/alerts/mac/growl/GrowlDefinesInternal.h
+++ b/toolkit/components/alerts/mac/growl/GrowlDefinesInternal.h
@@ -288,16 +288,17 @@ struct GrowlNetworkNotification {
 #define PREFERENCE_PANES_SUBFOLDER_OF_LIBRARY	XSTR("PreferencePanes")
 #define PREFERENCE_PANE_EXTENSION				XSTR("prefPane")
 
 //plug-in bundle filename extensions
 #define GROWL_PLUGIN_EXTENSION                  XSTR("growlPlugin")
 #define GROWL_PATHWAY_EXTENSION                 XSTR("growlPathway")
 #define GROWL_VIEW_EXTENSION					XSTR("growlView")
 #define GROWL_STYLE_EXTENSION					XSTR("growlStyle")
+#define GROWL_PATHEXTENSION_TICKET				XSTR("growlTicket")
 
 /* --- These following macros are intended for plug-ins --- */
 
 /*!	@function    SYNCHRONIZE_GROWL_PREFS
  *	@abstract    Synchronizes Growl prefs so they're up-to-date.
  *	@discussion  This macro is intended for use by GrowlHelperApp and by
  *	 plug-ins (when the prefpane is selected).
  */
--- a/toolkit/components/alerts/mac/growl/GrowlPathUtilities.m
+++ b/toolkit/components/alerts/mac/growl/GrowlPathUtilities.m
@@ -5,18 +5,16 @@
 //  Created by Ingmar Stein on 17.04.05.
 //  Copyright 2005-2006 The Growl Project. All rights reserved.
 //
 // This file is under the BSD License, refer to License.txt for details
 
 #import <Cocoa/Cocoa.h>
 
 #import "GrowlPathUtilities.h"
-#import "GrowlPreferencesController.h"
-#import "GrowlTicketController.h"
 #import "GrowlDefinesInternal.h"
 
 static NSBundle *helperAppBundle;
 static NSBundle *prefPaneBundle;
 
 #define NAME_OF_SCREENSHOTS_DIRECTORY           @"Screenshots"
 #define NAME_OF_TICKETS_DIRECTORY               @"Tickets"
 #define NAME_OF_PLUGINS_DIRECTORY               @"Plugins"