wmgenmenu: Add French and Spanish translations
[wmaker-crm.git] / WINGs / userdefaults.c
blob4eaed8245b92c597b55df4fd554d4f04b8a08040
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 gspath = getenv("GNUSTEP_USER_ROOT");
55 if (gspath) {
56 gspath = wexpandpath(gspath);
57 if (gspath) {
58 pathlen = strlen(gspath) + 4;
59 path = wmalloc(pathlen);
60 if (wstrlcpy(path, gspath, pathlen) >= pathlen) {
61 wfree(gspath);
62 return NULL;
64 wfree(gspath);
66 } else {
67 char *h = wgethomedir();
68 if (!h)
69 return NULL;
70 pathlen = strlen(h) + 8 /* /GNUstep */ + 1;
71 path = wmalloc(pathlen);
72 if (wstrlcpy(path, h, pathlen) >= pathlen ||
73 wstrlcat(path, "/GNUstep", pathlen) >= pathlen) {
74 wfree(path);
75 return NULL;
79 return path;
82 char *wdefaultspathfordomain(char *domain)
84 char *path;
85 char *gspath;
86 size_t slen;
88 gspath = wusergnusteppath();
89 slen = strlen(gspath) + strlen(DEFAULTS_DIR) + strlen(domain) + 4;
90 path = wmalloc(slen);
92 if (wstrlcpy(path, gspath, slen) >= slen ||
93 wstrlcat(path, DEFAULTS_DIR, slen) >= slen ||
94 wstrlcat(path, "/", slen) >= slen ||
95 wstrlcat(path, domain, slen) >= slen) {
96 wfree(path);
97 return NULL;
100 return path;
103 /* XXX: doesn't quite belong to *user*defaults.c */
104 #ifndef GLOBAL_DEFAULTS_SUBDIR
105 #define GLOBAL_DEFAULTS_SUBDIR "WindowMaker"
106 #endif
107 char *wglobaldefaultspathfordomain(const char *domain)
109 char *t = NULL;
110 size_t len;
112 len = strlen( SYSCONFDIR ) + strlen( GLOBAL_DEFAULTS_SUBDIR ) + strlen(domain) + 3;
113 t = wmalloc(len);
114 snprintf(t, len, "%s/%s/%s", SYSCONFDIR, GLOBAL_DEFAULTS_SUBDIR, domain);
116 return t;
119 static void
120 saveDefaultsChanges(void)
122 /* save the user defaults databases */
123 synchronizeUserDefaults(NULL);
126 /* set to save changes in defaults when program is exited */
127 static void registerSaveOnExit(void)
129 static Bool registeredSaveOnExit = False;
131 if (!registeredSaveOnExit) {
132 atexit(saveDefaultsChanges);
133 registeredSaveOnExit = True;
137 static void synchronizeUserDefaults(void *foo)
139 UserDefaults *database = sharedUserDefaults;
141 while (database) {
142 if (!database->dontSync)
143 WMSynchronizeUserDefaults(database);
144 database = database->next;
148 #ifndef HAVE_INOTIFY
149 static void addSynchronizeTimerHandler(void)
151 static Bool initialized = False;
153 if (!initialized) {
154 WMAddPersistentTimerHandler(UD_SYNC_INTERVAL,
155 synchronizeUserDefaults, NULL);
156 initialized = True;
159 #endif
161 void WMEnableUDPeriodicSynchronization(WMUserDefaults * database, Bool enable)
163 database->dontSync = !enable;
166 void WMSynchronizeUserDefaults(WMUserDefaults * database)
168 Bool fileIsNewer = False, release = False, notify = False;
169 WMPropList *plF, *key;
170 char *path;
171 struct stat stbuf;
173 if (!database->path) {
174 path = wdefaultspathfordomain(WMGetApplicationName());
175 release = True;
176 } else {
177 path = database->path;
180 if (stat(path, &stbuf) >= 0 && stbuf.st_mtime > database->timestamp)
181 fileIsNewer = True;
183 if (database->appDomain && (database->dirty || fileIsNewer)) {
184 if (database->dirty && fileIsNewer) {
185 plF = WMReadPropListFromFile(path);
186 if (plF) {
187 plF = WMMergePLDictionaries(plF, database->appDomain, False);
188 WMReleasePropList(database->appDomain);
189 database->appDomain = plF;
190 key = database->searchList[0];
191 WMPutInPLDictionary(database->defaults, key, plF);
192 notify = True;
193 } else {
194 /* something happened with the file. just overwrite it */
195 wwarning(_("cannot read domain from file '%s' when syncing"), path);
196 WMWritePropListToFile(database->appDomain, path);
198 } else if (database->dirty) {
199 WMWritePropListToFile(database->appDomain, path);
200 } else if (fileIsNewer) {
201 plF = WMReadPropListFromFile(path);
202 if (plF) {
203 WMReleasePropList(database->appDomain);
204 database->appDomain = plF;
205 key = database->searchList[0];
206 WMPutInPLDictionary(database->defaults, key, plF);
207 notify = True;
208 } else {
209 /* something happened with the file. just overwrite it */
210 wwarning(_("cannot read domain from file '%s' when syncing"), path);
211 WMWritePropListToFile(database->appDomain, path);
215 database->dirty = 0;
217 if (stat(path, &stbuf) >= 0)
218 database->timestamp = stbuf.st_mtime;
220 if (notify) {
221 WMPostNotificationName(WMUserDefaultsDidChangeNotification, database, NULL);
225 if (release)
226 wfree(path);
230 void WMSaveUserDefaults(WMUserDefaults * database)
232 if (database->appDomain) {
233 struct stat stbuf;
234 char *path;
235 Bool release = False;
237 if (!database->path) {
238 path = wdefaultspathfordomain(WMGetApplicationName());
239 release = True;
240 } else {
241 path = database->path;
243 WMWritePropListToFile(database->appDomain, path);
244 database->dirty = 0;
245 if (stat(path, &stbuf) >= 0)
246 database->timestamp = stbuf.st_mtime;
247 if (release)
248 wfree(path);
252 WMUserDefaults *WMGetStandardUserDefaults(void)
254 WMUserDefaults *defaults;
255 WMPropList *domain;
256 WMPropList *key;
257 struct stat stbuf;
258 char *path;
259 int i;
261 if (sharedUserDefaults) {
262 defaults = sharedUserDefaults;
263 while (defaults) {
264 /* path == NULL only for StandardUserDefaults db */
265 if (defaults->path == NULL)
266 return defaults;
267 defaults = defaults->next;
271 /* we didn't found the database we are looking for. Go read it. XXX: wtf? */
272 defaults = wmalloc(sizeof(WMUserDefaults));
273 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
274 defaults->searchList = wmalloc(sizeof(WMPropList *) * 3);
276 /* application domain */
277 key = WMCreatePLString(WMGetApplicationName());
278 defaults->searchList[0] = key;
280 /* temporary kluge. wmaker handles synchronization itself */
281 if (strcmp(WMGetApplicationName(), "WindowMaker") == 0) {
282 defaults->dontSync = 1;
285 path = wdefaultspathfordomain(WMGetFromPLString(key));
287 if (stat(path, &stbuf) >= 0)
288 defaults->timestamp = stbuf.st_mtime;
290 domain = WMReadPropListFromFile(path);
292 if (!domain)
293 domain = WMCreatePLDictionary(NULL, NULL);
295 if (path)
296 wfree(path);
298 defaults->appDomain = domain;
300 if (domain)
301 WMPutInPLDictionary(defaults->defaults, key, domain);
303 /* global domain */
304 key = WMCreatePLString("WMGLOBAL");
305 defaults->searchList[1] = key;
307 path = wdefaultspathfordomain(WMGetFromPLString(key));
309 domain = WMReadPropListFromFile(path);
311 wfree(path);
313 if (!domain)
314 domain = WMCreatePLDictionary(NULL, NULL);
316 if (domain)
317 WMPutInPLDictionary(defaults->defaults, key, domain);
319 /* terminate list */
320 defaults->searchList[2] = NULL;
322 defaults->searchListArray = WMCreatePLArray(NULL, NULL);
324 i = 0;
325 while (defaults->searchList[i]) {
326 WMAddToPLArray(defaults->searchListArray, defaults->searchList[i]);
327 i++;
330 if (sharedUserDefaults)
331 defaults->next = sharedUserDefaults;
332 sharedUserDefaults = defaults;
334 #ifndef HAVE_INOTIFY
335 addSynchronizeTimerHandler();
336 #endif
337 registerSaveOnExit();
339 return defaults;
342 WMUserDefaults *WMGetDefaultsFromPath(char *path)
344 WMUserDefaults *defaults;
345 WMPropList *domain;
346 WMPropList *key;
347 struct stat stbuf;
348 char *name;
349 int i;
351 assert(path != NULL);
353 if (sharedUserDefaults) {
354 defaults = sharedUserDefaults;
355 while (defaults) {
356 if (defaults->path && strcmp(defaults->path, path) == 0)
357 return defaults;
358 defaults = defaults->next;
362 /* we didn't found the database we are looking for. Go read it. XXX wtf? */
363 defaults = wmalloc(sizeof(WMUserDefaults));
364 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
365 defaults->searchList = wmalloc(sizeof(WMPropList *) * 2);
367 /* the domain we want, go in the first position */
368 name = strrchr(path, '/');
369 if (!name)
370 name = path;
371 else
372 name++;
374 key = WMCreatePLString(name);
375 defaults->searchList[0] = key;
377 if (stat(path, &stbuf) >= 0)
378 defaults->timestamp = stbuf.st_mtime;
380 domain = WMReadPropListFromFile(path);
382 if (!domain)
383 domain = WMCreatePLDictionary(NULL, NULL);
385 defaults->path = wstrdup(path);
387 defaults->appDomain = domain;
389 if (domain)
390 WMPutInPLDictionary(defaults->defaults, key, domain);
392 /* terminate list */
393 defaults->searchList[1] = NULL;
395 defaults->searchListArray = WMCreatePLArray(NULL, NULL);
397 i = 0;
398 while (defaults->searchList[i]) {
399 WMAddToPLArray(defaults->searchListArray, defaults->searchList[i]);
400 i++;
403 if (sharedUserDefaults)
404 defaults->next = sharedUserDefaults;
405 sharedUserDefaults = defaults;
407 #ifndef HAVE_INOTIFY
408 addSynchronizeTimerHandler();
409 #endif
410 registerSaveOnExit();
412 return defaults;
415 /* Returns a WMPropList array with all keys in the user defaults database.
416 * Free the array with WMReleasePropList() when no longer needed,
417 * but do not free the elements of the array! They're just references. */
418 WMPropList *WMGetUDKeys(WMUserDefaults * database)
420 return WMGetPLDictionaryKeys(database->appDomain);
423 WMPropList *WMGetUDObjectForKey(WMUserDefaults * database, char *defaultName)
425 WMPropList *domainName, *domain;
426 WMPropList *object = NULL;
427 WMPropList *key = WMCreatePLString(defaultName);
428 int i = 0;
430 while (database->searchList[i] && !object) {
431 domainName = database->searchList[i];
432 domain = WMGetFromPLDictionary(database->defaults, domainName);
433 if (domain) {
434 object = WMGetFromPLDictionary(domain, key);
436 i++;
438 WMReleasePropList(key);
440 return object;
443 void WMSetUDObjectForKey(WMUserDefaults * database, WMPropList * object, char *defaultName)
445 WMPropList *key = WMCreatePLString(defaultName);
447 database->dirty = 1;
449 WMPutInPLDictionary(database->appDomain, key, object);
450 WMReleasePropList(key);
453 void WMRemoveUDObjectForKey(WMUserDefaults * database, char *defaultName)
455 WMPropList *key = WMCreatePLString(defaultName);
457 database->dirty = 1;
459 WMRemoveFromPLDictionary(database->appDomain, key);
461 WMReleasePropList(key);
464 char *WMGetUDStringForKey(WMUserDefaults * database, char *defaultName)
466 WMPropList *val;
468 val = WMGetUDObjectForKey(database, defaultName);
470 if (!val)
471 return NULL;
473 if (!WMIsPLString(val))
474 return NULL;
476 return WMGetFromPLString(val);
479 int WMGetUDIntegerForKey(WMUserDefaults * database, char *defaultName)
481 WMPropList *val;
482 char *str;
483 int value;
485 val = WMGetUDObjectForKey(database, defaultName);
487 if (!val)
488 return 0;
490 if (!WMIsPLString(val))
491 return 0;
493 str = WMGetFromPLString(val);
494 if (!str)
495 return 0;
497 if (sscanf(str, "%i", &value) != 1)
498 return 0;
500 return value;
503 float WMGetUDFloatForKey(WMUserDefaults * database, char *defaultName)
505 WMPropList *val;
506 char *str;
507 float value;
509 val = WMGetUDObjectForKey(database, defaultName);
511 if (!val || !WMIsPLString(val))
512 return 0.0;
514 if (!(str = WMGetFromPLString(val)))
515 return 0.0;
517 if (sscanf(str, "%f", &value) != 1)
518 return 0.0;
520 return value;
523 Bool WMGetUDBoolForKey(WMUserDefaults * database, char *defaultName)
525 WMPropList *val;
526 int value;
527 char *str;
529 val = WMGetUDObjectForKey(database, defaultName);
531 if (!val)
532 return False;
534 if (!WMIsPLString(val))
535 return False;
537 str = WMGetFromPLString(val);
538 if (!str)
539 return False;
541 if (sscanf(str, "%i", &value) == 1 && value != 0)
542 return True;
544 if (strcasecmp(str, "YES") == 0)
545 return True;
547 if (strcasecmp(str, "Y") == 0)
548 return True;
550 return False;
553 void WMSetUDIntegerForKey(WMUserDefaults * database, int value, char *defaultName)
555 WMPropList *object;
556 char buffer[128];
558 sprintf(buffer, "%i", value);
559 object = WMCreatePLString(buffer);
561 WMSetUDObjectForKey(database, object, defaultName);
562 WMReleasePropList(object);
565 void WMSetUDStringForKey(WMUserDefaults * database, char *value, char *defaultName)
567 WMPropList *object;
569 object = WMCreatePLString(value);
571 WMSetUDObjectForKey(database, object, defaultName);
572 WMReleasePropList(object);
575 void WMSetUDFloatForKey(WMUserDefaults * database, float value, char *defaultName)
577 WMPropList *object;
578 char buffer[128];
580 sprintf(buffer, "%f", value);
581 object = WMCreatePLString(buffer);
583 WMSetUDObjectForKey(database, object, defaultName);
584 WMReleasePropList(object);
587 void WMSetUDBoolForKey(WMUserDefaults * database, Bool value, char *defaultName)
589 static WMPropList *yes = NULL, *no = NULL;
591 if (!yes) {
592 yes = WMCreatePLString("YES");
593 no = WMCreatePLString("NO");
596 WMSetUDObjectForKey(database, value ? yes : no, defaultName);
599 WMPropList *WMGetUDSearchList(WMUserDefaults * database)
601 return database->searchListArray;
604 void WMSetUDSearchList(WMUserDefaults * database, WMPropList * list)
606 int i, c;
608 if (database->searchList) {
609 i = 0;
610 while (database->searchList[i]) {
611 WMReleasePropList(database->searchList[i]);
612 i++;
614 wfree(database->searchList);
616 if (database->searchListArray) {
617 WMReleasePropList(database->searchListArray);
620 c = WMGetPropListItemCount(list);
621 database->searchList = wmalloc(sizeof(WMPropList *) * (c + 1));
623 for (i = 0; i < c; i++) {
624 database->searchList[i] = WMGetFromPLArray(list, i);
626 database->searchList[c] = NULL;
628 database->searchListArray = WMDeepCopyPropList(list);