13 typedef struct W_UserDefaults {
16 WMPropList *appDomain;
18 WMPropList *searchListArray;
19 WMPropList **searchList; /* cache for searchListArray */
25 char *path; /* where is db located */
27 time_t timestamp; /* last modification time */
29 struct W_UserDefaults *next;
33 static UserDefaults *sharedUserDefaults = NULL;
35 char *WMUserDefaultsDidChangeNotification = "WMUserDefaultsDidChangeNotification";
37 static void synchronizeUserDefaults(void *foo);
39 extern char *WMGetApplicationName();
41 #define DEFAULTS_DIR "/Defaults"
43 char *wusergnusteppath()
45 static char *path = NULL;
50 gspath = getenv("GNUSTEP_USER_ROOT");
52 gspath = wexpandpath(gspath);
53 pathlen = strlen(gspath) + 4;
54 path = wmalloc(pathlen);
58 pathlen = strlen(wgethomedir()) + 10;
59 path = wmalloc(pathlen);
60 strcpy(path, wgethomedir());
61 strcat(path, "/GNUstep");
68 char *wdefaultspathfordomain(char *domain)
73 gspath = wusergnusteppath();
74 path = wmalloc(strlen(gspath) + strlen(DEFAULTS_DIR) + strlen(domain) + 4);
76 strcat(path, DEFAULTS_DIR);
85 saveDefaultsChanges(void)
87 saveDefaultsChanges(int foo, void *bar)
90 /* save the user defaults databases */
91 synchronizeUserDefaults(NULL);
94 /* set to save changes in defaults when program is exited */
95 static void registerSaveOnExit(void)
97 static Bool registeredSaveOnExit = False;
99 if (!registeredSaveOnExit) {
101 atexit(saveDefaultsChanges);
103 on_exit(saveDefaultsChanges, (void *)NULL);
105 registeredSaveOnExit = True;
109 static void synchronizeUserDefaults(void *foo)
111 UserDefaults *database = sharedUserDefaults;
114 if (!database->dontSync)
115 WMSynchronizeUserDefaults(database);
116 database = database->next;
120 void WMEnableUDPeriodicSynchronization(WMUserDefaults * database, Bool enable)
122 database->dontSync = !enable;
125 void WMSynchronizeUserDefaults(WMUserDefaults * database)
127 Bool fileIsNewer = False, release = False, notify = False;
128 WMPropList *plF, *key;
132 if (!database->path) {
133 path = wdefaultspathfordomain(WMGetApplicationName());
136 path = database->path;
139 if (stat(path, &stbuf) >= 0 && stbuf.st_mtime > database->timestamp)
142 if (database->appDomain && (database->dirty || fileIsNewer)) {
143 if (database->dirty && fileIsNewer) {
144 plF = WMReadPropListFromFile(path);
146 plF = WMMergePLDictionaries(plF, database->appDomain, False);
147 WMReleasePropList(database->appDomain);
148 database->appDomain = plF;
149 key = database->searchList[0];
150 WMPutInPLDictionary(database->defaults, key, plF);
153 /* something happened with the file. just overwrite it */
154 wwarning(_("cannot read domain from file '%s' when syncing"), path);
155 WMWritePropListToFile(database->appDomain, path, True);
157 } else if (database->dirty) {
158 WMWritePropListToFile(database->appDomain, path, True);
159 } else if (fileIsNewer) {
160 plF = WMReadPropListFromFile(path);
162 WMReleasePropList(database->appDomain);
163 database->appDomain = plF;
164 key = database->searchList[0];
165 WMPutInPLDictionary(database->defaults, key, plF);
168 /* something happened with the file. just overwrite it */
169 wwarning(_("cannot read domain from file '%s' when syncing"), path);
170 WMWritePropListToFile(database->appDomain, path, True);
176 if (stat(path, &stbuf) >= 0)
177 database->timestamp = stbuf.st_mtime;
180 WMPostNotificationName(WMUserDefaultsDidChangeNotification, database, NULL);
189 void WMSaveUserDefaults(WMUserDefaults * database)
191 if (database->appDomain) {
194 Bool release = False;
196 if (!database->path) {
197 path = wdefaultspathfordomain(WMGetApplicationName());
200 path = database->path;
202 WMWritePropListToFile(database->appDomain, path, True);
204 if (stat(path, &stbuf) >= 0)
205 database->timestamp = stbuf.st_mtime;
211 WMUserDefaults *WMGetStandardUserDefaults(void)
213 WMUserDefaults *defaults;
220 if (sharedUserDefaults) {
221 defaults = sharedUserDefaults;
223 /* path == NULL only for StandardUserDefaults db */
224 if (defaults->path == NULL)
226 defaults = defaults->next;
230 /* we didn't found the database we are looking for. Go read it. */
231 defaults = wmalloc(sizeof(WMUserDefaults));
232 memset(defaults, 0, sizeof(WMUserDefaults));
234 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
236 defaults->searchList = wmalloc(sizeof(WMPropList *) * 3);
238 /* application domain */
239 key = WMCreatePLString(WMGetApplicationName());
240 defaults->searchList[0] = key;
242 /* temporary kluge. wmaker handles synchronization itself */
243 if (strcmp(WMGetApplicationName(), "WindowMaker") == 0) {
244 defaults->dontSync = 1;
247 path = wdefaultspathfordomain(WMGetFromPLString(key));
249 if (stat(path, &stbuf) >= 0)
250 defaults->timestamp = stbuf.st_mtime;
252 domain = WMReadPropListFromFile(path);
255 domain = WMCreatePLDictionary(NULL, NULL);
260 defaults->appDomain = domain;
263 WMPutInPLDictionary(defaults->defaults, key, domain);
266 key = WMCreatePLString("WMGLOBAL");
267 defaults->searchList[1] = key;
269 path = wdefaultspathfordomain(WMGetFromPLString(key));
271 domain = WMReadPropListFromFile(path);
276 domain = WMCreatePLDictionary(NULL, NULL);
279 WMPutInPLDictionary(defaults->defaults, key, domain);
282 defaults->searchList[2] = NULL;
284 defaults->searchListArray = WMCreatePLArray(NULL, NULL);
287 while (defaults->searchList[i]) {
288 WMAddToPLArray(defaults->searchListArray, defaults->searchList[i]);
292 if (sharedUserDefaults)
293 defaults->next = sharedUserDefaults;
294 sharedUserDefaults = defaults;
296 registerSaveOnExit();
301 WMUserDefaults *WMGetDefaultsFromPath(char *path)
303 WMUserDefaults *defaults;
310 assert(path != NULL);
312 if (sharedUserDefaults) {
313 defaults = sharedUserDefaults;
315 if (defaults->path && strcmp(defaults->path, path) == 0)
317 defaults = defaults->next;
321 /* we didn't found the database we are looking for. Go read it. */
322 defaults = wmalloc(sizeof(WMUserDefaults));
323 memset(defaults, 0, sizeof(WMUserDefaults));
325 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
327 defaults->searchList = wmalloc(sizeof(WMPropList *) * 2);
329 /* the domain we want, go in the first position */
330 name = strrchr(path, '/');
336 key = WMCreatePLString(name);
337 defaults->searchList[0] = key;
339 if (stat(path, &stbuf) >= 0)
340 defaults->timestamp = stbuf.st_mtime;
342 domain = WMReadPropListFromFile(path);
345 domain = WMCreatePLDictionary(NULL, NULL);
347 defaults->path = wstrdup(path);
349 defaults->appDomain = domain;
352 WMPutInPLDictionary(defaults->defaults, key, domain);
355 defaults->searchList[1] = NULL;
357 defaults->searchListArray = WMCreatePLArray(NULL, NULL);
360 while (defaults->searchList[i]) {
361 WMAddToPLArray(defaults->searchListArray, defaults->searchList[i]);
365 if (sharedUserDefaults)
366 defaults->next = sharedUserDefaults;
367 sharedUserDefaults = defaults;
369 registerSaveOnExit();
374 /* Returns a WMPropList array with all keys in the user defaults database.
375 * Free the array with WMReleasePropList() when no longer needed,
376 * but do not free the elements of the array! They're just references. */
377 WMPropList *WMGetUDKeys(WMUserDefaults * database)
379 return WMGetPLDictionaryKeys(database->appDomain);
382 WMPropList *WMGetUDObjectForKey(WMUserDefaults * database, char *defaultName)
384 WMPropList *domainName, *domain;
385 WMPropList *object = NULL;
386 WMPropList *key = WMCreatePLString(defaultName);
389 while (database->searchList[i] && !object) {
390 domainName = database->searchList[i];
391 domain = WMGetFromPLDictionary(database->defaults, domainName);
393 object = WMGetFromPLDictionary(domain, key);
397 WMReleasePropList(key);
402 void WMSetUDObjectForKey(WMUserDefaults * database, WMPropList * object, char *defaultName)
404 WMPropList *key = WMCreatePLString(defaultName);
408 WMPutInPLDictionary(database->appDomain, key, object);
409 WMReleasePropList(key);
412 void WMRemoveUDObjectForKey(WMUserDefaults * database, char *defaultName)
414 WMPropList *key = WMCreatePLString(defaultName);
418 WMRemoveFromPLDictionary(database->appDomain, key);
420 WMReleasePropList(key);
423 char *WMGetUDStringForKey(WMUserDefaults * database, char *defaultName)
427 val = WMGetUDObjectForKey(database, defaultName);
432 if (!WMIsPLString(val))
435 return WMGetFromPLString(val);
438 int WMGetUDIntegerForKey(WMUserDefaults * database, char *defaultName)
444 val = WMGetUDObjectForKey(database, defaultName);
449 if (!WMIsPLString(val))
452 str = WMGetFromPLString(val);
456 if (sscanf(str, "%i", &value) != 1)
462 float WMGetUDFloatForKey(WMUserDefaults * database, char *defaultName)
468 val = WMGetUDObjectForKey(database, defaultName);
470 if (!val || !WMIsPLString(val))
473 if (!(str = WMGetFromPLString(val)))
476 if (sscanf(str, "%f", &value) != 1)
482 Bool WMGetUDBoolForKey(WMUserDefaults * database, char *defaultName)
488 val = WMGetUDObjectForKey(database, defaultName);
493 if (!WMIsPLString(val))
496 str = WMGetFromPLString(val);
500 if (sscanf(str, "%i", &value) == 1 && value != 0)
503 if (strcasecmp(str, "YES") == 0)
506 if (strcasecmp(str, "Y") == 0)
512 void WMSetUDIntegerForKey(WMUserDefaults * database, int value, char *defaultName)
517 sprintf(buffer, "%i", value);
518 object = WMCreatePLString(buffer);
520 WMSetUDObjectForKey(database, object, defaultName);
521 WMReleasePropList(object);
524 void WMSetUDStringForKey(WMUserDefaults * database, char *value, char *defaultName)
528 object = WMCreatePLString(value);
530 WMSetUDObjectForKey(database, object, defaultName);
531 WMReleasePropList(object);
534 void WMSetUDFloatForKey(WMUserDefaults * database, float value, char *defaultName)
539 sprintf(buffer, "%f", value);
540 object = WMCreatePLString(buffer);
542 WMSetUDObjectForKey(database, object, defaultName);
543 WMReleasePropList(object);
546 void WMSetUDBoolForKey(WMUserDefaults * database, Bool value, char *defaultName)
548 static WMPropList *yes = NULL, *no = NULL;
551 yes = WMCreatePLString("YES");
552 no = WMCreatePLString("NO");
555 WMSetUDObjectForKey(database, value ? yes : no, defaultName);
558 WMPropList *WMGetUDSearchList(WMUserDefaults * database)
560 return database->searchListArray;
563 void WMSetUDSearchList(WMUserDefaults * database, WMPropList * list)
567 if (database->searchList) {
569 while (database->searchList[i]) {
570 WMReleasePropList(database->searchList[i]);
573 wfree(database->searchList);
575 if (database->searchListArray) {
576 WMReleasePropList(database->searchListArray);
579 c = WMGetPropListItemCount(list);
580 database->searchList = wmalloc(sizeof(WMPropList *) * (c + 1));
582 for (i = 0; i < c; i++) {
583 database->searchList[i] = WMGetFromPLArray(list, i);
585 database->searchList[c] = NULL;
587 database->searchListArray = WMDeepCopyPropList(list);