+#ifndef USE_IPHONE
+
+#include <objc/runtime.h>
+
+/* GlobalDefaults is an NSUserDefaults implementation that writes into
+ the preferences key we provide, instead of whatever the default would
+ be for this app. We do this by invoking the Core Foundation preferences
+ routines directly, while presenting the same API as NSUserDefaults.
+
+ We need this so that global prefs will go into the file
+ Library/Preferences/org.jwz.xscreensaver.updater.plist instead of into
+ Library/Preferences/ByHost/org.jwz.xscreensaver.Maze.XXXXX.plist
+ with the per-saver prefs.
+
+ The ScreenSaverDefaults class *almost* does this, but it always writes
+ into the ByHost subdirectory, which means it's not readable by an app
+ that tries to access it with a plain old +standardUserDefaults.
+ */
+@interface GlobalDefaults : NSUserDefaults
+{
+ NSString *domain;
+ NSDictionary *defaults;
+}
+@end
+
+@implementation GlobalDefaults
+- (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
+{
+ defaults = [dict retain];
+}
+
+- (id)objectForKey:(NSString *)key
+{
+ NSObject *obj = (NSObject *)
+ CFPreferencesCopyAppValue ((CFStringRef) key, (CFStringRef) domain);
+ if (obj)
+ [obj autorelease];
+ else if (defaults)
+ obj = [defaults objectForKey:key];
+ return obj;
+}
+
+- (void)setObject:(id)value forKey:(NSString *)key
+{
+ if (value && defaults) {
+ // If the value is the default, then remove it instead.
+ NSObject *def = [defaults objectForKey:key];
+ if (def && [def isEqual:value])
+ value = NULL;
+ }
+ CFPreferencesSetAppValue ((CFStringRef) key,
+ (CFPropertyListRef) value,
+ (CFStringRef) domain);
+}
+
+
+- (BOOL)synchronize
+{
+ return CFPreferencesAppSynchronize ((CFStringRef) domain);
+}
+
+
+// Make sure these all call our objectForKey.
+// Might not be necessary, but safe.
+
+- (NSString *)stringForKey:(NSString *)key
+{
+ return [[self objectForKey:key] stringValue];
+}
+
+- (NSArray *)arrayForKey:(NSString *)key
+{
+ return (NSArray *) [self objectForKey:key];
+}
+
+- (NSDictionary *)dictionaryForKey:(NSString *)key
+{
+ return (NSDictionary *) [self objectForKey:key];
+}
+
+- (NSData *)dataForKey:(NSString *)key
+{
+ return (NSData *) [self objectForKey:key];
+}
+
+- (NSArray *)stringArrayForKey:(NSString *)key
+{
+ return (NSArray *) [self objectForKey:key];
+}
+
+- (NSInteger)integerForKey:(NSString *)key
+{
+ return [[self objectForKey:key] integerValue];
+}
+
+- (float)floatForKey:(NSString *)key
+{
+ return [[self objectForKey:key] floatValue];
+}
+
+- (double)doubleForKey:(NSString *)key
+{
+ return [[self objectForKey:key] doubleValue];
+}
+
+- (BOOL)boolForKey:(NSString *)key
+{
+ return [[self objectForKey:key] integerValue];
+}
+
+// Make sure these all call our setObject.
+// Might not be necessary, but safe.
+
+- (void)removeObjectForKey:(NSString *)key
+{
+ [self setObject:NULL forKey:key];
+}
+
+- (void)setInteger:(NSInteger)value forKey:(NSString *)key
+{
+ [self setObject:[NSNumber numberWithInteger:value] forKey:key];
+}
+
+- (void)setFloat:(float)value forKey:(NSString *)key
+{
+ [self setObject:[NSNumber numberWithFloat:value] forKey:key];
+}
+
+- (void)setDouble:(double)value forKey:(NSString *)key
+{
+ [self setObject:[NSNumber numberWithDouble:value] forKey:key];
+}
+
+- (void)setBool:(BOOL)value forKey:(NSString *)key
+{
+ [self setObject:[NSNumber numberWithBool:value] forKey:key];
+}
+@end
+
+
+#endif // !USE_IPHONE
+
+