- Finished moving to the new proplist handling code in WINGs.
[wmaker-crm.git] / WINGs / userdefaults.c
blobe29c8040e08cc234cb75832d16589ddede03e56c
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdio.h>
5 #include <assert.h>
6 #include <unistd.h>
7 #include <sys/stat.h>
10 #include "../src/config.h"
12 #include "wconfig.h"
14 #include "WINGs.h"
18 typedef struct W_UserDefaults {
19 WMPropList *defaults;
21 WMPropList *appDomain;
23 WMPropList *searchListArray;
24 WMPropList **searchList; /* cache for searchListArray */
26 char dirty;
28 char dontSync;
30 char *path; /* where is db located */
32 time_t timestamp; /* last modification time */
34 struct W_UserDefaults *next;
36 } UserDefaults;
39 static UserDefaults *sharedUserDefaults = NULL;
41 char *WMUserDefaultsDidChangeNotification = "WMUserDefaultsDidChangeNotification";
45 extern char *WMGetApplicationName();
47 #define DEFAULTS_DIR "/Defaults"
49 #define UD_SYNC_INTERVAL 2000
53 char*
54 wusergnusteppath()
56 static char *path = NULL;
57 char *gspath;
58 int pathlen;
60 if (!path) {
61 gspath = getenv("GNUSTEP_USER_ROOT");
62 if (gspath) {
63 gspath = wexpandpath(gspath);
64 pathlen = strlen(gspath) + 4;
65 path = wmalloc(pathlen);
66 strcpy(path, gspath);
67 wfree(gspath);
68 } else {
69 pathlen = strlen(wgethomedir()) + 10;
70 path = wmalloc(pathlen);
71 strcpy(path, wgethomedir());
72 strcat(path, "/GNUstep");
76 return path;
80 char*
81 wdefaultspathfordomain(char *domain)
83 char *path;
84 char *gspath;
86 gspath = wusergnusteppath();
87 path = wmalloc(strlen(gspath)+strlen(DEFAULTS_DIR)+strlen(domain)+4);
88 strcpy(path, gspath);
89 strcat(path, DEFAULTS_DIR);
90 strcat(path, "/");
91 strcat(path, domain);
93 return path;
97 static void
98 #ifndef HAVE_ATEXIT
99 saveDefaultsChanges(int foo, void *bar)
100 #else
101 saveDefaultsChanges(void)
102 #endif
104 /* save the user defaults databases */
105 UserDefaults *tmp = sharedUserDefaults;
107 while (tmp) {
108 WMSynchronizeUserDefaults(tmp);
109 tmp = tmp->next;
114 /* set to save changes in defaults when program is exited */
115 static void
116 registerSaveOnExit(void)
118 static Bool registeredSaveOnExit = False;
120 if (!registeredSaveOnExit) {
121 #ifndef HAVE_ATEXIT
122 on_exit(saveDefaultsChanges, (void*)NULL);
123 #else
124 atexit(saveDefaultsChanges);
125 #endif
126 registeredSaveOnExit = True;
131 static void
132 synchronizeUserDefaults(void *foo)
134 UserDefaults *database = sharedUserDefaults;
136 while (database) {
137 if (!database->dontSync)
138 WMSynchronizeUserDefaults(database);
139 database = database->next;
141 WMAddTimerHandler(UD_SYNC_INTERVAL, synchronizeUserDefaults, NULL);
145 static void
146 addSynchronizeTimerHandler(void)
148 static Bool initialized = False;
150 if (!initialized) {
151 WMAddTimerHandler(UD_SYNC_INTERVAL, synchronizeUserDefaults, NULL);
152 initialized = True;
157 void
158 WMEnableUDPeriodicSynchronization(WMUserDefaults *database, Bool enable)
160 database->dontSync = !enable;
164 void
165 WMSynchronizeUserDefaults(WMUserDefaults *database)
167 Bool fileIsNewer = False, release = False, notify = False;
168 WMPropList *plF, *key;
169 char *path;
170 struct stat stbuf;
172 if (!database->path) {
173 path = wdefaultspathfordomain(WMGetApplicationName());
174 release = True;
175 } else {
176 path = database->path;
179 if (stat(path, &stbuf) >= 0 && stbuf.st_mtime > database->timestamp)
180 fileIsNewer = True;
182 if (database->appDomain && (database->dirty || fileIsNewer)) {
183 if (database->dirty && fileIsNewer) {
184 plF = WMReadPropListFromFile(path);
185 if (plF) {
186 plF = WMMergePLDictionaries(plF, database->appDomain);
187 WMReleasePropList(database->appDomain);
188 database->appDomain = plF;
189 key = database->searchList[0];
190 WMPutInPLDictionary(database->defaults, key, plF);
191 notify = True;
192 } else {
193 /* something happened with the file. just overwrite it */
194 wwarning(_("cannot read domain from file '%s' when syncing"),
195 path);
196 WMWritePropListToFile(database->appDomain, path, True);
198 } else if (database->dirty) {
199 WMWritePropListToFile(database->appDomain, path, True);
200 } else if (fileIsNewer) {
201 plF = WMReadPropListFromFile(path);
202 if (plF) {
203 WMReleasePropList(database->appDomain);
204 database->appDomain = plF;
205 key = database->searchList[0];
206 WMPutInPLDictionary(database->defaults, key, plF);
207 notify = True;
208 } else {
209 /* something happened with the file. just overwrite it */
210 wwarning(_("cannot read domain from file '%s' when syncing"),
211 path);
212 WMWritePropListToFile(database->appDomain, path, True);
216 database->dirty = 0;
218 if (stat(path, &stbuf) >= 0)
219 database->timestamp = stbuf.st_mtime;
221 if (notify) {
222 WMPostNotificationName(WMUserDefaultsDidChangeNotification,
223 database, NULL);
227 if (release)
228 wfree(path);
233 void
234 WMSaveUserDefaults(WMUserDefaults *database)
236 if (database->appDomain) {
237 struct stat stbuf;
238 char *path;
239 Bool release = False;
241 if (!database->path) {
242 path = wdefaultspathfordomain(WMGetApplicationName());
243 release = True;
244 } else {
245 path = database->path;
247 WMWritePropListToFile(database->appDomain, path, True);
248 database->dirty = 0;
249 if (stat(path, &stbuf) >= 0)
250 database->timestamp = stbuf.st_mtime;
251 if (release)
252 wfree(path);
257 WMUserDefaults*
258 WMGetStandardUserDefaults(void)
260 WMUserDefaults *defaults;
261 WMPropList *domain;
262 WMPropList *key;
263 struct stat stbuf;
264 char *path;
265 int i;
267 if (sharedUserDefaults) {
268 defaults = sharedUserDefaults;
269 while (defaults) {
270 /* Trick, path == NULL only for StandardUserDefaults db */
271 if (defaults->path == NULL)
272 return defaults;
273 defaults = defaults->next;
277 /* we didn't found the database we are looking for. Go read it. */
278 defaults = wmalloc(sizeof(WMUserDefaults));
279 memset(defaults, 0, sizeof(WMUserDefaults));
281 defaults->defaults = WMCreatePLDictionary(NULL, NULL, NULL);
283 defaults->searchList = wmalloc(sizeof(WMPropList*)*3);
285 /* application domain */
286 key = WMCreatePLString(WMGetApplicationName());
287 defaults->searchList[0] = key;
289 /* temporary kluge */
290 if (strcmp(WMGetApplicationName(), "WindowMaker")==0) {
291 domain = NULL;
292 path = NULL;
293 } else {
294 path = wdefaultspathfordomain(WMGetFromPLString(key));
296 if (stat(path, &stbuf) >= 0)
297 defaults->timestamp = stbuf.st_mtime;
299 domain = WMReadPropListFromFile(path);
302 if (!domain)
303 domain = WMCreatePLDictionary(NULL, NULL, NULL);
305 if (path)
306 wfree(path);
308 defaults->appDomain = domain;
310 if (domain)
311 WMPutInPLDictionary(defaults->defaults, key, domain);
313 /* global domain */
314 key = WMCreatePLString("WMGLOBAL");
315 defaults->searchList[1] = key;
317 path = wdefaultspathfordomain(WMGetFromPLString(key));
319 domain = WMReadPropListFromFile(path);
321 wfree(path);
323 if (!domain)
324 domain = WMCreatePLDictionary(NULL, NULL, NULL);
326 if (domain)
327 WMPutInPLDictionary(defaults->defaults, key, domain);
329 /* terminate list */
330 defaults->searchList[2] = NULL;
332 defaults->searchListArray = WMCreatePLArray(NULL,NULL);
334 i = 0;
335 while (defaults->searchList[i]) {
336 WMAddToPLArray(defaults->searchListArray,
337 defaults->searchList[i]);
338 i++;
341 if (sharedUserDefaults)
342 defaults->next = sharedUserDefaults;
343 sharedUserDefaults = defaults;
345 addSynchronizeTimerHandler();
346 registerSaveOnExit();
348 return defaults;
352 WMUserDefaults*
353 WMGetDefaultsFromPath(char *path)
355 WMUserDefaults *defaults;
356 WMPropList *domain;
357 WMPropList *key;
358 struct stat stbuf;
359 char *name;
360 int i;
362 assert(path != NULL);
364 if (sharedUserDefaults) {
365 defaults = sharedUserDefaults;
366 while (defaults) {
367 if (defaults->path && strcmp(defaults->path, path) == 0)
368 return defaults;
369 defaults = defaults->next;
373 /* we didn't found the database we are looking for. Go read it. */
374 defaults = wmalloc(sizeof(WMUserDefaults));
375 memset(defaults, 0, sizeof(WMUserDefaults));
377 defaults->defaults = WMCreatePLDictionary(NULL, NULL, NULL);
379 defaults->searchList = wmalloc(sizeof(WMPropList*)*2);
381 /* the domain we want, go in the first position */
382 name = strrchr(path, '/');
383 if (!name)
384 name = path;
385 else
386 name++;
388 key = WMCreatePLString(name);
389 defaults->searchList[0] = key;
391 if (stat(path, &stbuf) >= 0)
392 defaults->timestamp = stbuf.st_mtime;
394 domain = WMReadPropListFromFile(path);
396 if (!domain)
397 domain = WMCreatePLDictionary(NULL, NULL, NULL);
399 defaults->path = wstrdup(path);
401 defaults->appDomain = domain;
403 if (domain)
404 WMPutInPLDictionary(defaults->defaults, key, domain);
406 /* terminate list */
407 defaults->searchList[1] = NULL;
409 defaults->searchListArray = WMCreatePLArray(NULL,NULL);
411 i = 0;
412 while (defaults->searchList[i]) {
413 WMAddToPLArray(defaults->searchListArray,
414 defaults->searchList[i]);
415 i++;
418 if (sharedUserDefaults)
419 defaults->next = sharedUserDefaults;
420 sharedUserDefaults = defaults;
422 addSynchronizeTimerHandler();
423 registerSaveOnExit();
425 return defaults;
429 /* Returns a WMPropList array with all keys in the user defaults database.
430 * Free the array with WMReleasePropList() when no longer needed,
431 * but do not free the elements of the array! They're just references. */
432 WMPropList*
433 WMGetUDKeys(WMUserDefaults *database)
435 return WMGetPLDictionaryKeys(database->appDomain);
439 WMPropList*
440 WMGetUDObjectForKey(WMUserDefaults *database, char *defaultName)
442 WMPropList *domainName, *domain;
443 WMPropList *object = NULL;
444 WMPropList *key = WMCreatePLString(defaultName);
445 int i = 0;
447 while (database->searchList[i] && !object) {
448 domainName = database->searchList[i];
449 domain = WMGetFromPLDictionary(database->defaults, domainName);
450 if (domain) {
451 object = WMGetFromPLDictionary(domain, key);
453 i++;
455 WMReleasePropList(key);
457 return object;
461 void
462 WMSetUDObjectForKey(WMUserDefaults *database, WMPropList *object,
463 char *defaultName)
465 WMPropList *key = WMCreatePLString(defaultName);
467 database->dirty = 1;
469 WMPutInPLDictionary(database->appDomain, key, object);
470 WMReleasePropList(key);
474 void
475 WMRemoveUDObjectForKey(WMUserDefaults *database, char *defaultName)
477 WMPropList *key = WMCreatePLString(defaultName);
479 database->dirty = 1;
481 WMRemoveFromPLDictionary(database->appDomain, key);
483 WMReleasePropList(key);
487 char*
488 WMGetUDStringForKey(WMUserDefaults *database, char *defaultName)
490 WMPropList *val;
492 val = WMGetUDObjectForKey(database, defaultName);
494 if (!val)
495 return NULL;
497 if (!WMIsPLString(val))
498 return NULL;
500 return WMGetFromPLString(val);
505 WMGetUDIntegerForKey(WMUserDefaults *database, char *defaultName)
507 WMPropList *val;
508 char *str;
509 int value;
511 val = WMGetUDObjectForKey(database, defaultName);
513 if (!val)
514 return 0;
516 if (!WMIsPLString(val))
517 return 0;
519 str = WMGetFromPLString(val);
520 if (!str)
521 return 0;
523 if (sscanf(str, "%i", &value)!=1)
524 return 0;
526 return value;
531 float
532 WMGetUDFloatForKey(WMUserDefaults *database, char *defaultName)
534 WMPropList *val;
535 char *str;
536 float value;
538 val = WMGetUDObjectForKey(database, defaultName);
540 if (!val || !WMIsPLString(val))
541 return 0.0;
543 if (!(str = WMGetFromPLString(val)))
544 return 0.0;
546 if (sscanf(str, "%f", &value)!=1)
547 return 0.0;
549 return value;
554 Bool
555 WMGetUDBoolForKey(WMUserDefaults *database, char *defaultName)
557 WMPropList *val;
558 int value;
559 char *str;
561 val = WMGetUDObjectForKey(database, defaultName);
563 if (!val)
564 return False;
566 if (!WMIsPLString(val))
567 return False;
569 str = WMGetFromPLString(val);
570 if (!str)
571 return False;
573 if (sscanf(str, "%i", &value)==1 && value!=0)
574 return True;
576 if (strcasecmp(str, "YES")==0)
577 return True;
579 if (strcasecmp(str, "Y")==0)
580 return True;
582 return False;
586 void
587 WMSetUDIntegerForKey(WMUserDefaults *database, int value, char *defaultName)
589 WMPropList *object;
590 char buffer[128];
592 sprintf(buffer, "%i", value);
593 object = WMCreatePLString(buffer);
595 WMSetUDObjectForKey(database, object, defaultName);
596 WMReleasePropList(object);
602 void
603 WMSetUDStringForKey(WMUserDefaults *database, char *value, char *defaultName)
605 WMPropList *object;
607 object = WMCreatePLString(value);
609 WMSetUDObjectForKey(database, object, defaultName);
610 WMReleasePropList(object);
615 void
616 WMSetUDFloatForKey(WMUserDefaults *database, float value, char *defaultName)
618 WMPropList *object;
619 char buffer[128];
621 sprintf(buffer, "%f", value);
622 object = WMCreatePLString(buffer);
624 WMSetUDObjectForKey(database, object, defaultName);
625 WMReleasePropList(object);
630 void
631 WMSetUDBoolForKey(WMUserDefaults *database, Bool value, char *defaultName)
633 static WMPropList *yes = NULL, *no = NULL;
635 if (!yes) {
636 yes = WMCreatePLString("YES");
637 no = WMCreatePLString("NO");
640 WMSetUDObjectForKey(database, value ? yes : no, defaultName);
644 WMPropList*
645 WMGetUDSearchList(WMUserDefaults *database)
647 return database->searchListArray;
651 void
652 WMSetUDSearchList(WMUserDefaults *database, WMPropList *list)
654 int i, c;
656 if (database->searchList) {
657 i = 0;
658 while (database->searchList[i]) {
659 WMReleasePropList(database->searchList[i]);
660 i++;
662 wfree(database->searchList);
664 if (database->searchListArray) {
665 WMReleasePropList(database->searchListArray);
668 c = WMGetPropListItemCount(list);
669 database->searchList = wmalloc(sizeof(WMPropList*)*(c+1));
671 for (i=0; i<c; i++) {
672 database->searchList[i] = WMGetFromPLArray(list, i);
675 database->searchListArray = WMDeepCopyPropList(list);