changed indentation to use spaces only
[wmaker-crm.git] / WINGs / userdefaults.c
blob465d6bf9ebed71e65eebe8a9a3136bc5c91c4991
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 "wconfig.h"
12 #include "WINGs.h"
16 typedef struct W_UserDefaults {
17 WMPropList *defaults;
19 WMPropList *appDomain;
21 WMPropList *searchListArray;
22 WMPropList **searchList; /* cache for searchListArray */
24 char dirty;
26 char dontSync;
28 char *path; /* where is db located */
30 time_t timestamp; /* last modification time */
32 struct W_UserDefaults *next;
34 } UserDefaults;
37 static UserDefaults *sharedUserDefaults = NULL;
39 char *WMUserDefaultsDidChangeNotification = "WMUserDefaultsDidChangeNotification";
42 static void synchronizeUserDefaults(void *foo);
44 extern char *WMGetApplicationName();
46 #define DEFAULTS_DIR "/Defaults"
48 #define UD_SYNC_INTERVAL 2000
52 char*
53 wusergnusteppath()
55 static char *path = NULL;
56 char *gspath;
57 int pathlen;
59 if (!path) {
60 gspath = getenv("GNUSTEP_USER_ROOT");
61 if (gspath) {
62 gspath = wexpandpath(gspath);
63 pathlen = strlen(gspath) + 4;
64 path = wmalloc(pathlen);
65 strcpy(path, gspath);
66 wfree(gspath);
67 } else {
68 pathlen = strlen(wgethomedir()) + 10;
69 path = wmalloc(pathlen);
70 strcpy(path, wgethomedir());
71 strcat(path, "/GNUstep");
75 return path;
79 char*
80 wdefaultspathfordomain(char *domain)
82 char *path;
83 char *gspath;
85 gspath = wusergnusteppath();
86 path = wmalloc(strlen(gspath)+strlen(DEFAULTS_DIR)+strlen(domain)+4);
87 strcpy(path, gspath);
88 strcat(path, DEFAULTS_DIR);
89 strcat(path, "/");
90 strcat(path, domain);
92 return path;
96 static void
97 #ifdef HAVE_ATEXIT
98 saveDefaultsChanges(void)
99 #else
100 saveDefaultsChanges(int foo, void *bar)
101 #endif
103 /* save the user defaults databases */
104 synchronizeUserDefaults(NULL);
108 /* set to save changes in defaults when program is exited */
109 static void
110 registerSaveOnExit(void)
112 static Bool registeredSaveOnExit = False;
114 if (!registeredSaveOnExit) {
115 #ifdef HAVE_ATEXIT
116 atexit(saveDefaultsChanges);
117 #else
118 on_exit(saveDefaultsChanges, (void*)NULL);
119 #endif
120 registeredSaveOnExit = True;
125 static void
126 synchronizeUserDefaults(void *foo)
128 UserDefaults *database = sharedUserDefaults;
130 while (database) {
131 if (!database->dontSync)
132 WMSynchronizeUserDefaults(database);
133 database = database->next;
138 static void
139 addSynchronizeTimerHandler(void)
141 static Bool initialized = False;
143 if (!initialized) {
144 WMAddPersistentTimerHandler(UD_SYNC_INTERVAL, synchronizeUserDefaults,
145 NULL);
146 initialized = True;
151 void
152 WMEnableUDPeriodicSynchronization(WMUserDefaults *database, Bool enable)
154 database->dontSync = !enable;
158 void
159 WMSynchronizeUserDefaults(WMUserDefaults *database)
161 Bool fileIsNewer = False, release = False, notify = False;
162 WMPropList *plF, *key;
163 char *path;
164 struct stat stbuf;
166 if (!database->path) {
167 path = wdefaultspathfordomain(WMGetApplicationName());
168 release = True;
169 } else {
170 path = database->path;
173 if (stat(path, &stbuf) >= 0 && stbuf.st_mtime > database->timestamp)
174 fileIsNewer = True;
176 if (database->appDomain && (database->dirty || fileIsNewer)) {
177 if (database->dirty && fileIsNewer) {
178 plF = WMReadPropListFromFile(path);
179 if (plF) {
180 plF = WMMergePLDictionaries(plF, database->appDomain, False);
181 WMReleasePropList(database->appDomain);
182 database->appDomain = plF;
183 key = database->searchList[0];
184 WMPutInPLDictionary(database->defaults, key, plF);
185 notify = True;
186 } else {
187 /* something happened with the file. just overwrite it */
188 wwarning(_("cannot read domain from file '%s' when syncing"),
189 path);
190 WMWritePropListToFile(database->appDomain, path, True);
192 } else if (database->dirty) {
193 WMWritePropListToFile(database->appDomain, path, True);
194 } else if (fileIsNewer) {
195 plF = WMReadPropListFromFile(path);
196 if (plF) {
197 WMReleasePropList(database->appDomain);
198 database->appDomain = plF;
199 key = database->searchList[0];
200 WMPutInPLDictionary(database->defaults, key, plF);
201 notify = True;
202 } else {
203 /* something happened with the file. just overwrite it */
204 wwarning(_("cannot read domain from file '%s' when syncing"),
205 path);
206 WMWritePropListToFile(database->appDomain, path, True);
210 database->dirty = 0;
212 if (stat(path, &stbuf) >= 0)
213 database->timestamp = stbuf.st_mtime;
215 if (notify) {
216 WMPostNotificationName(WMUserDefaultsDidChangeNotification,
217 database, NULL);
221 if (release)
222 wfree(path);
227 void
228 WMSaveUserDefaults(WMUserDefaults *database)
230 if (database->appDomain) {
231 struct stat stbuf;
232 char *path;
233 Bool release = False;
235 if (!database->path) {
236 path = wdefaultspathfordomain(WMGetApplicationName());
237 release = True;
238 } else {
239 path = database->path;
241 WMWritePropListToFile(database->appDomain, path, True);
242 database->dirty = 0;
243 if (stat(path, &stbuf) >= 0)
244 database->timestamp = stbuf.st_mtime;
245 if (release)
246 wfree(path);
251 WMUserDefaults*
252 WMGetStandardUserDefaults(void)
254 WMUserDefaults *defaults;
255 WMPropList *domain;
256 WMPropList *key;
257 struct stat stbuf;
258 char *path;
259 int i;
261 if (sharedUserDefaults) {
262 defaults = sharedUserDefaults;
263 while (defaults) {
264 /* path == NULL only for StandardUserDefaults db */
265 if (defaults->path == NULL)
266 return defaults;
267 defaults = defaults->next;
271 /* we didn't found the database we are looking for. Go read it. */
272 defaults = wmalloc(sizeof(WMUserDefaults));
273 memset(defaults, 0, sizeof(WMUserDefaults));
275 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
277 defaults->searchList = wmalloc(sizeof(WMPropList*)*3);
279 /* application domain */
280 key = WMCreatePLString(WMGetApplicationName());
281 defaults->searchList[0] = key;
283 /* temporary kluge. wmaker handles synchronization itself */
284 if (strcmp(WMGetApplicationName(), "WindowMaker")==0) {
285 defaults->dontSync = 1;
288 path = wdefaultspathfordomain(WMGetFromPLString(key));
290 if (stat(path, &stbuf) >= 0)
291 defaults->timestamp = stbuf.st_mtime;
293 domain = WMReadPropListFromFile(path);
295 if (!domain)
296 domain = WMCreatePLDictionary(NULL, NULL);
298 if (path)
299 wfree(path);
301 defaults->appDomain = domain;
303 if (domain)
304 WMPutInPLDictionary(defaults->defaults, key, domain);
306 /* global domain */
307 key = WMCreatePLString("WMGLOBAL");
308 defaults->searchList[1] = key;
310 path = wdefaultspathfordomain(WMGetFromPLString(key));
312 domain = WMReadPropListFromFile(path);
314 wfree(path);
316 if (!domain)
317 domain = WMCreatePLDictionary(NULL, NULL);
319 if (domain)
320 WMPutInPLDictionary(defaults->defaults, key, domain);
322 /* terminate list */
323 defaults->searchList[2] = NULL;
325 defaults->searchListArray = WMCreatePLArray(NULL,NULL);
327 i = 0;
328 while (defaults->searchList[i]) {
329 WMAddToPLArray(defaults->searchListArray,
330 defaults->searchList[i]);
331 i++;
334 if (sharedUserDefaults)
335 defaults->next = sharedUserDefaults;
336 sharedUserDefaults = defaults;
338 addSynchronizeTimerHandler();
339 registerSaveOnExit();
341 return defaults;
345 WMUserDefaults*
346 WMGetDefaultsFromPath(char *path)
348 WMUserDefaults *defaults;
349 WMPropList *domain;
350 WMPropList *key;
351 struct stat stbuf;
352 char *name;
353 int i;
355 assert(path != NULL);
357 if (sharedUserDefaults) {
358 defaults = sharedUserDefaults;
359 while (defaults) {
360 if (defaults->path && strcmp(defaults->path, path) == 0)
361 return defaults;
362 defaults = defaults->next;
366 /* we didn't found the database we are looking for. Go read it. */
367 defaults = wmalloc(sizeof(WMUserDefaults));
368 memset(defaults, 0, sizeof(WMUserDefaults));
370 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
372 defaults->searchList = wmalloc(sizeof(WMPropList*)*2);
374 /* the domain we want, go in the first position */
375 name = strrchr(path, '/');
376 if (!name)
377 name = path;
378 else
379 name++;
381 key = WMCreatePLString(name);
382 defaults->searchList[0] = key;
384 if (stat(path, &stbuf) >= 0)
385 defaults->timestamp = stbuf.st_mtime;
387 domain = WMReadPropListFromFile(path);
389 if (!domain)
390 domain = WMCreatePLDictionary(NULL, NULL);
392 defaults->path = wstrdup(path);
394 defaults->appDomain = domain;
396 if (domain)
397 WMPutInPLDictionary(defaults->defaults, key, domain);
399 /* terminate list */
400 defaults->searchList[1] = NULL;
402 defaults->searchListArray = WMCreatePLArray(NULL,NULL);
404 i = 0;
405 while (defaults->searchList[i]) {
406 WMAddToPLArray(defaults->searchListArray,
407 defaults->searchList[i]);
408 i++;
411 if (sharedUserDefaults)
412 defaults->next = sharedUserDefaults;
413 sharedUserDefaults = defaults;
415 addSynchronizeTimerHandler();
416 registerSaveOnExit();
418 return defaults;
422 /* Returns a WMPropList array with all keys in the user defaults database.
423 * Free the array with WMReleasePropList() when no longer needed,
424 * but do not free the elements of the array! They're just references. */
425 WMPropList*
426 WMGetUDKeys(WMUserDefaults *database)
428 return WMGetPLDictionaryKeys(database->appDomain);
432 WMPropList*
433 WMGetUDObjectForKey(WMUserDefaults *database, char *defaultName)
435 WMPropList *domainName, *domain;
436 WMPropList *object = NULL;
437 WMPropList *key = WMCreatePLString(defaultName);
438 int i = 0;
440 while (database->searchList[i] && !object) {
441 domainName = database->searchList[i];
442 domain = WMGetFromPLDictionary(database->defaults, domainName);
443 if (domain) {
444 object = WMGetFromPLDictionary(domain, key);
446 i++;
448 WMReleasePropList(key);
450 return object;
454 void
455 WMSetUDObjectForKey(WMUserDefaults *database, WMPropList *object,
456 char *defaultName)
458 WMPropList *key = WMCreatePLString(defaultName);
460 database->dirty = 1;
462 WMPutInPLDictionary(database->appDomain, key, object);
463 WMReleasePropList(key);
467 void
468 WMRemoveUDObjectForKey(WMUserDefaults *database, char *defaultName)
470 WMPropList *key = WMCreatePLString(defaultName);
472 database->dirty = 1;
474 WMRemoveFromPLDictionary(database->appDomain, key);
476 WMReleasePropList(key);
480 char*
481 WMGetUDStringForKey(WMUserDefaults *database, char *defaultName)
483 WMPropList *val;
485 val = WMGetUDObjectForKey(database, defaultName);
487 if (!val)
488 return NULL;
490 if (!WMIsPLString(val))
491 return NULL;
493 return WMGetFromPLString(val);
498 WMGetUDIntegerForKey(WMUserDefaults *database, char *defaultName)
500 WMPropList *val;
501 char *str;
502 int value;
504 val = WMGetUDObjectForKey(database, defaultName);
506 if (!val)
507 return 0;
509 if (!WMIsPLString(val))
510 return 0;
512 str = WMGetFromPLString(val);
513 if (!str)
514 return 0;
516 if (sscanf(str, "%i", &value)!=1)
517 return 0;
519 return value;
524 float
525 WMGetUDFloatForKey(WMUserDefaults *database, char *defaultName)
527 WMPropList *val;
528 char *str;
529 float value;
531 val = WMGetUDObjectForKey(database, defaultName);
533 if (!val || !WMIsPLString(val))
534 return 0.0;
536 if (!(str = WMGetFromPLString(val)))
537 return 0.0;
539 if (sscanf(str, "%f", &value)!=1)
540 return 0.0;
542 return value;
547 Bool
548 WMGetUDBoolForKey(WMUserDefaults *database, char *defaultName)
550 WMPropList *val;
551 int value;
552 char *str;
554 val = WMGetUDObjectForKey(database, defaultName);
556 if (!val)
557 return False;
559 if (!WMIsPLString(val))
560 return False;
562 str = WMGetFromPLString(val);
563 if (!str)
564 return False;
566 if (sscanf(str, "%i", &value)==1 && value!=0)
567 return True;
569 if (strcasecmp(str, "YES")==0)
570 return True;
572 if (strcasecmp(str, "Y")==0)
573 return True;
575 return False;
579 void
580 WMSetUDIntegerForKey(WMUserDefaults *database, int value, char *defaultName)
582 WMPropList *object;
583 char buffer[128];
585 sprintf(buffer, "%i", value);
586 object = WMCreatePLString(buffer);
588 WMSetUDObjectForKey(database, object, defaultName);
589 WMReleasePropList(object);
595 void
596 WMSetUDStringForKey(WMUserDefaults *database, char *value, char *defaultName)
598 WMPropList *object;
600 object = WMCreatePLString(value);
602 WMSetUDObjectForKey(database, object, defaultName);
603 WMReleasePropList(object);
608 void
609 WMSetUDFloatForKey(WMUserDefaults *database, float value, char *defaultName)
611 WMPropList *object;
612 char buffer[128];
614 sprintf(buffer, "%f", value);
615 object = WMCreatePLString(buffer);
617 WMSetUDObjectForKey(database, object, defaultName);
618 WMReleasePropList(object);
623 void
624 WMSetUDBoolForKey(WMUserDefaults *database, Bool value, char *defaultName)
626 static WMPropList *yes = NULL, *no = NULL;
628 if (!yes) {
629 yes = WMCreatePLString("YES");
630 no = WMCreatePLString("NO");
633 WMSetUDObjectForKey(database, value ? yes : no, defaultName);
637 WMPropList*
638 WMGetUDSearchList(WMUserDefaults *database)
640 return database->searchListArray;
644 void
645 WMSetUDSearchList(WMUserDefaults *database, WMPropList *list)
647 int i, c;
649 if (database->searchList) {
650 i = 0;
651 while (database->searchList[i]) {
652 WMReleasePropList(database->searchList[i]);
653 i++;
655 wfree(database->searchList);
657 if (database->searchListArray) {
658 WMReleasePropList(database->searchListArray);
661 c = WMGetPropListItemCount(list);
662 database->searchList = wmalloc(sizeof(WMPropList*)*(c+1));
664 for (i=0; i<c; i++) {
665 database->searchList[i] = WMGetFromPLArray(list, i);
667 database->searchList[c] = NULL;
669 database->searchListArray = WMDeepCopyPropList(list);