*** empty log message ***
[wmaker-crm.git] / WINGs / userdefaults.c
blob47db9abe2c04ecc1e1cdfbff4fcdf717e477498d
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 proplist_t
415 WMGetUDObjectForKey(WMUserDefaults *database, char *defaultName)
417 proplist_t domainName, domain;
418 proplist_t object = NULL;
419 proplist_t key = PLMakeString(defaultName);
420 int i = 0;
422 while (database->searchList[i] && !object) {
423 domainName = database->searchList[i];
424 domain = PLGetDictionaryEntry(database->defaults, domainName);
425 if (domain) {
426 object = PLGetDictionaryEntry(domain, key);
428 i++;
430 PLRelease(key);
432 return object;
436 void
437 WMSetUDObjectForKey(WMUserDefaults *database, proplist_t object,
438 char *defaultName)
440 proplist_t key = PLMakeString(defaultName);
442 database->dirty = 1;
444 PLInsertDictionaryEntry(database->appDomain, key, object);
445 PLRelease(key);
449 void
450 WMRemoveUDObjectForKey(WMUserDefaults *database, char *defaultName)
452 proplist_t key = PLMakeString(defaultName);
454 database->dirty = 1;
456 PLRemoveDictionaryEntry(database->appDomain, key);
458 PLRelease(key);
462 char*
463 WMGetUDStringForKey(WMUserDefaults *database, char *defaultName)
465 proplist_t val;
467 val = WMGetUDObjectForKey(database, defaultName);
469 if (!val)
470 return NULL;
472 if (!PLIsString(val))
473 return NULL;
475 return PLGetString(val);
480 WMGetUDIntegerForKey(WMUserDefaults *database, char *defaultName)
482 proplist_t val;
483 char *str;
484 int value;
486 val = WMGetUDObjectForKey(database, defaultName);
488 if (!val)
489 return 0;
491 if (!PLIsString(val))
492 return 0;
494 str = PLGetString(val);
495 if (!str)
496 return 0;
498 if (sscanf(str, "%i", &value)!=1)
499 return 0;
501 return value;
506 float
507 WMGetUDFloatForKey(WMUserDefaults *database, char *defaultName)
509 proplist_t val;
510 char *str;
511 float value;
513 val = WMGetUDObjectForKey(database, defaultName);
515 if (!val || !PLIsString(val))
516 return 0.0;
518 if (!(str = PLGetString(val)))
519 return 0.0;
521 if (sscanf(str, "%f", &value)!=1)
522 return 0.0;
524 return value;
529 Bool
530 WMGetUDBoolForKey(WMUserDefaults *database, char *defaultName)
532 proplist_t val;
533 int value;
534 char *str;
536 val = WMGetUDObjectForKey(database, defaultName);
538 if (!val)
539 return False;
541 if (!PLIsString(val))
542 return False;
544 str = PLGetString(val);
545 if (!str)
546 return False;
548 if (sscanf(str, "%i", &value)==1 && value!=0)
549 return True;
551 if (strcasecmp(str, "YES")==0)
552 return True;
554 if (strcasecmp(str, "Y")==0)
555 return True;
557 return False;
561 void
562 WMSetUDIntegerForKey(WMUserDefaults *database, int value, char *defaultName)
564 proplist_t object;
565 char buffer[128];
567 sprintf(buffer, "%i", value);
568 object = PLMakeString(buffer);
570 WMSetUDObjectForKey(database, object, defaultName);
571 PLRelease(object);
577 void
578 WMSetUDStringForKey(WMUserDefaults *database, char *value, char *defaultName)
580 proplist_t object;
582 object = PLMakeString(value);
584 WMSetUDObjectForKey(database, object, defaultName);
585 PLRelease(object);
590 void
591 WMSetUDFloatForKey(WMUserDefaults *database, float value, char *defaultName)
593 proplist_t object;
594 char buffer[128];
596 sprintf(buffer, "%f", value);
597 object = PLMakeString(buffer);
599 WMSetUDObjectForKey(database, object, defaultName);
600 PLRelease(object);
605 void
606 WMSetUDBoolForKey(WMUserDefaults *database, Bool value, char *defaultName)
608 static proplist_t yes = NULL, no = NULL;
610 if (!yes) {
611 yes = PLMakeString("YES");
612 no = PLMakeString("NO");
615 WMSetUDObjectForKey(database, value ? yes : no, defaultName);
619 proplist_t
620 WMGetUDSearchList(WMUserDefaults *database)
622 return database->searchListArray;
626 void
627 WMSetUDSearchList(WMUserDefaults *database, proplist_t list)
629 int i, c;
631 if (database->searchList) {
632 i = 0;
633 while (database->searchList[i]) {
634 PLRelease(database->searchList[i]);
635 i++;
637 wfree(database->searchList);
639 if (database->searchListArray) {
640 PLRelease(database->searchListArray);
643 c = PLGetNumberOfElements(list);
644 database->searchList = wmalloc(sizeof(proplist_t)*(c+1));
646 for (i=0; i<c; i++) {
647 database->searchList[i] = PLGetArrayElement(list, i);
650 database->searchListArray = PLDeepCopy(list);