doc: Update getstyle and setstyle manpages.
[wmaker-crm.git] / WINGs / userdefaults.c
blob6b55e8cf91f8fcafb0a2bf75b18a1ec5e7299abe
2 #include <stdlib.h>
3 #include <string.h>
4 #include <strings.h>
5 #include <stdio.h>
6 #include <assert.h>
7 #include <unistd.h>
8 #include <sys/stat.h>
10 #include "wconfig.h"
12 #include "WINGs.h"
13 #include "WINGsP.h"
14 #include "userdefaults.h"
17 typedef struct W_UserDefaults {
18 WMPropList *defaults;
20 WMPropList *appDomain;
22 WMPropList *searchListArray;
23 WMPropList **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;
37 static UserDefaults *sharedUserDefaults = NULL;
39 char *WMUserDefaultsDidChangeNotification = "WMUserDefaultsDidChangeNotification";
41 static void synchronizeUserDefaults(void *foo);
43 #define DEFAULTS_DIR "/Defaults"
44 #ifndef HAVE_INOTIFY
45 /* Check defaults database for changes every this many milliseconds */
46 /* XXX: this is shared with src/ stuff, put it in some common header */
47 #define UD_SYNC_INTERVAL 2000
48 #endif
50 const char *wusergnusteppath()
52 static const char subdir[] = "/GNUstep";
53 static char *path = NULL;
54 char *gspath, *h;
55 int pathlen;
57 if (path)
58 /* Value have been already computed, re-use it */
59 return path;
61 gspath = getenv("GNUSTEP_USER_ROOT");
62 if (gspath) {
63 gspath = wexpandpath(gspath);
64 if (gspath) {
65 path = gspath;
66 return path;
68 wwarning(_("variable GNUSTEP_USER_ROOT defined with invalid path, not used"));
71 h = wgethomedir();
72 if (!h)
73 return NULL;
75 pathlen = strlen(h);
76 path = wmalloc(pathlen + sizeof(subdir));
77 strcpy(path, h);
78 strcpy(path + pathlen, subdir);
80 return path;
83 char *wdefaultspathfordomain(const char *domain)
85 char *path;
86 const char *gspath;
87 size_t slen;
89 gspath = wusergnusteppath();
90 slen = strlen(gspath) + strlen(DEFAULTS_DIR) + strlen(domain) + 4;
91 path = wmalloc(slen);
93 strcpy(path, gspath);
94 strcat(path, DEFAULTS_DIR);
95 strcat(path, "/");
96 strcat(path, domain);
98 return path;
101 /* XXX: doesn't quite belong to *user*defaults.c */
102 #ifndef GLOBAL_DEFAULTS_SUBDIR
103 #define GLOBAL_DEFAULTS_SUBDIR "WindowMaker"
104 #endif
105 char *wglobaldefaultspathfordomain(const char *domain)
107 char *t = NULL;
108 size_t len;
110 len = strlen( SYSCONFDIR ) + strlen( GLOBAL_DEFAULTS_SUBDIR ) + strlen(domain) + 3;
111 t = wmalloc(len);
112 snprintf(t, len, "%s/%s/%s", SYSCONFDIR, GLOBAL_DEFAULTS_SUBDIR, domain);
114 return t;
117 void w_save_defaults_changes(void)
119 if (WMApplication.applicationName == NULL) {
121 * This means that the user has properly exited by calling the
122 * function 'WMReleaseApplication' (which has already called us)
123 * but we're being called again by the fallback 'atexit' method
124 * (the legacy way of saving changes on exit which is kept for
125 * application that would forget to call 'WMReleaseApplication')
127 return;
130 /* save the user defaults databases */
131 synchronizeUserDefaults(NULL);
134 /* set to save changes in defaults when program is exited */
135 static void registerSaveOnExit(void)
137 static Bool registeredSaveOnExit = False;
139 if (!registeredSaveOnExit) {
140 atexit(w_save_defaults_changes);
141 registeredSaveOnExit = True;
145 static void synchronizeUserDefaults(void *foo)
147 UserDefaults *database = sharedUserDefaults;
149 /* Parameter not used, but tell the compiler that it is ok */
150 (void) foo;
152 while (database) {
153 if (!database->dontSync)
154 WMSynchronizeUserDefaults(database);
155 database = database->next;
159 #ifndef HAVE_INOTIFY
160 static void addSynchronizeTimerHandler(void)
162 static Bool initialized = False;
164 if (!initialized) {
165 WMAddPersistentTimerHandler(UD_SYNC_INTERVAL,
166 synchronizeUserDefaults, NULL);
167 initialized = True;
170 #endif
172 void WMEnableUDPeriodicSynchronization(WMUserDefaults * database, Bool enable)
174 database->dontSync = !enable;
177 void WMSynchronizeUserDefaults(WMUserDefaults * database)
179 Bool fileIsNewer = False, release = False, notify = False;
180 WMPropList *plF, *key;
181 char *path;
182 struct stat stbuf;
184 if (!database->path) {
185 path = wdefaultspathfordomain(WMGetApplicationName());
186 release = True;
187 } else {
188 path = database->path;
191 if (stat(path, &stbuf) >= 0 && stbuf.st_mtime > database->timestamp)
192 fileIsNewer = True;
194 if (database->appDomain && (database->dirty || fileIsNewer)) {
195 if (database->dirty && fileIsNewer) {
196 plF = WMReadPropListFromFile(path);
197 if (plF) {
198 plF = WMMergePLDictionaries(plF, database->appDomain, False);
199 WMReleasePropList(database->appDomain);
200 database->appDomain = plF;
201 key = database->searchList[0];
202 WMPutInPLDictionary(database->defaults, key, plF);
203 notify = True;
204 } else {
205 /* something happened with the file. just overwrite it */
206 wwarning(_("cannot read domain from file '%s' when syncing"), path);
207 WMWritePropListToFile(database->appDomain, path);
209 } else if (database->dirty) {
210 WMWritePropListToFile(database->appDomain, path);
211 } else if (fileIsNewer) {
212 plF = WMReadPropListFromFile(path);
213 if (plF) {
214 WMReleasePropList(database->appDomain);
215 database->appDomain = plF;
216 key = database->searchList[0];
217 WMPutInPLDictionary(database->defaults, key, plF);
218 notify = True;
219 } else {
220 /* something happened with the file. just overwrite it */
221 wwarning(_("cannot read domain from file '%s' when syncing"), path);
222 WMWritePropListToFile(database->appDomain, path);
226 database->dirty = 0;
228 if (stat(path, &stbuf) >= 0)
229 database->timestamp = stbuf.st_mtime;
231 if (notify) {
232 WMPostNotificationName(WMUserDefaultsDidChangeNotification, database, NULL);
236 if (release)
237 wfree(path);
241 void WMSaveUserDefaults(WMUserDefaults * database)
243 if (database->appDomain) {
244 struct stat stbuf;
245 char *path;
246 Bool release = False;
248 if (!database->path) {
249 path = wdefaultspathfordomain(WMGetApplicationName());
250 release = True;
251 } else {
252 path = database->path;
254 WMWritePropListToFile(database->appDomain, path);
255 database->dirty = 0;
256 if (stat(path, &stbuf) >= 0)
257 database->timestamp = stbuf.st_mtime;
258 if (release)
259 wfree(path);
263 WMUserDefaults *WMGetStandardUserDefaults(void)
265 WMUserDefaults *defaults;
266 WMPropList *domain;
267 WMPropList *key;
268 struct stat stbuf;
269 char *path;
270 int i;
272 if (sharedUserDefaults) {
273 defaults = sharedUserDefaults;
274 while (defaults) {
275 /* path == NULL only for StandardUserDefaults db */
276 if (defaults->path == NULL)
277 return defaults;
278 defaults = defaults->next;
282 /* we didn't found the database we are looking for. Go read it. XXX: wtf? */
283 defaults = wmalloc(sizeof(WMUserDefaults));
284 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
285 defaults->searchList = wmalloc(sizeof(WMPropList *) * 3);
287 /* application domain */
288 key = WMCreatePLString(WMGetApplicationName());
289 defaults->searchList[0] = key;
291 /* temporary kluge. wmaker handles synchronization itself */
292 if (strcmp(WMGetApplicationName(), "WindowMaker") == 0) {
293 defaults->dontSync = 1;
296 path = wdefaultspathfordomain(WMGetFromPLString(key));
298 if (stat(path, &stbuf) >= 0)
299 defaults->timestamp = stbuf.st_mtime;
301 domain = WMReadPropListFromFile(path);
303 if (!domain)
304 domain = WMCreatePLDictionary(NULL, NULL);
306 if (path)
307 wfree(path);
309 defaults->appDomain = domain;
311 if (domain)
312 WMPutInPLDictionary(defaults->defaults, key, domain);
314 /* global domain */
315 key = WMCreatePLString("WMGLOBAL");
316 defaults->searchList[1] = key;
318 path = wdefaultspathfordomain(WMGetFromPLString(key));
320 domain = WMReadPropListFromFile(path);
322 wfree(path);
324 if (!domain)
325 domain = WMCreatePLDictionary(NULL, NULL);
327 if (domain)
328 WMPutInPLDictionary(defaults->defaults, key, domain);
330 /* terminate list */
331 defaults->searchList[2] = NULL;
333 defaults->searchListArray = WMCreatePLArray(NULL, NULL);
335 i = 0;
336 while (defaults->searchList[i]) {
337 WMAddToPLArray(defaults->searchListArray, defaults->searchList[i]);
338 i++;
341 if (sharedUserDefaults)
342 defaults->next = sharedUserDefaults;
343 sharedUserDefaults = defaults;
345 #ifndef HAVE_INOTIFY
346 addSynchronizeTimerHandler();
347 #endif
348 registerSaveOnExit();
350 return defaults;
353 WMUserDefaults *WMGetDefaultsFromPath(const char *path)
355 WMUserDefaults *defaults;
356 WMPropList *domain;
357 WMPropList *key;
358 struct stat stbuf;
359 const char *name;
360 int i;
362 assert(path != NULL);
364 if (sharedUserDefaults) {
365 defaults = sharedUserDefaults;
366 while (defaults) {
367 if (defaults->path && strcmp(defaults->path, path) == 0)
368 return defaults;
369 defaults = defaults->next;
373 /* we didn't found the database we are looking for. Go read it. XXX wtf? */
374 defaults = wmalloc(sizeof(WMUserDefaults));
375 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
376 defaults->searchList = wmalloc(sizeof(WMPropList *) * 2);
378 /* the domain we want, go in the first position */
379 name = strrchr(path, '/');
380 if (!name)
381 name = path;
382 else
383 name++;
385 key = WMCreatePLString(name);
386 defaults->searchList[0] = key;
388 if (stat(path, &stbuf) >= 0)
389 defaults->timestamp = stbuf.st_mtime;
391 domain = WMReadPropListFromFile(path);
393 if (!domain)
394 domain = WMCreatePLDictionary(NULL, NULL);
396 defaults->path = wstrdup(path);
398 defaults->appDomain = domain;
400 if (domain)
401 WMPutInPLDictionary(defaults->defaults, key, domain);
403 /* terminate list */
404 defaults->searchList[1] = NULL;
406 defaults->searchListArray = WMCreatePLArray(NULL, NULL);
408 i = 0;
409 while (defaults->searchList[i]) {
410 WMAddToPLArray(defaults->searchListArray, defaults->searchList[i]);
411 i++;
414 if (sharedUserDefaults)
415 defaults->next = sharedUserDefaults;
416 sharedUserDefaults = defaults;
418 #ifndef HAVE_INOTIFY
419 addSynchronizeTimerHandler();
420 #endif
421 registerSaveOnExit();
423 return defaults;
426 /* Returns a WMPropList array with all keys in the user defaults database.
427 * Free the array with WMReleasePropList() when no longer needed,
428 * but do not free the elements of the array! They're just references. */
429 WMPropList *WMGetUDKeys(WMUserDefaults * database)
431 return WMGetPLDictionaryKeys(database->appDomain);
434 WMPropList *WMGetUDObjectForKey(WMUserDefaults * database, const char *defaultName)
436 WMPropList *domainName, *domain;
437 WMPropList *object = NULL;
438 WMPropList *key = WMCreatePLString(defaultName);
439 int i = 0;
441 while (database->searchList[i] && !object) {
442 domainName = database->searchList[i];
443 domain = WMGetFromPLDictionary(database->defaults, domainName);
444 if (domain) {
445 object = WMGetFromPLDictionary(domain, key);
447 i++;
449 WMReleasePropList(key);
451 return object;
454 void WMSetUDObjectForKey(WMUserDefaults * database, WMPropList * object, const char *defaultName)
456 WMPropList *key = WMCreatePLString(defaultName);
458 database->dirty = 1;
460 WMPutInPLDictionary(database->appDomain, key, object);
461 WMReleasePropList(key);
464 void WMRemoveUDObjectForKey(WMUserDefaults * database, const char *defaultName)
466 WMPropList *key = WMCreatePLString(defaultName);
468 database->dirty = 1;
470 WMRemoveFromPLDictionary(database->appDomain, key);
472 WMReleasePropList(key);
475 char *WMGetUDStringForKey(WMUserDefaults * database, const char *defaultName)
477 WMPropList *val;
479 val = WMGetUDObjectForKey(database, defaultName);
481 if (!val)
482 return NULL;
484 if (!WMIsPLString(val))
485 return NULL;
487 return WMGetFromPLString(val);
490 int WMGetUDIntegerForKey(WMUserDefaults * database, const char *defaultName)
492 WMPropList *val;
493 char *str;
494 int value;
496 val = WMGetUDObjectForKey(database, defaultName);
498 if (!val)
499 return 0;
501 if (!WMIsPLString(val))
502 return 0;
504 str = WMGetFromPLString(val);
505 if (!str)
506 return 0;
508 if (sscanf(str, "%i", &value) != 1)
509 return 0;
511 return value;
514 float WMGetUDFloatForKey(WMUserDefaults * database, const char *defaultName)
516 WMPropList *val;
517 char *str;
518 float value;
520 val = WMGetUDObjectForKey(database, defaultName);
522 if (!val || !WMIsPLString(val))
523 return 0.0;
525 if (!(str = WMGetFromPLString(val)))
526 return 0.0;
528 if (sscanf(str, "%f", &value) != 1)
529 return 0.0;
531 return value;
534 Bool WMGetUDBoolForKey(WMUserDefaults * database, const char *defaultName)
536 WMPropList *val;
537 int value;
538 char *str;
540 val = WMGetUDObjectForKey(database, defaultName);
542 if (!val)
543 return False;
545 if (!WMIsPLString(val))
546 return False;
548 str = WMGetFromPLString(val);
549 if (!str)
550 return False;
552 if (sscanf(str, "%i", &value) == 1 && value != 0)
553 return True;
555 if (strcasecmp(str, "YES") == 0)
556 return True;
558 if (strcasecmp(str, "Y") == 0)
559 return True;
561 return False;
564 void WMSetUDIntegerForKey(WMUserDefaults * database, int value, const char *defaultName)
566 WMPropList *object;
567 char buffer[128];
569 sprintf(buffer, "%i", value);
570 object = WMCreatePLString(buffer);
572 WMSetUDObjectForKey(database, object, defaultName);
573 WMReleasePropList(object);
576 void WMSetUDStringForKey(WMUserDefaults * database, const char *value, const char *defaultName)
578 WMPropList *object;
580 object = WMCreatePLString(value);
582 WMSetUDObjectForKey(database, object, defaultName);
583 WMReleasePropList(object);
586 void WMSetUDFloatForKey(WMUserDefaults * database, float value, const char *defaultName)
588 WMPropList *object;
589 char buffer[128];
591 sprintf(buffer, "%f", value);
592 object = WMCreatePLString(buffer);
594 WMSetUDObjectForKey(database, object, defaultName);
595 WMReleasePropList(object);
598 void WMSetUDBoolForKey(WMUserDefaults * database, Bool value, const char *defaultName)
600 static WMPropList *yes = NULL, *no = NULL;
602 if (!yes) {
603 yes = WMCreatePLString("YES");
604 no = WMCreatePLString("NO");
607 WMSetUDObjectForKey(database, value ? yes : no, defaultName);
610 WMPropList *WMGetUDSearchList(WMUserDefaults * database)
612 return database->searchListArray;
615 void WMSetUDSearchList(WMUserDefaults * database, WMPropList * list)
617 int i, c;
619 if (database->searchList) {
620 i = 0;
621 while (database->searchList[i]) {
622 WMReleasePropList(database->searchList[i]);
623 i++;
625 wfree(database->searchList);
627 if (database->searchListArray) {
628 WMReleasePropList(database->searchListArray);
631 c = WMGetPropListItemCount(list);
632 database->searchList = wmalloc(sizeof(WMPropList *) * (c + 1));
634 for (i = 0; i < c; i++) {
635 database->searchList[i] = WMGetFromPLArray(list, i);
637 database->searchList[c] = NULL;
639 database->searchListArray = WMDeepCopyPropList(list);