Since poseAsClass: is doomed anyway and appears to cause a crash on PowerPC[1], replace it with method-swizzling. This definitely contributes to our 64-bit cleanliness; hopefully, it also fixes that crash.
[1]: <http://groups.google.com/group/growldiscuss/msg/2b85001f4c6c0d4a>
1.1 --- a/Extras/GrowlMail/GrowlMailPreferences.m Sat Jun 06 21:30:17 2009 -0700
1.2 +++ b/Extras/GrowlMail/GrowlMailPreferences.m Sat Jun 06 21:30:17 2009 -0700
1.3 @@ -35,16 +35,63 @@
1.4 #import "GrowlMailPreferences.h"
1.5 #import "GrowlMailPreferencesModule.h"
1.6 #import "GrowlMail.h"
1.7 +#import "GrowlMailNotifier.h"
1.8 +
1.9 +#import <objc/objc-runtime.h>
1.10 +
1.11 +static void GMExchangeMethodImplementations(Method a, Method b);
1.12 +
1.13 +@interface NSPreferences (GMSwizzleSticks)
1.14 +
1.15 ++ (id) sharedPreferencesForGrowlMail;
1.16 ++ (id) sharedPreferencesFromAppKitSwizzledByGrowlMail;
1.17 +
1.18 +@end
1.19
1.20 @implementation GrowlMailPreferences
1.21 -// we need to do posing as the other mail bundles do that too
1.22 +
1.23 +//As of Mac OS X 10.5.6, Mail creates the +sharedPreferences object lazily, so the simplest way to install our prefpane is to swizzle the +sharedPreferences method.
1.24 +//We used to install our prefpane by posing as NSPreferences, but class-posing doesn't exist in 64-bit, and seemed to cause at least one crash on PowerPC machines in GrowlMail 1.1.5b1.
1.25 + (void) load {
1.26 - [GrowlMailPreferences poseAsClass:[NSPreferences class]];
1.27 + Class NSPreferencesClass = NSClassFromString(@"NSPreferences");
1.28 + if (!NSPreferencesClass)
1.29 + GMShutDownGrowlMailAndWarn(@"Couldn't install GrowlMail prefpane: NSPreferences class missing");
1.30 + else {
1.31 + //+[NSPreferences sharedPreferences]
1.32 + Method sharedPreferencesFromAppKit = class_getClassMethod(NSPreferencesClass, @selector(sharedPreferences));
1.33 + if (!sharedPreferencesFromAppKit)
1.34 + GMShutDownGrowlMailAndWarn(@"Couldn't install GrowlMail prefpane: +[NSPreferences sharedPreferences] method missing");
1.35 + else {
1.36 + //+[GrowlMailPreferences sharedPreferencesFromAppKitSwizzledByGrowlMail]
1.37 + Method sharedPreferencesFromAppKitFromGrowlMail = class_getClassMethod(self, @selector(sharedPreferencesFromAppKitSwizzledByGrowlMail));
1.38 + //+[GrowlMailPreferences sharedPreferencesForGrowlMail]
1.39 + Method sharedPreferencesForGrowlMail = class_getClassMethod(self, @selector(sharedPreferencesForGrowlMail));
1.40 +
1.41 + //Follow the lady!
1.42 + GMExchangeMethodImplementations(sharedPreferencesFromAppKit, sharedPreferencesFromAppKitFromGrowlMail);
1.43 + GMExchangeMethodImplementations(sharedPreferencesFromAppKit, sharedPreferencesForGrowlMail);
1.44 + /*Results of the swizzling:
1.45 + *
1.46 + *+[NSPreferences sharedPreferences]
1.47 + * implemented by former +[NSPreferences sharedPreferencesForGrowlMail]
1.48 + *
1.49 + *+[NSPreferences sharedPreferencesForGrowlMail]
1.50 + * implemented by former +[NSPreferences sharedPreferencesFromAppKitSwizzledByGrowlMail] (the stub)
1.51 + *
1.52 + *+[NSPreferences sharedPreferencesFromAppKitSwizzledByGrowlMail]
1.53 + * implemented by former +[NSPreferences sharedPreferences]
1.54 + */
1.55 + }
1.56 + }
1.57 }
1.58
1.59 -+ (id) sharedPreferences {
1.60 +@end
1.61 +
1.62 +@implementation NSPreferences (GMSwizzleSticks)
1.63 +
1.64 ++ (id) sharedPreferencesForGrowlMail {
1.65 static BOOL added = NO;
1.66 - id preferences = [super sharedPreferences];
1.67 + id preferences = [self sharedPreferencesFromAppKitSwizzledByGrowlMail];
1.68
1.69 if (preferences && !added) {
1.70 added = YES;
1.71 @@ -53,4 +100,30 @@
1.72
1.73 return preferences;
1.74 }
1.75 ++ (id) sharedPreferencesFromAppKitSwizzledByGrowlMail {
1.76 + //Stub implementation to swizzle out.
1.77 + return nil;
1.78 +}
1.79 +
1.80 @end
1.81 +
1.82 +static void GMExchangeMethodImplementations(Method a, Method b)
1.83 +{
1.84 +#if __OBJC2__
1.85 + method_exchangeImplementations(a, b);
1.86 +#else
1.87 + NSCAssert(a && b, @"Attempt to swizzle fewer than two method implementations");
1.88 +
1.89 + //Adapted from ObjC 1 implementation written by an unknown author and posted to http://www.cocoadev.com/index.pl?MethodSwizzling
1.90 + char *tempTypes;
1.91 + IMP tempImp;
1.92 +
1.93 + tempTypes = a->method_types;
1.94 + a->method_types = b->method_types;
1.95 + b->method_types = tempTypes;
1.96 +
1.97 + tempImp = a->method_imp;
1.98 + a->method_imp = b->method_imp;
1.99 + b->method_imp = tempImp;
1.100 +#endif
1.101 +}