Added a function to get all keys in a user defaults database (for databases
[wmaker-crm.git] / WINGs / userdefaults.c
blob126fbfe99b9669d84d0e961e1deb520a6368afe2
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 "WINGs.h"
14 #include <proplist.h>
17 typedef struct W_UserDefaults {
18 proplist_t defaults;
20 proplist_t appDomain;
22 proplist_t searchListArray;
23 proplist_t *searchList; /* cache for searchListArray */
25 char dirty;
27 char dontSync;
29 char *path; /* where is db located */
31 time_t timestamp; /* last modification time */
33 struct W_UserDefaults *next;
35 } UserDefaults;
38 static UserDefaults *sharedUserDefaults = NULL;
40 char *WMUserDefaultsDidChangeNotification = "WMUserDefaultsDidChangeNotification";
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 #ifndef HAVE_ATEXIT
98 saveDefaultsChanges(int foo, void *bar)
99 #else
100 saveDefaultsChanges(void)
101 #endif
103 /* save the user defaults databases */
104 UserDefaults *tmp = sharedUserDefaults;
106 while (tmp) {
107 WMSynchronizeUserDefaults(tmp);
108 tmp = tmp->next;
113 /* set to save changes in defaults when program is exited */
114 static void
115 registerSaveOnExit(void)
117 static Bool registeredSaveOnExit = False;
119 if (!registeredSaveOnExit) {
120 #ifndef HAVE_ATEXIT
121 on_exit(saveDefaultsChanges, (void*)NULL);
122 #else
123 atexit(saveDefaultsChanges);
124 #endif
125 registeredSaveOnExit = True;
130 static void
131 synchronizeUserDefaults(void *foo)
133 UserDefaults *database = sharedUserDefaults;
135 while (database) {
136 if (!database->dontSync)
137 WMSynchronizeUserDefaults(database);
138 database = database->next;
140 WMAddTimerHandler(UD_SYNC_INTERVAL, synchronizeUserDefaults, NULL);
144 static void
145 addSynchronizeTimerHandler(void)
147 static Bool initialized = False;
149 if (!initialized) {
150 WMAddTimerHandler(UD_SYNC_INTERVAL, synchronizeUserDefaults, NULL);
151 initialized = True;
156 void
157 WMEnableUDPeriodicSynchronization(WMUserDefaults *database, Bool enable)
159 database->dontSync = !enable;
163 void
164 WMSynchronizeUserDefaults(WMUserDefaults *database)
166 Bool fileIsNewer = False, release = False;
167 char *path;
168 struct stat stbuf;
170 if (!database->path) {
171 path = wdefaultspathfordomain(WMGetApplicationName());
172 release = True;
173 } else {
174 path = database->path;
177 if (stat(path, &stbuf) >= 0 && stbuf.st_mtime > database->timestamp)
178 fileIsNewer = True;
180 if (database->appDomain && (database->dirty || fileIsNewer)) {
182 /*fprintf(stderr, "syncing: %s %d %d\n", path, database->dirty, fileIsNewer);*/
184 PLShallowSynchronize(database->appDomain);
185 database->dirty = 0;
186 if (stat(path, &stbuf) >= 0)
187 database->timestamp = stbuf.st_mtime;
188 if (fileIsNewer) {
189 WMPostNotificationName(WMUserDefaultsDidChangeNotification,
190 database, NULL);
194 if (release)
195 wfree(path);
200 void
201 WMSaveUserDefaults(WMUserDefaults *database)
203 if (database->appDomain) {
204 struct stat stbuf;
205 char *path;
206 Bool release = False;
208 PLSave(database->appDomain, YES);
209 database->dirty = 0;
210 if (!database->path) {
211 path = wdefaultspathfordomain(WMGetApplicationName());
212 release = True;
213 } else {
214 path = database->path;
216 if (stat(path, &stbuf) >= 0)
217 database->timestamp = stbuf.st_mtime;
218 if (release)
219 wfree(path);
224 WMUserDefaults*
225 WMGetStandardUserDefaults(void)
227 WMUserDefaults *defaults;
228 proplist_t domain;
229 proplist_t key;
230 struct stat stbuf;
231 char *path;
232 int i;
234 if (sharedUserDefaults) {
235 defaults = sharedUserDefaults;
236 while (defaults) {
237 /* Trick, path == NULL only for StandardUserDefaults db */
238 if (defaults->path == NULL)
239 return defaults;
240 defaults = defaults->next;
244 /* we didn't found the database we are looking for. Go read it. */
245 defaults = wmalloc(sizeof(WMUserDefaults));
246 memset(defaults, 0, sizeof(WMUserDefaults));
248 defaults->defaults = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
250 defaults->searchList = wmalloc(sizeof(proplist_t)*3);
252 /* application domain */
253 key = PLMakeString(WMGetApplicationName());
254 defaults->searchList[0] = key;
256 /* temporary kluge */
257 if (strcmp(WMGetApplicationName(), "WindowMaker")==0) {
258 domain = NULL;
259 path = NULL;
260 } else {
261 path = wdefaultspathfordomain(PLGetString(key));
263 if (stat(path, &stbuf) >= 0)
264 defaults->timestamp = stbuf.st_mtime;
266 domain = PLGetProplistWithPath(path);
268 if (!domain) {
269 proplist_t p;
271 domain = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
272 if (path) {
273 p = PLMakeString(path);
274 PLSetFilename(domain, p);
275 PLRelease(p);
278 if (path)
279 wfree(path);
281 defaults->appDomain = domain;
283 if (domain)
284 PLInsertDictionaryEntry(defaults->defaults, key, domain);
286 PLRelease(key);
288 /* global domain */
289 key = PLMakeString("WMGLOBAL");
290 defaults->searchList[1] = key;
292 path = wdefaultspathfordomain(PLGetString(key));
294 domain = PLGetProplistWithPath(path);
296 wfree(path);
298 if (!domain)
299 domain = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
301 if (domain)
302 PLInsertDictionaryEntry(defaults->defaults, key, domain);
304 PLRelease(key);
306 /* terminate list */
307 defaults->searchList[2] = NULL;
309 defaults->searchListArray = PLMakeArrayFromElements(NULL,NULL);
311 i = 0;
312 while (defaults->searchList[i]) {
313 PLAppendArrayElement(defaults->searchListArray,
314 defaults->searchList[i]);
315 i++;
318 if (sharedUserDefaults)
319 defaults->next = sharedUserDefaults;
320 sharedUserDefaults = defaults;
322 addSynchronizeTimerHandler();
323 registerSaveOnExit();
325 return defaults;
329 WMUserDefaults*
330 WMGetDefaultsFromPath(char *path)
332 WMUserDefaults *defaults;
333 proplist_t domain;
334 proplist_t key;
335 struct stat stbuf;
336 char *name;
337 int i;
339 assert(path != NULL);
341 if (sharedUserDefaults) {
342 defaults = sharedUserDefaults;
343 while (defaults) {
344 if (defaults->path && strcmp(defaults->path, path) == 0)
345 return defaults;
346 defaults = defaults->next;
350 /* we didn't found the database we are looking for. Go read it. */
351 defaults = wmalloc(sizeof(WMUserDefaults));
352 memset(defaults, 0, sizeof(WMUserDefaults));
354 defaults->defaults = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
356 defaults->searchList = wmalloc(sizeof(proplist_t)*2);
358 /* the domain we want, go in the first position */
359 name = strrchr(path, '/');
360 if (!name)
361 name = path;
362 else
363 name++;
365 key = PLMakeString(name);
366 defaults->searchList[0] = key;
368 if (stat(path, &stbuf) >= 0)
369 defaults->timestamp = stbuf.st_mtime;
371 domain = PLGetProplistWithPath(path);
373 if (!domain) {
374 proplist_t p;
376 domain = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
377 p = PLMakeString(path);
378 PLSetFilename(domain, p);
379 PLRelease(p);
382 defaults->path = wstrdup(path);
384 defaults->appDomain = domain;
386 if (domain)
387 PLInsertDictionaryEntry(defaults->defaults, key, domain);
389 PLRelease(key);
391 /* terminate list */
392 defaults->searchList[1] = NULL;
394 defaults->searchListArray = PLMakeArrayFromElements(NULL,NULL);
396 i = 0;
397 while (defaults->searchList[i]) {
398 PLAppendArrayElement(defaults->searchListArray,
399 defaults->searchList[i]);
400 i++;
403 if (sharedUserDefaults)
404 defaults->next = sharedUserDefaults;
405 sharedUserDefaults = defaults;
407 addSynchronizeTimerHandler();
408 registerSaveOnExit();
410 return defaults;
414 /* Returns a PLArray with all keys in the user defaults database.
415 * Free the returned array with PLRelease() when no longer needed,
416 * but do not free the elements of the array! They're just references. */
417 proplist_t
418 WMGetUDAllKeys(WMUserDefaults *database)
420 return PLGetAllDictionaryKeys(database->defaults);
424 proplist_t
425 WMGetUDObjectForKey(WMUserDefaults *database, char *defaultName)
427 proplist_t domainName, domain;
428 proplist_t object = NULL;
429 proplist_t key = PLMakeString(defaultName);
430 int i = 0;
432 while (database->searchList[i] && !object) {
433 domainName = database->searchList[i];
434 domain = PLGetDictionaryEntry(database->defaults, domainName);
435 if (domain) {
436 object = PLGetDictionaryEntry(domain, key);
438 i++;
440 PLRelease(key);
442 return object;
446 void
447 WMSetUDObjectForKey(WMUserDefaults *database, proplist_t object,
448 char *defaultName)
450 proplist_t key = PLMakeString(defaultName);
452 database->dirty = 1;
454 PLInsertDictionaryEntry(database->appDomain, key, object);
455 PLRelease(key);
459 void
460 WMRemoveUDObjectForKey(WMUserDefaults *database, char *defaultName)
462 proplist_t key = PLMakeString(defaultName);
464 database->dirty = 1;
466 PLRemoveDictionaryEntry(database->appDomain, key);
468 PLRelease(key);
472 char*
473 WMGetUDStringForKey(WMUserDefaults *database, char *defaultName)
475 proplist_t val;
477 val = WMGetUDObjectForKey(database, defaultName);
479 if (!val)
480 return NULL;
482 if (!PLIsString(val))
483 return NULL;
485 return PLGetString(val);
490 WMGetUDIntegerForKey(WMUserDefaults *database, char *defaultName)
492 proplist_t val;
493 char *str;
494 int value;
496 val = WMGetUDObjectForKey(database, defaultName);
498 if (!val)
499 return 0;
501 if (!PLIsString(val))
502 return 0;
504 str = PLGetString(val);
505 if (!str)
506 return 0;
508 if (sscanf(str, "%i", &value)!=1)
509 return 0;
511 return value;
516 float
517 WMGetUDFloatForKey(WMUserDefaults *database, char *defaultName)
519 proplist_t val;
520 char *str;
521 float value;
523 val = WMGetUDObjectForKey(database, defaultName);
525 if (!val || !PLIsString(val))
526 return 0.0;
528 if (!(str = PLGetString(val)))
529 return 0.0;
531 if (sscanf(str, "%f", &value)!=1)
532 return 0.0;
534 return value;
539 Bool
540 WMGetUDBoolForKey(WMUserDefaults *database, char *defaultName)
542 proplist_t val;
543 int value;
544 char *str;
546 val = WMGetUDObjectForKey(database, defaultName);
548 if (!val)
549 return False;
551 if (!PLIsString(val))
552 return False;
554 str = PLGetString(val);
555 if (!str)
556 return False;
558 if (sscanf(str, "%i", &value)==1 && value!=0)
559 return True;
561 if (strcasecmp(str, "YES")==0)
562 return True;
564 if (strcasecmp(str, "Y")==0)
565 return True;
567 return False;
571 void
572 WMSetUDIntegerForKey(WMUserDefaults *database, int value, char *defaultName)
574 proplist_t object;
575 char buffer[128];
577 sprintf(buffer, "%i", value);
578 object = PLMakeString(buffer);
580 WMSetUDObjectForKey(database, object, defaultName);
581 PLRelease(object);
587 void
588 WMSetUDStringForKey(WMUserDefaults *database, char *value, char *defaultName)
590 proplist_t object;
592 object = PLMakeString(value);
594 WMSetUDObjectForKey(database, object, defaultName);
595 PLRelease(object);
600 void
601 WMSetUDFloatForKey(WMUserDefaults *database, float value, char *defaultName)
603 proplist_t object;
604 char buffer[128];
606 sprintf(buffer, "%f", value);
607 object = PLMakeString(buffer);
609 WMSetUDObjectForKey(database, object, defaultName);
610 PLRelease(object);
615 void
616 WMSetUDBoolForKey(WMUserDefaults *database, Bool value, char *defaultName)
618 static proplist_t yes = NULL, no = NULL;
620 if (!yes) {
621 yes = PLMakeString("YES");
622 no = PLMakeString("NO");
625 WMSetUDObjectForKey(database, value ? yes : no, defaultName);
629 proplist_t
630 WMGetUDSearchList(WMUserDefaults *database)
632 return database->searchListArray;
636 void
637 WMSetUDSearchList(WMUserDefaults *database, proplist_t list)
639 int i, c;
641 if (database->searchList) {
642 i = 0;
643 while (database->searchList[i]) {
644 PLRelease(database->searchList[i]);
645 i++;
647 wfree(database->searchList);
649 if (database->searchListArray) {
650 PLRelease(database->searchListArray);
653 c = PLGetNumberOfElements(list);
654 database->searchList = wmalloc(sizeof(proplist_t)*(c+1));
656 for (i=0; i<c; i++) {
657 database->searchList[i] = PLGetArrayElement(list, i);
660 database->searchListArray = PLDeepCopy(list);