X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=OSX%2FPrefsReader.m;h=a1c4ed48e0625dc1f69aaa0f8cf4fad3a11e407c;hb=aa75c7476aeaa84cf3abc192b376a8b03c325213;hp=cf1698ece73a964928f56bc7510617fa2f89bf6b;hpb=019de959b265701cd0c3fccbb61f2b69f06bf9ee;p=xscreensaver diff --git a/OSX/PrefsReader.m b/OSX/PrefsReader.m index cf1698ec..a1c4ed48 100644 --- a/OSX/PrefsReader.m +++ b/OSX/PrefsReader.m @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 2006-2013 Jamie Zawinski +/* xscreensaver, Copyright (c) 2006-2015 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -26,6 +26,7 @@ #ifndef USE_IPHONE +#include /* GlobalDefaults is an NSUserDefaults implementation that writes into the preferences key we provide, instead of whatever the default would @@ -49,18 +50,42 @@ @end @implementation GlobalDefaults -- (id) initWithDomain:(NSString *)_domain -{ +- (id) initWithDomain:(NSString *)_domain module:(NSString *)_module +{ + // Key-Value Observing tries to create an Objective-C class named + // NSKVONotifying_GlobalDefaults when the configuration page is shown. But if + // this is the second XScreenSaver .saver running in the same process, class + // creation fails because that class name was already used by the first + // .saver, and it refers to the GlobalDefaults from the other .saver. + + // This gives the class a unique name, sidestepping the above issue. + + // It really just needs to be unique for this .saver and this instance. + // Using the pointer to the .saver's mach_header and the full path to the + // .saver would be preferable, but this should be good enough. + char class_name[128]; + sprintf(class_name, "GlobalDefaults_%s_%p_%u", + strrchr(_module.UTF8String, '.') + 1, self, random()); + Class c = objc_allocateClassPair([GlobalDefaults class], class_name, 0); + if (!c) + return nil; + objc_registerClassPair(c); + self = [super init]; + object_setClass(self, c); domain = [_domain retain]; return self; } - (void) dealloc { + Class c = object_getClass(self); + [domain release]; [defaults release]; [super dealloc]; + + objc_disposeClassPair(c); } - (void)registerDefaults:(NSDictionary *)dict @@ -72,7 +97,9 @@ { NSObject *obj = (NSObject *) CFPreferencesCopyAppValue ((CFStringRef) key, (CFStringRef) domain); - if (!obj && defaults) + if (obj) + [obj autorelease]; + else if (defaults) obj = [defaults objectForKey:key]; return obj; } @@ -223,7 +250,7 @@ while (*val == ' ' || *val == '\t') val++; - int L = strlen(val); + unsigned long L = strlen(val); while (L > 0 && (val[L-1] == ' ' || val[L-1] == '\t')) val[--L] = 0; @@ -287,10 +314,10 @@ initialValues:defsdict]; globalDefaultsController = [[NSUserDefaultsController alloc] initWithDefaults:globalDefaults - initialValues:defsdict]; + initialValues:UPDATER_DEFAULTS]; # else // USE_IPHONE - userDefaultsController = userDefaults; - globalDefaultsController = userDefaults; + userDefaultsController = [userDefaults retain]; + globalDefaultsController = [userDefaults retain]; # endif // USE_IPHONE NSDictionary *optsdict = [NSMutableDictionary dictionaryWithCapacity:20]; @@ -386,24 +413,33 @@ - (NSObject *) getObjectResource: (const char *) name { - // First look in userDefaults, then in globalDefaults. - for (int globalp = 0; globalp <= 1; globalp++) { - const char *name2 = name; - while (1) { - NSString *key = [self makeCKey:name2]; - NSObject *obj = [(globalp ? globalDefaults : userDefaults) - objectForKey:key]; - if (obj) - return obj; - - // If key is "foo.bar.baz", check "foo.bar.baz", "bar.baz", and "baz". - // - const char *dot = strchr (name2, '.'); - if (dot && dot[1]) - name2 = dot + 1; - else - break; - } + // Only look in globalDefaults for updater preferences. + + static NSDictionary *updaterDefaults; + if (!updaterDefaults) { + updaterDefaults = UPDATER_DEFAULTS; + [updaterDefaults retain]; + } + + NSUserDefaults *defaults = + [updaterDefaults objectForKey:[NSString stringWithUTF8String:name]] ? + globalDefaults : + userDefaults; + + const char *name2 = name; + while (1) { + NSString *key = [self makeCKey:name2]; + NSObject *obj = [defaults objectForKey:key]; + if (obj) + return obj; + + // If key is "foo.bar.baz", check "foo.bar.baz", "bar.baz", and "baz". + // + const char *dot = strchr (name2, '.'); + if (dot && dot[1]) + name2 = dot + 1; + else + break; } return NULL; } @@ -542,11 +578,11 @@ # ifndef USE_IPHONE userDefaults = [ScreenSaverDefaults defaultsForModuleWithName:name]; - globalDefaults = [[[GlobalDefaults alloc] initWithDomain:@UPDATER_DOMAIN] - retain]; + globalDefaults = [[GlobalDefaults alloc] initWithDomain:@UPDATER_DOMAIN + module:name]; # else // USE_IPHONE userDefaults = [NSUserDefaults standardUserDefaults]; - globalDefaults = userDefaults; + globalDefaults = [userDefaults retain]; # endif // USE_IPHONE // Convert "org.jwz.xscreensaver.NAME" to just "NAME". @@ -565,6 +601,7 @@ [saver_name release]; [userDefaultsController release]; [globalDefaultsController release]; + [globalDefaults release]; [super dealloc]; }