X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=OSX%2FPrefsReader.m;fp=OSX%2FPrefsReader.m;h=3c20f3dcf328db28ecbd24bba93b6a83b39a334a;hb=49f5b54f312fe4ac2e9bc47581a72451bd0e8439;hp=0000000000000000000000000000000000000000;hpb=ccb7f4903325f92555a9722bba74b58346654ba0;p=xscreensaver diff --git a/OSX/PrefsReader.m b/OSX/PrefsReader.m new file mode 100644 index 00000000..3c20f3dc --- /dev/null +++ b/OSX/PrefsReader.m @@ -0,0 +1,283 @@ +/* xscreensaver, Copyright (c) 2006 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 + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +/* This implements the substrate of the xscreensaver preferences code: + It does this by writing defaults to, and reading values from, the + NSUserDefaultsController (and ScreenSaverDefaults/NSUserDefaults) + and thereby reading the preferences that may have been edited by + the UI (XScreenSaverConfigSheet). + */ + +#import +#import "PrefsReader.h" +#import "screenhackI.h" + +@implementation PrefsReader + +/* Converts an array of "key:value" strings to an NSDictionary. + */ +- (NSDictionary *) defaultsToDict: (const char * const *) defs +{ + NSDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:20]; + while (*defs) { + char *line = strdup (*defs); + char *key, *val; + key = line; + while (*key == '.' || *key == '*' || *key == ' ' || *key == '\t') + key++; + val = key; + while (*val && *val != ':') + val++; + if (*val != ':') abort(); + *val++ = 0; + while (*val == ' ' || *val == '\t') + val++; + + int L = strlen(val); + while (L > 0 && (val[L-1] == ' ' || val[L-1] == '\t')) + val[--L] = 0; + + // When storing into preferences, look at the default string and + // decide whether it's a boolean, int, float, or string, and store + // an object of the appropriate type in the prefs. + // + NSString *nskey = [NSString stringWithCString:key + encoding:NSUTF8StringEncoding]; + NSObject *nsval; + int dd; + double ff; + char cc; + if (!strcasecmp (val, "true") || !strcasecmp (val, "yes")) + nsval = [NSNumber numberWithBool:YES]; + else if (!strcasecmp (val, "false") || !strcasecmp (val, "no")) + nsval = [NSNumber numberWithBool:NO]; + else if (1 == sscanf (val, " %d %c", &dd, &cc)) + nsval = [NSNumber numberWithInt:dd]; + else if (1 == sscanf (val, " %lf %c", &ff, &cc)) + nsval = [NSNumber numberWithDouble:ff]; + else + nsval = [NSString stringWithCString:val encoding:NSUTF8StringEncoding]; + +// NSLog (@"default: \"%@\" = \"%@\" [%@]\n", nskey, nsval, [nsval class]); + [dict setValue:nsval forKey:nskey]; + free (line); + defs++; + } + return dict; +} + + +/* Initialize the Cocoa preferences database: + - sets the default preferences values from the 'defaults' array; + - binds 'self' to each preference as an observer; + - ensures that nothing is mentioned in 'options' and not in 'defaults'; + - ensures that nothing is mentioned in 'defaults' and not in 'options'. + */ +- (void) registerXrmKeys: (const XrmOptionDescRec *) opts + defaults: (const char * const *) defs +{ + // Store the contents of 'defaults' into the real preferences database. + NSDictionary *defsdict = [self defaultsToDict:defs]; + [userDefaults registerDefaults:defsdict]; + + userDefaultsController = + [[NSUserDefaultsController alloc] initWithDefaults:userDefaults + initialValues:defsdict]; + + NSDictionary *optsdict = [NSMutableDictionary dictionaryWithCapacity:20]; + + while (opts[0].option) { + //const char *option = opts->option; + const char *resource = opts->specifier; + + while (*resource == '.' || *resource == '*') + resource++; + NSString *nsresource = [NSString stringWithCString:resource + encoding:NSUTF8StringEncoding]; + + // make sure there's no resource mentioned in options and not defaults. + if (![defsdict objectForKey:nsresource]) { + if (! (!strcmp(resource, "font") || // don't warn about these + !strcmp(resource, "textLiteral") || + !strcmp(resource, "textFile") || + !strcmp(resource, "textURL") || + !strcmp(resource, "imageDirectory"))) + NSLog (@"warning: \"%s\" is in options but not defaults", resource); + } + [optsdict setValue:nsresource forKey:nsresource]; + + opts++; + } + + // make sure there's no resource mentioned in defaults and not options. + NSEnumerator *enumerator = [defsdict keyEnumerator]; + NSString *key; + while ((key = [enumerator nextObject])) { +#if 0 + if (! [optsdict objectForKey:key]) + if (! ([key isEqualToString:@"foreground"] || // don't warn about these + [key isEqualToString:@"background"] || + [key isEqualToString:@"Background"] || + [key isEqualToString:@"geometry"] || + [key isEqualToString:@"font"] || + [key isEqualToString:@"dontClearRoot"] || + + // fps.c settings + [key isEqualToString:@"fpsSolid"] || + [key isEqualToString:@"fpsTop"] || + [key isEqualToString:@"titleFont"] || + + // analogtv.c settings + [key isEqualToString:@"TVBrightness"] || + [key isEqualToString:@"TVColor"] || + [key isEqualToString:@"TVContrast"] || + [key isEqualToString:@"TVTint"] + )) + NSLog (@"warning: \"%@\" is in defaults but not options", key); +#endif /* 0 */ + } + +} + +- (NSUserDefaultsController *) userDefaultsController +{ + NSAssert(userDefaultsController, @"userDefaultsController uninitialized"); + return userDefaultsController; +} + + +- (NSObject *) getObjectResource: (const char *) name +{ + while (1) { + NSString *key = [NSString stringWithCString:name + encoding:NSUTF8StringEncoding]; + NSObject *obj = [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 (name, '.'); + if (dot && dot[1]) + name = dot + 1; + else + return nil; + } +} + + +- (char *) getStringResource: (const char *) name +{ + NSObject *o = [self getObjectResource:name]; + //NSLog(@"%s = %@\n",name,o); + if (o == nil) { + if (! (!strcmp(name, "eraseMode") || // erase.c + // xlockmore.c reads all of these whether used or not... + !strcmp(name, "right3d") || + !strcmp(name, "left3d") || + !strcmp(name, "both3d") || + !strcmp(name, "none3d") || + !strcmp(name, "font") || + !strcmp(name, "labelFont") || // grabclient.c + !strcmp(name, "titleFont") || + !strcmp(name, "background") + )) + NSLog(@"warning: no preference \"%s\" [string]\n", name); + return NULL; + } +#if 0 + if (! [o isKindOfClass:[NSString class]]) { + NSAssert2(0, @"%s = \"%@\" but should have been an NSString", name, o); + abort(); + } +#else + if (! [o isKindOfClass:[NSString class]]) { + NSLog(@"asked for %s as a string, but it is a %@", name, [o class]); + o = [(NSNumber *) o stringValue]; + } +#endif + + NSString *os = (NSString *) o; + const char *result = [os cStringUsingEncoding:NSUTF8StringEncoding]; + return strdup (result); +} + + +- (double) getFloatResource: (const char *) name +{ + NSObject *o = [self getObjectResource:name]; + if (o == nil) { + // xlockmore.c reads all of these whether used or not... + if (! (!strcmp(name, "cycles") || + !strcmp(name, "size") || + !strcmp(name, "use3d") || + !strcmp(name, "delta3d") || + !strcmp(name, "wireframe") || + !strcmp(name, "showFPS") || + !strcmp(name, "fpsSolid") || + !strcmp(name, "fpsTop") || + !strcmp(name, "mono") || + !strcmp(name, "count") || + !strcmp(name, "ncolors") || + !strcmp(name, "eraseSeconds") // erase.c + )) + NSLog(@"warning: no preference \"%s\" [float]\n", name); + return 0.0; + } + if ([o isKindOfClass:[NSString class]]) { + return [(NSString *) o doubleValue]; + } else if ([o isKindOfClass:[NSNumber class]]) { + return [(NSNumber *) o doubleValue]; + } else { + NSAssert2(0, @"%s = \"%@\" but should have been an NSNumber", name, o); + abort(); + } +} + + +- (int) getIntegerResource: (const char *) name +{ + return (int) [self getFloatResource:name]; +} + + +- (BOOL) getBooleanResource: (const char *) name +{ + int n = [self getIntegerResource:name]; + if (n == 0) return NO; + else if (n == 1) return YES; + else { + NSAssert2(0, @"%s = %d but should have been 0 or 1\n", name, n); + abort(); + } +} + + +- (id) initWithName: (NSString *) name + xrmKeys: (const XrmOptionDescRec *) opts + defaults: (const char * const *) defs +{ + self = [self init]; + if (!self) return nil; + + userDefaults = [ScreenSaverDefaults defaultsForModuleWithName:name]; + + [self registerXrmKeys:opts defaults:defs]; + return self; +} + +- (void) dealloc +{ + [userDefaultsController release]; + [super dealloc]; +} + +@end