Make inotify optional
[wmaker-crm.git] / WINGs / userdefaults.c
blobee3a3b73ceabdf204ed48d6c0fd32e3a2c6a2caa
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>
9 #include "wconfig.h"
11 #include "WINGs.h"
13 typedef struct W_UserDefaults {
14 WMPropList *defaults;
16 WMPropList *appDomain;
18 WMPropList *searchListArray;
19 WMPropList **searchList; /* cache for searchListArray */
21 char dirty;
23 char dontSync;
25 char *path; /* where is db located */
27 time_t timestamp; /* last modification time */
29 struct W_UserDefaults *next;
31 } UserDefaults;
33 static UserDefaults *sharedUserDefaults = NULL;
35 char *WMUserDefaultsDidChangeNotification = "WMUserDefaultsDidChangeNotification";
37 static void synchronizeUserDefaults(void *foo);
39 extern char *WMGetApplicationName();
41 #define DEFAULTS_DIR "/Defaults"
42 #ifndef HAVE_INOTIFY
43 /* Check defaults database for changes every this many milliseconds */
44 /* XXX: this is shared with src/ stuff, put it in some common header */
45 #define UD_SYNC_INTERVAL 2000
46 #endif
48 char *wusergnusteppath()
50 static char *path = NULL;
51 char *gspath;
52 int pathlen;
54 if (!path) {
55 gspath = getenv("GNUSTEP_USER_ROOT");
56 if (gspath) {
57 gspath = wexpandpath(gspath);
58 pathlen = strlen(gspath) + 4;
59 path = wmalloc(pathlen);
60 strcpy(path, gspath);
61 wfree(gspath);
62 } else {
63 pathlen = strlen(wgethomedir()) + 10;
64 path = wmalloc(pathlen);
65 strcpy(path, wgethomedir());
66 strcat(path, "/GNUstep");
70 return path;
73 char *wdefaultspathfordomain(char *domain)
75 char *path;
76 char *gspath;
78 gspath = wusergnusteppath();
79 path = wmalloc(strlen(gspath) + strlen(DEFAULTS_DIR) + strlen(domain) + 4);
80 strcpy(path, gspath);
81 strcat(path, DEFAULTS_DIR);
82 strcat(path, "/");
83 strcat(path, domain);
85 return path;
88 /* XXX: doesn't quite belong to *user*defaults.c */
89 #ifndef GLOBAL_DEFAULTS_SUBDIR
90 #define GLOBAL_DEFAULTS_SUBDIR "WindowMaker"
91 #endif
92 char *wglobaldefaultspathfordomain(const char *domain)
94 char *t = NULL;
95 size_t len;
97 len = strlen( SYSCONFDIR ) + strlen( GLOBAL_DEFAULTS_SUBDIR ) + strlen(domain) + 3;
98 t = wmalloc(len);
99 snprintf(t, len, "%s/%s/%s", SYSCONFDIR, GLOBAL_DEFAULTS_SUBDIR, domain);
101 return t;
104 static void
105 #ifdef HAVE_ATEXIT
106 saveDefaultsChanges(void)
107 #else
108 saveDefaultsChanges(int foo, void *bar)
109 #endif
111 /* save the user defaults databases */
112 synchronizeUserDefaults(NULL);
115 /* set to save changes in defaults when program is exited */
116 static void registerSaveOnExit(void)
118 static Bool registeredSaveOnExit = False;
120 if (!registeredSaveOnExit) {
121 #ifdef HAVE_ATEXIT
122 atexit(saveDefaultsChanges);
123 #else
124 on_exit(saveDefaultsChanges, (void *)NULL);
125 #endif
126 registeredSaveOnExit = True;
130 static void synchronizeUserDefaults(void *foo)
132 UserDefaults *database = sharedUserDefaults;
134 while (database) {
135 if (!database->dontSync)
136 WMSynchronizeUserDefaults(database);
137 database = database->next;
141 #ifndef HAVE_INOTIFY
142 static void addSynchronizeTimerHandler(void)
144 static Bool initialized = False;
146 if (!initialized) {
147 WMAddPersistentTimerHandler(UD_SYNC_INTERVAL,
148 synchronizeUserDefaults, NULL);
149 initialized = True;
152 #endif
154 void WMEnableUDPeriodicSynchronization(WMUserDefaults * database, Bool enable)
156 database->dontSync = !enable;
159 void 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"), path);
189 WMWritePropListToFile(database->appDomain, path);
191 } else if (database->dirty) {
192 WMWritePropListToFile(database->appDomain, path);
193 } else if (fileIsNewer) {
194 plF = WMReadPropListFromFile(path);
195 if (plF) {
196 WMReleasePropList(database->appDomain);
197 database->appDomain = plF;
198 key = database->searchList[0];
199 WMPutInPLDictionary(database->defaults, key, plF);
200 notify = True;
201 } else {
202 /* something happened with the file. just overwrite it */
203 wwarning(_("cannot read domain from file '%s' when syncing"), path);
204 WMWritePropListToFile(database->appDomain, path);
208 database->dirty = 0;
210 if (stat(path, &stbuf) >= 0)
211 database->timestamp = stbuf.st_mtime;
213 if (notify) {
214 WMPostNotificationName(WMUserDefaultsDidChangeNotification, database, NULL);
218 if (release)
219 wfree(path);
223 void WMSaveUserDefaults(WMUserDefaults * database)
225 if (database->appDomain) {
226 struct stat stbuf;
227 char *path;
228 Bool release = False;
230 if (!database->path) {
231 path = wdefaultspathfordomain(WMGetApplicationName());
232 release = True;
233 } else {
234 path = database->path;
236 WMWritePropListToFile(database->appDomain, path);
237 database->dirty = 0;
238 if (stat(path, &stbuf) >= 0)
239 database->timestamp = stbuf.st_mtime;
240 if (release)
241 wfree(path);
245 WMUserDefaults *WMGetStandardUserDefaults(void)
247 WMUserDefaults *defaults;
248 WMPropList *domain;
249 WMPropList *key;
250 struct stat stbuf;
251 char *path;
252 int i;
254 if (sharedUserDefaults) {
255 defaults = sharedUserDefaults;
256 while (defaults) {
257 /* path == NULL only for StandardUserDefaults db */
258 if (defaults->path == NULL)
259 return defaults;
260 defaults = defaults->next;
264 /* we didn't found the database we are looking for. Go read it. */
265 defaults = wmalloc(sizeof(WMUserDefaults));
266 memset(defaults, 0, sizeof(WMUserDefaults));
268 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
270 defaults->searchList = wmalloc(sizeof(WMPropList *) * 3);
272 /* application domain */
273 key = WMCreatePLString(WMGetApplicationName());
274 defaults->searchList[0] = key;
276 /* temporary kluge. wmaker handles synchronization itself */
277 if (strcmp(WMGetApplicationName(), "WindowMaker") == 0) {
278 defaults->dontSync = 1;
281 path = wdefaultspathfordomain(WMGetFromPLString(key));
283 if (stat(path, &stbuf) >= 0)
284 defaults->timestamp = stbuf.st_mtime;
286 domain = WMReadPropListFromFile(path);
288 if (!domain)
289 domain = WMCreatePLDictionary(NULL, NULL);
291 if (path)
292 wfree(path);
294 defaults->appDomain = domain;
296 if (domain)
297 WMPutInPLDictionary(defaults->defaults, key, domain);
299 /* global domain */
300 key = WMCreatePLString("WMGLOBAL");
301 defaults->searchList[1] = key;
303 path = wdefaultspathfordomain(WMGetFromPLString(key));
305 domain = WMReadPropListFromFile(path);
307 wfree(path);
309 if (!domain)
310 domain = WMCreatePLDictionary(NULL, NULL);
312 if (domain)
313 WMPutInPLDictionary(defaults->defaults, key, domain);
315 /* terminate list */
316 defaults->searchList[2] = NULL;
318 defaults->searchListArray = WMCreatePLArray(NULL, NULL);
320 i = 0;
321 while (defaults->searchList[i]) {
322 WMAddToPLArray(defaults->searchListArray, defaults->searchList[i]);
323 i++;
326 if (sharedUserDefaults)
327 defaults->next = sharedUserDefaults;
328 sharedUserDefaults = defaults;
330 #ifndef HAVE_INOTIFY
331 addSynchronizeTimerHandler();
332 #endif
333 registerSaveOnExit();
335 return defaults;
338 WMUserDefaults *WMGetDefaultsFromPath(char *path)
340 WMUserDefaults *defaults;
341 WMPropList *domain;
342 WMPropList *key;
343 struct stat stbuf;
344 char *name;
345 int i;
347 assert(path != NULL);
349 if (sharedUserDefaults) {
350 defaults = sharedUserDefaults;
351 while (defaults) {
352 if (defaults->path && strcmp(defaults->path, path) == 0)
353 return defaults;
354 defaults = defaults->next;
358 /* we didn't found the database we are looking for. Go read it. */
359 defaults = wmalloc(sizeof(WMUserDefaults));
360 memset(defaults, 0, sizeof(WMUserDefaults));
362 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
364 defaults->searchList = wmalloc(sizeof(WMPropList *) * 2);
366 /* the domain we want, go in the first position */
367 name = strrchr(path, '/');
368 if (!name)
369 name = path;
370 else
371 name++;
373 key = WMCreatePLString(name);
374 defaults->searchList[0] = key;
376 if (stat(path, &stbuf) >= 0)
377 defaults->timestamp = stbuf.st_mtime;
379 domain = WMReadPropListFromFile(path);
381 if (!domain)
382 domain = WMCreatePLDictionary(NULL, NULL);
384 defaults->path = wstrdup(path);
386 defaults->appDomain = domain;
388 if (domain)
389 WMPutInPLDictionary(defaults->defaults, key, domain);
391 /* terminate list */
392 defaults->searchList[1] = NULL;
394 defaults->searchListArray = WMCreatePLArray(NULL, NULL);
396 i = 0;
397 while (defaults->searchList[i]) {
398 WMAddToPLArray(defaults->searchListArray, defaults->searchList[i]);
399 i++;
402 if (sharedUserDefaults)
403 defaults->next = sharedUserDefaults;
404 sharedUserDefaults = defaults;
406 #ifndef HAVE_INOTIFY
407 addSynchronizeTimerHandler();
408 #endif
409 registerSaveOnExit();
411 return defaults;
414 /* Returns a WMPropList array with all keys in the user defaults database.
415 * Free the array with WMReleasePropList() when no longer needed,
416 * but do not free the elements of the array! They're just references. */
417 WMPropList *WMGetUDKeys(WMUserDefaults * database)
419 return WMGetPLDictionaryKeys(database->appDomain);
422 WMPropList *WMGetUDObjectForKey(WMUserDefaults * database, char *defaultName)
424 WMPropList *domainName, *domain;
425 WMPropList *object = NULL;
426 WMPropList *key = WMCreatePLString(defaultName);
427 int i = 0;
429 while (database->searchList[i] && !object) {
430 domainName = database->searchList[i];
431 domain = WMGetFromPLDictionary(database->defaults, domainName);
432 if (domain) {
433 object = WMGetFromPLDictionary(domain, key);
435 i++;
437 WMReleasePropList(key);
439 return object;
442 void WMSetUDObjectForKey(WMUserDefaults * database, WMPropList * object, char *defaultName)
444 WMPropList *key = WMCreatePLString(defaultName);
446 database->dirty = 1;
448 WMPutInPLDictionary(database->appDomain, key, object);
449 WMReleasePropList(key);
452 void WMRemoveUDObjectForKey(WMUserDefaults * database, char *defaultName)
454 WMPropList *key = WMCreatePLString(defaultName);
456 database->dirty = 1;
458 WMRemoveFromPLDictionary(database->appDomain, key);
460 WMReleasePropList(key);
463 char *WMGetUDStringForKey(WMUserDefaults * database, char *defaultName)
465 WMPropList *val;
467 val = WMGetUDObjectForKey(database, defaultName);
469 if (!val)
470 return NULL;
472 if (!WMIsPLString(val))
473 return NULL;
475 return WMGetFromPLString(val);
478 int WMGetUDIntegerForKey(WMUserDefaults * database, char *defaultName)
480 WMPropList *val;
481 char *str;
482 int value;
484 val = WMGetUDObjectForKey(database, defaultName);
486 if (!val)
487 return 0;
489 if (!WMIsPLString(val))
490 return 0;
492 str = WMGetFromPLString(val);
493 if (!str)
494 return 0;
496 if (sscanf(str, "%i", &value) != 1)
497 return 0;
499 return value;
502 float WMGetUDFloatForKey(WMUserDefaults * database, char *defaultName)
504 WMPropList *val;
505 char *str;
506 float value;
508 val = WMGetUDObjectForKey(database, defaultName);
510 if (!val || !WMIsPLString(val))
511 return 0.0;
513 if (!(str = WMGetFromPLString(val)))
514 return 0.0;
516 if (sscanf(str, "%f", &value) != 1)
517 return 0.0;
519 return value;
522 Bool WMGetUDBoolForKey(WMUserDefaults * database, char *defaultName)
524 WMPropList *val;
525 int value;
526 char *str;
528 val = WMGetUDObjectForKey(database, defaultName);
530 if (!val)
531 return False;
533 if (!WMIsPLString(val))
534 return False;
536 str = WMGetFromPLString(val);
537 if (!str)
538 return False;
540 if (sscanf(str, "%i", &value) == 1 && value != 0)
541 return True;
543 if (strcasecmp(str, "YES") == 0)
544 return True;
546 if (strcasecmp(str, "Y") == 0)
547 return True;
549 return False;
552 void WMSetUDIntegerForKey(WMUserDefaults * database, int value, char *defaultName)
554 WMPropList *object;
555 char buffer[128];
557 sprintf(buffer, "%i", value);
558 object = WMCreatePLString(buffer);
560 WMSetUDObjectForKey(database, object, defaultName);
561 WMReleasePropList(object);
564 void WMSetUDStringForKey(WMUserDefaults * database, char *value, char *defaultName)
566 WMPropList *object;
568 object = WMCreatePLString(value);
570 WMSetUDObjectForKey(database, object, defaultName);
571 WMReleasePropList(object);
574 void WMSetUDFloatForKey(WMUserDefaults * database, float value, char *defaultName)
576 WMPropList *object;
577 char buffer[128];
579 sprintf(buffer, "%f", value);
580 object = WMCreatePLString(buffer);
582 WMSetUDObjectForKey(database, object, defaultName);
583 WMReleasePropList(object);
586 void WMSetUDBoolForKey(WMUserDefaults * database, Bool value, char *defaultName)
588 static WMPropList *yes = NULL, *no = NULL;
590 if (!yes) {
591 yes = WMCreatePLString("YES");
592 no = WMCreatePLString("NO");
595 WMSetUDObjectForKey(database, value ? yes : no, defaultName);
598 WMPropList *WMGetUDSearchList(WMUserDefaults * database)
600 return database->searchListArray;
603 void WMSetUDSearchList(WMUserDefaults * database, WMPropList * list)
605 int i, c;
607 if (database->searchList) {
608 i = 0;
609 while (database->searchList[i]) {
610 WMReleasePropList(database->searchList[i]);
611 i++;
613 wfree(database->searchList);
615 if (database->searchListArray) {
616 WMReleasePropList(database->searchListArray);
619 c = WMGetPropListItemCount(list);
620 database->searchList = wmalloc(sizeof(WMPropList *) * (c + 1));
622 for (i = 0; i < c; i++) {
623 database->searchList[i] = WMGetFromPLArray(list, i);
625 database->searchList[c] = NULL;
627 database->searchListArray = WMDeepCopyPropList(list);