wmaker: Changed math on floating point by integer operation
[wmaker-crm.git] / WINGs / userdefaults.c
blob2947331329bef2cb362f518c14657462de1b360f
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"
14 typedef struct W_UserDefaults {
15 WMPropList *defaults;
17 WMPropList *appDomain;
19 WMPropList *searchListArray;
20 WMPropList **searchList; /* cache for searchListArray */
22 char dirty;
24 char dontSync;
26 char *path; /* where is db located */
28 time_t timestamp; /* last modification time */
30 struct W_UserDefaults *next;
32 } UserDefaults;
34 static UserDefaults *sharedUserDefaults = NULL;
36 char *WMUserDefaultsDidChangeNotification = "WMUserDefaultsDidChangeNotification";
38 static void synchronizeUserDefaults(void *foo);
40 #define DEFAULTS_DIR "/Defaults"
41 #ifndef HAVE_INOTIFY
42 /* Check defaults database for changes every this many milliseconds */
43 /* XXX: this is shared with src/ stuff, put it in some common header */
44 #define UD_SYNC_INTERVAL 2000
45 #endif
47 const char *wusergnusteppath()
49 static const char subdir[] = "/GNUstep";
50 static char *path = NULL;
51 char *gspath, *h;
52 int pathlen;
54 if (path)
55 /* Value have been already computed, re-use it */
56 return path;
58 gspath = getenv("GNUSTEP_USER_ROOT");
59 if (gspath) {
60 gspath = wexpandpath(gspath);
61 if (gspath) {
62 path = gspath;
63 return path;
65 wwarning(_("variable GNUSTEP_USER_ROOT defined with invalid path, not used"));
68 h = wgethomedir();
69 if (!h)
70 return NULL;
72 pathlen = strlen(h);
73 path = wmalloc(pathlen + sizeof(subdir));
74 strcpy(path, h);
75 strcpy(path + pathlen, subdir);
77 return path;
80 char *wdefaultspathfordomain(const char *domain)
82 char *path;
83 const char *gspath;
84 size_t slen;
86 gspath = wusergnusteppath();
87 slen = strlen(gspath) + strlen(DEFAULTS_DIR) + strlen(domain) + 4;
88 path = wmalloc(slen);
90 if (wstrlcpy(path, gspath, slen) >= slen ||
91 wstrlcat(path, DEFAULTS_DIR, slen) >= slen ||
92 wstrlcat(path, "/", slen) >= slen ||
93 wstrlcat(path, domain, slen) >= slen) {
94 wfree(path);
95 return NULL;
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 static void
118 saveDefaultsChanges(void)
120 /* save the user defaults databases */
121 synchronizeUserDefaults(NULL);
124 /* set to save changes in defaults when program is exited */
125 static void registerSaveOnExit(void)
127 static Bool registeredSaveOnExit = False;
129 if (!registeredSaveOnExit) {
130 atexit(saveDefaultsChanges);
131 registeredSaveOnExit = True;
135 static void synchronizeUserDefaults(void *foo)
137 UserDefaults *database = sharedUserDefaults;
139 while (database) {
140 if (!database->dontSync)
141 WMSynchronizeUserDefaults(database);
142 database = database->next;
146 #ifndef HAVE_INOTIFY
147 static void addSynchronizeTimerHandler(void)
149 static Bool initialized = False;
151 if (!initialized) {
152 WMAddPersistentTimerHandler(UD_SYNC_INTERVAL,
153 synchronizeUserDefaults, NULL);
154 initialized = True;
157 #endif
159 void WMEnableUDPeriodicSynchronization(WMUserDefaults * database, Bool enable)
161 database->dontSync = !enable;
164 void WMSynchronizeUserDefaults(WMUserDefaults * database)
166 Bool fileIsNewer = False, release = False, notify = False;
167 WMPropList *plF, *key;
168 char *path;
169 struct stat stbuf;
171 if (!database->path) {
172 path = wdefaultspathfordomain(WMGetApplicationName());
173 release = True;
174 } else {
175 path = database->path;
178 if (stat(path, &stbuf) >= 0 && stbuf.st_mtime > database->timestamp)
179 fileIsNewer = True;
181 if (database->appDomain && (database->dirty || fileIsNewer)) {
182 if (database->dirty && fileIsNewer) {
183 plF = WMReadPropListFromFile(path);
184 if (plF) {
185 plF = WMMergePLDictionaries(plF, database->appDomain, False);
186 WMReleasePropList(database->appDomain);
187 database->appDomain = plF;
188 key = database->searchList[0];
189 WMPutInPLDictionary(database->defaults, key, plF);
190 notify = True;
191 } else {
192 /* something happened with the file. just overwrite it */
193 wwarning(_("cannot read domain from file '%s' when syncing"), path);
194 WMWritePropListToFile(database->appDomain, path);
196 } else if (database->dirty) {
197 WMWritePropListToFile(database->appDomain, path);
198 } else if (fileIsNewer) {
199 plF = WMReadPropListFromFile(path);
200 if (plF) {
201 WMReleasePropList(database->appDomain);
202 database->appDomain = plF;
203 key = database->searchList[0];
204 WMPutInPLDictionary(database->defaults, key, plF);
205 notify = True;
206 } else {
207 /* something happened with the file. just overwrite it */
208 wwarning(_("cannot read domain from file '%s' when syncing"), path);
209 WMWritePropListToFile(database->appDomain, path);
213 database->dirty = 0;
215 if (stat(path, &stbuf) >= 0)
216 database->timestamp = stbuf.st_mtime;
218 if (notify) {
219 WMPostNotificationName(WMUserDefaultsDidChangeNotification, database, NULL);
223 if (release)
224 wfree(path);
228 void WMSaveUserDefaults(WMUserDefaults * database)
230 if (database->appDomain) {
231 struct stat stbuf;
232 char *path;
233 Bool release = False;
235 if (!database->path) {
236 path = wdefaultspathfordomain(WMGetApplicationName());
237 release = True;
238 } else {
239 path = database->path;
241 WMWritePropListToFile(database->appDomain, path);
242 database->dirty = 0;
243 if (stat(path, &stbuf) >= 0)
244 database->timestamp = stbuf.st_mtime;
245 if (release)
246 wfree(path);
250 WMUserDefaults *WMGetStandardUserDefaults(void)
252 WMUserDefaults *defaults;
253 WMPropList *domain;
254 WMPropList *key;
255 struct stat stbuf;
256 char *path;
257 int i;
259 if (sharedUserDefaults) {
260 defaults = sharedUserDefaults;
261 while (defaults) {
262 /* path == NULL only for StandardUserDefaults db */
263 if (defaults->path == NULL)
264 return defaults;
265 defaults = defaults->next;
269 /* we didn't found the database we are looking for. Go read it. XXX: wtf? */
270 defaults = wmalloc(sizeof(WMUserDefaults));
271 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
272 defaults->searchList = wmalloc(sizeof(WMPropList *) * 3);
274 /* application domain */
275 key = WMCreatePLString(WMGetApplicationName());
276 defaults->searchList[0] = key;
278 /* temporary kluge. wmaker handles synchronization itself */
279 if (strcmp(WMGetApplicationName(), "WindowMaker") == 0) {
280 defaults->dontSync = 1;
283 path = wdefaultspathfordomain(WMGetFromPLString(key));
285 if (stat(path, &stbuf) >= 0)
286 defaults->timestamp = stbuf.st_mtime;
288 domain = WMReadPropListFromFile(path);
290 if (!domain)
291 domain = WMCreatePLDictionary(NULL, NULL);
293 if (path)
294 wfree(path);
296 defaults->appDomain = domain;
298 if (domain)
299 WMPutInPLDictionary(defaults->defaults, key, domain);
301 /* global domain */
302 key = WMCreatePLString("WMGLOBAL");
303 defaults->searchList[1] = key;
305 path = wdefaultspathfordomain(WMGetFromPLString(key));
307 domain = WMReadPropListFromFile(path);
309 wfree(path);
311 if (!domain)
312 domain = WMCreatePLDictionary(NULL, NULL);
314 if (domain)
315 WMPutInPLDictionary(defaults->defaults, key, domain);
317 /* terminate list */
318 defaults->searchList[2] = NULL;
320 defaults->searchListArray = WMCreatePLArray(NULL, NULL);
322 i = 0;
323 while (defaults->searchList[i]) {
324 WMAddToPLArray(defaults->searchListArray, defaults->searchList[i]);
325 i++;
328 if (sharedUserDefaults)
329 defaults->next = sharedUserDefaults;
330 sharedUserDefaults = defaults;
332 #ifndef HAVE_INOTIFY
333 addSynchronizeTimerHandler();
334 #endif
335 registerSaveOnExit();
337 return defaults;
340 WMUserDefaults *WMGetDefaultsFromPath(const char *path)
342 WMUserDefaults *defaults;
343 WMPropList *domain;
344 WMPropList *key;
345 struct stat stbuf;
346 const char *name;
347 int i;
349 assert(path != NULL);
351 if (sharedUserDefaults) {
352 defaults = sharedUserDefaults;
353 while (defaults) {
354 if (defaults->path && strcmp(defaults->path, path) == 0)
355 return defaults;
356 defaults = defaults->next;
360 /* we didn't found the database we are looking for. Go read it. XXX wtf? */
361 defaults = wmalloc(sizeof(WMUserDefaults));
362 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
363 defaults->searchList = wmalloc(sizeof(WMPropList *) * 2);
365 /* the domain we want, go in the first position */
366 name = strrchr(path, '/');
367 if (!name)
368 name = path;
369 else
370 name++;
372 key = WMCreatePLString(name);
373 defaults->searchList[0] = key;
375 if (stat(path, &stbuf) >= 0)
376 defaults->timestamp = stbuf.st_mtime;
378 domain = WMReadPropListFromFile(path);
380 if (!domain)
381 domain = WMCreatePLDictionary(NULL, NULL);
383 defaults->path = wstrdup(path);
385 defaults->appDomain = domain;
387 if (domain)
388 WMPutInPLDictionary(defaults->defaults, key, domain);
390 /* terminate list */
391 defaults->searchList[1] = NULL;
393 defaults->searchListArray = WMCreatePLArray(NULL, NULL);
395 i = 0;
396 while (defaults->searchList[i]) {
397 WMAddToPLArray(defaults->searchListArray, defaults->searchList[i]);
398 i++;
401 if (sharedUserDefaults)
402 defaults->next = sharedUserDefaults;
403 sharedUserDefaults = defaults;
405 #ifndef HAVE_INOTIFY
406 addSynchronizeTimerHandler();
407 #endif
408 registerSaveOnExit();
410 return defaults;
413 /* Returns a WMPropList array with all keys in the user defaults database.
414 * Free the array with WMReleasePropList() when no longer needed,
415 * but do not free the elements of the array! They're just references. */
416 WMPropList *WMGetUDKeys(WMUserDefaults * database)
418 return WMGetPLDictionaryKeys(database->appDomain);
421 WMPropList *WMGetUDObjectForKey(WMUserDefaults * database, const char *defaultName)
423 WMPropList *domainName, *domain;
424 WMPropList *object = NULL;
425 WMPropList *key = WMCreatePLString(defaultName);
426 int i = 0;
428 while (database->searchList[i] && !object) {
429 domainName = database->searchList[i];
430 domain = WMGetFromPLDictionary(database->defaults, domainName);
431 if (domain) {
432 object = WMGetFromPLDictionary(domain, key);
434 i++;
436 WMReleasePropList(key);
438 return object;
441 void WMSetUDObjectForKey(WMUserDefaults * database, WMPropList * object, const char *defaultName)
443 WMPropList *key = WMCreatePLString(defaultName);
445 database->dirty = 1;
447 WMPutInPLDictionary(database->appDomain, key, object);
448 WMReleasePropList(key);
451 void WMRemoveUDObjectForKey(WMUserDefaults * database, const char *defaultName)
453 WMPropList *key = WMCreatePLString(defaultName);
455 database->dirty = 1;
457 WMRemoveFromPLDictionary(database->appDomain, key);
459 WMReleasePropList(key);
462 char *WMGetUDStringForKey(WMUserDefaults * database, const char *defaultName)
464 WMPropList *val;
466 val = WMGetUDObjectForKey(database, defaultName);
468 if (!val)
469 return NULL;
471 if (!WMIsPLString(val))
472 return NULL;
474 return WMGetFromPLString(val);
477 int WMGetUDIntegerForKey(WMUserDefaults * database, const char *defaultName)
479 WMPropList *val;
480 char *str;
481 int value;
483 val = WMGetUDObjectForKey(database, defaultName);
485 if (!val)
486 return 0;
488 if (!WMIsPLString(val))
489 return 0;
491 str = WMGetFromPLString(val);
492 if (!str)
493 return 0;
495 if (sscanf(str, "%i", &value) != 1)
496 return 0;
498 return value;
501 float WMGetUDFloatForKey(WMUserDefaults * database, const char *defaultName)
503 WMPropList *val;
504 char *str;
505 float value;
507 val = WMGetUDObjectForKey(database, defaultName);
509 if (!val || !WMIsPLString(val))
510 return 0.0;
512 if (!(str = WMGetFromPLString(val)))
513 return 0.0;
515 if (sscanf(str, "%f", &value) != 1)
516 return 0.0;
518 return value;
521 Bool WMGetUDBoolForKey(WMUserDefaults * database, const char *defaultName)
523 WMPropList *val;
524 int value;
525 char *str;
527 val = WMGetUDObjectForKey(database, defaultName);
529 if (!val)
530 return False;
532 if (!WMIsPLString(val))
533 return False;
535 str = WMGetFromPLString(val);
536 if (!str)
537 return False;
539 if (sscanf(str, "%i", &value) == 1 && value != 0)
540 return True;
542 if (strcasecmp(str, "YES") == 0)
543 return True;
545 if (strcasecmp(str, "Y") == 0)
546 return True;
548 return False;
551 void WMSetUDIntegerForKey(WMUserDefaults * database, int value, const char *defaultName)
553 WMPropList *object;
554 char buffer[128];
556 sprintf(buffer, "%i", value);
557 object = WMCreatePLString(buffer);
559 WMSetUDObjectForKey(database, object, defaultName);
560 WMReleasePropList(object);
563 void WMSetUDStringForKey(WMUserDefaults * database, const char *value, const char *defaultName)
565 WMPropList *object;
567 object = WMCreatePLString(value);
569 WMSetUDObjectForKey(database, object, defaultName);
570 WMReleasePropList(object);
573 void WMSetUDFloatForKey(WMUserDefaults * database, float value, const char *defaultName)
575 WMPropList *object;
576 char buffer[128];
578 sprintf(buffer, "%f", value);
579 object = WMCreatePLString(buffer);
581 WMSetUDObjectForKey(database, object, defaultName);
582 WMReleasePropList(object);
585 void WMSetUDBoolForKey(WMUserDefaults * database, Bool value, const char *defaultName)
587 static WMPropList *yes = NULL, *no = NULL;
589 if (!yes) {
590 yes = WMCreatePLString("YES");
591 no = WMCreatePLString("NO");
594 WMSetUDObjectForKey(database, value ? yes : no, defaultName);
597 WMPropList *WMGetUDSearchList(WMUserDefaults * database)
599 return database->searchListArray;
602 void WMSetUDSearchList(WMUserDefaults * database, WMPropList * list)
604 int i, c;
606 if (database->searchList) {
607 i = 0;
608 while (database->searchList[i]) {
609 WMReleasePropList(database->searchList[i]);
610 i++;
612 wfree(database->searchList);
614 if (database->searchListArray) {
615 WMReleasePropList(database->searchListArray);
618 c = WMGetPropListItemCount(list);
619 database->searchList = wmalloc(sizeof(WMPropList *) * (c + 1));
621 for (i = 0; i < c; i++) {
622 database->searchList[i] = WMGetFromPLArray(list, i);
624 database->searchList[c] = NULL;
626 database->searchListArray = WMDeepCopyPropList(list);