- Added a test in configure for the version of libPropList that is installed
[wmaker-crm.git] / WINGs / userdefaults.c
blobec0577a2598b2a32d0cd0827e28dfae6f72470a5
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 /*printf("syncing: %s %d %d\n", path, database->dirty, fileIsNewer);*/
182 if (database->appDomain && (database->dirty || fileIsNewer)) {
183 PLShallowSynchronize(database->appDomain);
184 database->dirty = 0;
185 if (stat(path, &stbuf) >= 0)
186 database->timestamp = stbuf.st_mtime;
187 if (fileIsNewer) {
188 WMPostNotificationName(WMUserDefaultsDidChangeNotification,
189 database, NULL);
193 if (release)
194 wfree(path);
199 void
200 WMSaveUserDefaults(WMUserDefaults *database)
202 if (database->appDomain) {
203 struct stat stbuf;
204 char *path;
205 Bool release = False;
207 PLSave(database->appDomain, YES);
208 database->dirty = 0;
209 if (!database->path) {
210 path = wdefaultspathfordomain(WMGetApplicationName());
211 release = True;
212 } else {
213 path = database->path;
215 if (stat(path, &stbuf) >= 0)
216 database->timestamp = stbuf.st_mtime;
217 if (release)
218 wfree(path);
223 WMUserDefaults*
224 WMGetStandardUserDefaults(void)
226 WMUserDefaults *defaults;
227 proplist_t domain;
228 proplist_t key;
229 struct stat stbuf;
230 char *path;
231 int i;
233 if (sharedUserDefaults) {
234 defaults = sharedUserDefaults;
235 while (defaults) {
236 /* Trick, path == NULL only for StandardUserDefaults db */
237 if (defaults->path == NULL)
238 return defaults;
239 defaults = defaults->next;
243 /* we didn't found the database we are looking for. Go read it. */
244 defaults = wmalloc(sizeof(WMUserDefaults));
245 memset(defaults, 0, sizeof(WMUserDefaults));
247 defaults->defaults = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
249 defaults->searchList = wmalloc(sizeof(proplist_t)*3);
251 /* application domain */
252 key = PLMakeString(WMGetApplicationName());
253 defaults->searchList[0] = key;
255 /* temporary kluge */
256 if (strcmp(WMGetApplicationName(), "WindowMaker")==0) {
257 domain = NULL;
258 path = NULL;
259 } else {
260 path = wdefaultspathfordomain(PLGetString(key));
262 if (stat(path, &stbuf) >= 0)
263 defaults->timestamp = stbuf.st_mtime;
265 domain = PLGetProplistWithPath(path);
267 if (!domain) {
268 proplist_t p;
270 domain = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
271 if (path) {
272 p = PLMakeString(path);
273 PLSetFilename(domain, p);
274 PLRelease(p);
277 if (path)
278 wfree(path);
280 defaults->appDomain = domain;
282 if (domain)
283 PLInsertDictionaryEntry(defaults->defaults, key, domain);
285 PLRelease(key);
287 /* global domain */
288 key = PLMakeString("WMGLOBAL");
289 defaults->searchList[1] = key;
291 path = wdefaultspathfordomain(PLGetString(key));
293 domain = PLGetProplistWithPath(path);
295 wfree(path);
297 if (!domain)
298 domain = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
300 if (domain)
301 PLInsertDictionaryEntry(defaults->defaults, key, domain);
303 PLRelease(key);
305 /* terminate list */
306 defaults->searchList[2] = NULL;
308 defaults->searchListArray = PLMakeArrayFromElements(NULL,NULL);
310 i = 0;
311 while (defaults->searchList[i]) {
312 PLAppendArrayElement(defaults->searchListArray,
313 defaults->searchList[i]);
314 i++;
317 if (sharedUserDefaults)
318 defaults->next = sharedUserDefaults;
319 sharedUserDefaults = defaults;
321 addSynchronizeTimerHandler();
322 registerSaveOnExit();
324 return defaults;
328 WMUserDefaults*
329 WMGetDefaultsFromPath(char *path)
331 WMUserDefaults *defaults;
332 proplist_t domain;
333 proplist_t key;
334 struct stat stbuf;
335 char *name;
336 int i;
338 assert(path != NULL);
340 if (sharedUserDefaults) {
341 defaults = sharedUserDefaults;
342 while (defaults) {
343 if (defaults->path && strcmp(defaults->path, path) == 0)
344 return defaults;
345 defaults = defaults->next;
349 /* we didn't found the database we are looking for. Go read it. */
350 defaults = wmalloc(sizeof(WMUserDefaults));
351 memset(defaults, 0, sizeof(WMUserDefaults));
353 defaults->defaults = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
355 defaults->searchList = wmalloc(sizeof(proplist_t)*2);
357 /* the domain we want, go in the first position */
358 name = strrchr(path, '/');
359 if (!name)
360 name = path;
361 else
362 name++;
364 key = PLMakeString(name);
365 defaults->searchList[0] = key;
367 if (stat(path, &stbuf) >= 0)
368 defaults->timestamp = stbuf.st_mtime;
370 domain = PLGetProplistWithPath(path);
372 if (!domain) {
373 proplist_t p;
375 domain = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
376 p = PLMakeString(path);
377 PLSetFilename(domain, p);
378 PLRelease(p);
381 defaults->path = wstrdup(path);
383 defaults->appDomain = domain;
385 if (domain)
386 PLInsertDictionaryEntry(defaults->defaults, key, domain);
388 PLRelease(key);
390 /* terminate list */
391 defaults->searchList[1] = NULL;
393 defaults->searchListArray = PLMakeArrayFromElements(NULL,NULL);
395 i = 0;
396 while (defaults->searchList[i]) {
397 PLAppendArrayElement(defaults->searchListArray,
398 defaults->searchList[i]);
399 i++;
402 if (sharedUserDefaults)
403 defaults->next = sharedUserDefaults;
404 sharedUserDefaults = defaults;
406 addSynchronizeTimerHandler();
407 registerSaveOnExit();
409 return defaults;
413 proplist_t
414 WMGetUDObjectForKey(WMUserDefaults *database, char *defaultName)
416 proplist_t domainName, domain;
417 proplist_t object = NULL;
418 proplist_t key = PLMakeString(defaultName);
419 int i = 0;
421 while (database->searchList[i] && !object) {
422 domainName = database->searchList[i];
423 domain = PLGetDictionaryEntry(database->defaults, domainName);
424 if (domain) {
425 object = PLGetDictionaryEntry(domain, key);
427 i++;
429 PLRelease(key);
431 return object;
435 void
436 WMSetUDObjectForKey(WMUserDefaults *database, proplist_t object,
437 char *defaultName)
439 proplist_t key = PLMakeString(defaultName);
441 database->dirty = 1;
443 PLInsertDictionaryEntry(database->appDomain, key, object);
444 PLRelease(key);
448 void
449 WMRemoveUDObjectForKey(WMUserDefaults *database, char *defaultName)
451 proplist_t key = PLMakeString(defaultName);
453 database->dirty = 1;
455 PLRemoveDictionaryEntry(database->appDomain, key);
457 PLRelease(key);
461 char*
462 WMGetUDStringForKey(WMUserDefaults *database, char *defaultName)
464 proplist_t val;
466 val = WMGetUDObjectForKey(database, defaultName);
468 if (!val)
469 return NULL;
471 if (!PLIsString(val))
472 return NULL;
474 return PLGetString(val);
479 WMGetUDIntegerForKey(WMUserDefaults *database, char *defaultName)
481 proplist_t val;
482 char *str;
483 int value;
485 val = WMGetUDObjectForKey(database, defaultName);
487 if (!val)
488 return 0;
490 if (!PLIsString(val))
491 return 0;
493 str = PLGetString(val);
494 if (!str)
495 return 0;
497 if (sscanf(str, "%i", &value)!=1)
498 return 0;
500 return value;
505 float
506 WMGetUDFloatForKey(WMUserDefaults *database, char *defaultName)
508 proplist_t val;
509 char *str;
510 float value;
512 val = WMGetUDObjectForKey(database, defaultName);
514 if (!val || !PLIsString(val))
515 return 0.0;
517 if (!(str = PLGetString(val)))
518 return 0.0;
520 if (sscanf(str, "%f", &value)!=1)
521 return 0.0;
523 return value;
528 Bool
529 WMGetUDBoolForKey(WMUserDefaults *database, char *defaultName)
531 proplist_t val;
532 int value;
533 char *str;
535 val = WMGetUDObjectForKey(database, defaultName);
537 if (!val)
538 return False;
540 if (!PLIsString(val))
541 return False;
543 str = PLGetString(val);
544 if (!str)
545 return False;
547 if (sscanf(str, "%i", &value)==1 && value!=0)
548 return True;
550 if (strcasecmp(str, "YES")==0)
551 return True;
553 if (strcasecmp(str, "Y")==0)
554 return True;
556 return False;
560 void
561 WMSetUDIntegerForKey(WMUserDefaults *database, int value, char *defaultName)
563 proplist_t object;
564 char buffer[128];
566 sprintf(buffer, "%i", value);
567 object = PLMakeString(buffer);
569 WMSetUDObjectForKey(database, object, defaultName);
570 PLRelease(object);
576 void
577 WMSetUDStringForKey(WMUserDefaults *database, char *value, char *defaultName)
579 proplist_t object;
581 object = PLMakeString(value);
583 WMSetUDObjectForKey(database, object, defaultName);
584 PLRelease(object);
589 void
590 WMSetUDFloatForKey(WMUserDefaults *database, float value, char *defaultName)
592 proplist_t object;
593 char buffer[128];
595 sprintf(buffer, "%f", value);
596 object = PLMakeString(buffer);
598 WMSetUDObjectForKey(database, object, defaultName);
599 PLRelease(object);
604 void
605 WMSetUDBoolForKey(WMUserDefaults *database, Bool value, char *defaultName)
607 static proplist_t yes = NULL, no = NULL;
609 if (!yes) {
610 yes = PLMakeString("YES");
611 no = PLMakeString("NO");
614 WMSetUDObjectForKey(database, value ? yes : no, defaultName);
618 proplist_t
619 WMGetUDSearchList(WMUserDefaults *database)
621 return database->searchListArray;
625 void
626 WMSetUDSearchList(WMUserDefaults *database, proplist_t list)
628 int i, c;
630 if (database->searchList) {
631 i = 0;
632 while (database->searchList[i]) {
633 PLRelease(database->searchList[i]);
634 i++;
636 wfree(database->searchList);
638 if (database->searchListArray) {
639 PLRelease(database->searchListArray);
642 c = PLGetNumberOfElements(list);
643 database->searchList = wmalloc(sizeof(proplist_t)*(c+1));
645 for (i=0; i<c; i++) {
646 database->searchList[i] = PLGetArrayElement(list, i);
649 database->searchListArray = PLDeepCopy(list);