Switched from using Launch Services to open the .growlRegDict file to sending GHA the open-document event ourselves. This seems to fix the bug where GrowlSafari registering yanks the user out of Safari.
1.1 --- a/Framework/Source/GrowlApplicationBridge.m Thu Sep 24 09:35:42 2009 -0700
1.2 +++ b/Framework/Source/GrowlApplicationBridge.m Thu Sep 24 13:22:25 2009 -0700
1.3 @@ -753,62 +753,97 @@
1.4
1.5 //Houston, we are go for launch.
1.6 if (growlHelperAppPath) {
1.7 - //Let's launch in the background (unfortunately, requires Carbon on Jaguar)
1.8 - LSLaunchFSRefSpec spec;
1.9 - FSRef appRef;
1.10 - OSStatus status = FSPathMakeRef((UInt8 *)[growlHelperAppPath fileSystemRepresentation], &appRef, NULL);
1.11 - if (status == noErr) {
1.12 - FSRef regItemRef;
1.13 - BOOL passRegDict = NO;
1.14 + //Let's launch in the background (requires sending the Apple Event ourselves, as LS may activate the application anyway if it's already running)
1.15 + NSURL *appURL = [NSURL fileURLWithPath:growlHelperAppPath];
1.16 + if (appURL) {
1.17 + OSStatus err;
1.18
1.19 - if (regDict) {
1.20 - OSStatus regStatus;
1.21 - NSString *regDictFileName;
1.22 - NSString *regDictPath;
1.23 + //Find the PSN for GrowlHelperApp. (We'll need this later.)
1.24 + struct ProcessSerialNumber appPSN = {
1.25 + 0, kNoProcess
1.26 + };
1.27 + while ((err = GetNextProcess(&appPSN)) == noErr) {
1.28 + NSDictionary *dict = [(id)ProcessInformationCopyDictionary(&appPSN, kProcessDictionaryIncludeAllInformationMask) autorelease];
1.29 + NSString *bundlePath = [dict objectForKey:@"BundlePath"];
1.30 + if ([bundlePath isEqualToString:growlHelperAppPath]) {
1.31 + //Match!
1.32 + break;
1.33 + }
1.34 + }
1.35
1.36 - //Obtain a truly unique file name
1.37 - CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
1.38 - CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuid);
1.39 - CFRelease(uuid);
1.40 - regDictFileName = [[NSString stringWithFormat:@"%@-%u-%@", [self _applicationNameForGrowlSearchingRegistrationDictionary:regDict], getpid(), (NSString *)uuidString] stringByAppendingPathExtension:GROWL_REG_DICT_EXTENSION];
1.41 - CFRelease(uuidString);
1.42 - if ([regDictFileName length] > NAME_MAX)
1.43 - regDictFileName = [[regDictFileName substringToIndex:(NAME_MAX - [GROWL_REG_DICT_EXTENSION length])] stringByAppendingPathExtension:GROWL_REG_DICT_EXTENSION];
1.44 + if (err == noErr) {
1.45 + NSURL *regItemURL = nil;
1.46 + BOOL passRegDict = NO;
1.47
1.48 - //make sure it's within pathname length constraints
1.49 - regDictPath = [NSTemporaryDirectory() stringByAppendingPathComponent:regDictFileName];
1.50 - if ([regDictPath length] > PATH_MAX)
1.51 - regDictPath = [[regDictPath substringToIndex:(PATH_MAX - [GROWL_REG_DICT_EXTENSION length])] stringByAppendingPathExtension:GROWL_REG_DICT_EXTENSION];
1.52 + if (regDict) {
1.53 + NSString *regDictFileName;
1.54 + NSString *regDictPath;
1.55
1.56 - //Write the registration dictionary out to the temporary directory
1.57 - NSData *plistData;
1.58 - NSString *error;
1.59 - plistData = [NSPropertyListSerialization dataFromPropertyList:regDict
1.60 - format:NSPropertyListBinaryFormat_v1_0
1.61 - errorDescription:&error];
1.62 - if (plistData) {
1.63 - if (![plistData writeToFile:regDictPath atomically:NO])
1.64 - NSLog(@"GrowlApplicationBridge: Error writing registration dictionary at %@", regDictPath);
1.65 - } else {
1.66 - NSLog(@"GrowlApplicationBridge: Error writing registration dictionary at %@: %@", regDictPath, error);
1.67 - NSLog(@"GrowlApplicationBridge: Registration dictionary follows\n%@", regDict);
1.68 - [error release];
1.69 + //Obtain a truly unique file name
1.70 + CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
1.71 + CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuid);
1.72 + CFRelease(uuid);
1.73 + regDictFileName = [[NSString stringWithFormat:@"%@-%u-%@", [self _applicationNameForGrowlSearchingRegistrationDictionary:regDict], getpid(), (NSString *)uuidString] stringByAppendingPathExtension:GROWL_REG_DICT_EXTENSION];
1.74 + CFRelease(uuidString);
1.75 + if ([regDictFileName length] > NAME_MAX)
1.76 + regDictFileName = [[regDictFileName substringToIndex:(NAME_MAX - [GROWL_REG_DICT_EXTENSION length])] stringByAppendingPathExtension:GROWL_REG_DICT_EXTENSION];
1.77 +
1.78 + //make sure it's within pathname length constraints
1.79 + regDictPath = [NSTemporaryDirectory() stringByAppendingPathComponent:regDictFileName];
1.80 + if ([regDictPath length] > PATH_MAX)
1.81 + regDictPath = [[regDictPath substringToIndex:(PATH_MAX - [GROWL_REG_DICT_EXTENSION length])] stringByAppendingPathExtension:GROWL_REG_DICT_EXTENSION];
1.82 +
1.83 + //Write the registration dictionary out to the temporary directory
1.84 + NSData *plistData;
1.85 + NSString *error;
1.86 + plistData = [NSPropertyListSerialization dataFromPropertyList:regDict
1.87 + format:NSPropertyListBinaryFormat_v1_0
1.88 + errorDescription:&error];
1.89 + if (plistData) {
1.90 + if (![plistData writeToFile:regDictPath atomically:NO])
1.91 + NSLog(@"GrowlApplicationBridge: Error writing registration dictionary at %@", regDictPath);
1.92 + } else {
1.93 + NSLog(@"GrowlApplicationBridge: Error writing registration dictionary at %@: %@", regDictPath, error);
1.94 + NSLog(@"GrowlApplicationBridge: Registration dictionary follows\n%@", regDict);
1.95 + [error release];
1.96 + }
1.97 +
1.98 + if ([[NSFileManager defaultManager] fileExistsAtPath:regDictPath]) {
1.99 + regItemURL = [NSURL fileURLWithPath:regDictPath];
1.100 + passRegDict = YES;
1.101 + }
1.102 }
1.103
1.104 - regStatus = FSPathMakeRef((UInt8 *)[regDictPath fileSystemRepresentation], ®ItemRef, NULL);
1.105 - if (regStatus == noErr)
1.106 - passRegDict = YES;
1.107 + AEStreamRef stream = AEStreamCreateEvent(kAECoreSuite, kAEOpen,
1.108 + //Target application
1.109 + typeProcessSerialNumber, &appPSN, sizeof(appPSN),
1.110 + kAutoGenerateReturnID, kAnyTransactionID);
1.111 + if (!stream) {
1.112 + NSLog(@"%@: Could not create open-document event to register this application with Growl", [self class]);
1.113 + } else {
1.114 + if (passRegDict) {
1.115 + NSString *regItemURLString = [regItemURL absoluteString];
1.116 + NSData *regItemURLUTF8Data = [regItemURLString dataUsingEncoding:NSUTF8StringEncoding];
1.117 + err = AEStreamWriteKeyDesc(stream, kEventParamDirectObject, typeFileURL, [regItemURLUTF8Data bytes], [regItemURLUTF8Data length]);
1.118 + if (err != noErr) {
1.119 + 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));
1.120 + }
1.121 + }
1.122 +
1.123 + AppleEvent event;
1.124 + err = AEStreamClose(stream, &event);
1.125 + if (err != noErr) {
1.126 + NSLog(@"%@: Could not finish open-document event to register this application with Growl because AEStreamClose returned %li/%s", [self class], (long)err, GetMacOSStatusCommentString(err));
1.127 + } else {
1.128 + err = AESend(&event, /*reply*/ NULL, kAENoReply | kAEDontReconnect | kAENeverInteract | kAEDontRecord, kAENormalPriority, kAEDefaultTimeout, /*idleProc*/ NULL, /*filterProc*/ NULL);
1.129 + if (err != noErr) {
1.130 + NSLog(@"%@: Could not send open-document event to register this application with Growl because AESend returned %li/%s", [self class], (long)err, GetMacOSStatusCommentString(err));
1.131 + }
1.132 + }
1.133 +
1.134 + success = (err == noErr);
1.135 + }
1.136 }
1.137 -
1.138 - spec.appRef = &appRef;
1.139 - spec.numDocs = (passRegDict != NO);
1.140 - spec.itemRefs = (passRegDict ? ®ItemRef : NULL);
1.141 - spec.passThruParams = NULL;
1.142 - spec.launchFlags = kLSLaunchDontAddToRecents | kLSLaunchDontSwitch | kLSLaunchNoParams | kLSLaunchAsync;
1.143 - spec.asyncRefCon = NULL;
1.144 - status = LSOpenFromRefSpec(&spec, NULL);
1.145 -
1.146 - success = (status == noErr);
1.147 }
1.148 }
1.149