Fix periodic focus bug
[wmaker-crm.git] / WINGs / userdefaults.c
blob479a30ee3d0b5d7ef37415fec07438b7b00dd39c
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 "wconfig.h"
12 #include "WINGs.h"
16 typedef struct W_UserDefaults {
17 WMPropList *defaults;
19 WMPropList *appDomain;
21 WMPropList *searchListArray;
22 WMPropList **searchList; /* cache for searchListArray */
24 char dirty;
26 char dontSync;
28 char *path; /* where is db located */
30 time_t timestamp; /* last modification time */
32 struct W_UserDefaults *next;
34 } UserDefaults;
37 static UserDefaults *sharedUserDefaults = NULL;
39 char *WMUserDefaultsDidChangeNotification = "WMUserDefaultsDidChangeNotification";
42 static void synchronizeUserDefaults(void *foo);
44 extern char *WMGetApplicationName();
46 #define DEFAULTS_DIR "/Defaults"
51 char*
52 wusergnusteppath()
54 static char *path = NULL;
55 char *gspath;
56 int pathlen;
58 if (!path) {
59 gspath = getenv("GNUSTEP_USER_ROOT");
60 if (gspath) {
61 gspath = wexpandpath(gspath);
62 pathlen = strlen(gspath) + 4;
63 path = wmalloc(pathlen);
64 strcpy(path, gspath);
65 wfree(gspath);
66 } else {
67 pathlen = strlen(wgethomedir()) + 10;
68 path = wmalloc(pathlen);
69 strcpy(path, wgethomedir());
70 strcat(path, "/GNUstep");
74 return path;
78 char*
79 wdefaultspathfordomain(char *domain)
81 char *path;
82 char *gspath;
84 gspath = wusergnusteppath();
85 path = wmalloc(strlen(gspath)+strlen(DEFAULTS_DIR)+strlen(domain)+4);
86 strcpy(path, gspath);
87 strcat(path, DEFAULTS_DIR);
88 strcat(path, "/");
89 strcat(path, domain);
91 return path;
95 static void
96 #ifdef HAVE_ATEXIT
97 saveDefaultsChanges(void)
98 #else
99 saveDefaultsChanges(int foo, void *bar)
100 #endif
102 /* save the user defaults databases */
103 synchronizeUserDefaults(NULL);
107 /* set to save changes in defaults when program is exited */
108 static void
109 registerSaveOnExit(void)
111 static Bool registeredSaveOnExit = False;
113 if (!registeredSaveOnExit) {
114 #ifdef HAVE_ATEXIT
115 atexit(saveDefaultsChanges);
116 #else
117 on_exit(saveDefaultsChanges, (void*)NULL);
118 #endif
119 registeredSaveOnExit = True;
124 static void
125 synchronizeUserDefaults(void *foo)
127 UserDefaults *database = sharedUserDefaults;
129 while (database) {
130 if (!database->dontSync)
131 WMSynchronizeUserDefaults(database);
132 database = database->next;
139 void
140 WMEnableUDPeriodicSynchronization(WMUserDefaults *database, Bool enable)
142 database->dontSync = !enable;
146 void
147 WMSynchronizeUserDefaults(WMUserDefaults *database)
149 Bool fileIsNewer = False, release = False, notify = False;
150 WMPropList *plF, *key;
151 char *path;
152 struct stat stbuf;
154 if (!database->path) {
155 path = wdefaultspathfordomain(WMGetApplicationName());
156 release = True;
157 } else {
158 path = database->path;
161 if (stat(path, &stbuf) >= 0 && stbuf.st_mtime > database->timestamp)
162 fileIsNewer = True;
164 if (database->appDomain && (database->dirty || fileIsNewer)) {
165 if (database->dirty && fileIsNewer) {
166 plF = WMReadPropListFromFile(path);
167 if (plF) {
168 plF = WMMergePLDictionaries(plF, database->appDomain, False);
169 WMReleasePropList(database->appDomain);
170 database->appDomain = plF;
171 key = database->searchList[0];
172 WMPutInPLDictionary(database->defaults, key, plF);
173 notify = True;
174 } else {
175 /* something happened with the file. just overwrite it */
176 wwarning(_("cannot read domain from file '%s' when syncing"),
177 path);
178 WMWritePropListToFile(database->appDomain, path, True);
180 } else if (database->dirty) {
181 WMWritePropListToFile(database->appDomain, path, True);
182 } else if (fileIsNewer) {
183 plF = WMReadPropListFromFile(path);
184 if (plF) {
185 WMReleasePropList(database->appDomain);
186 database->appDomain = plF;
187 key = database->searchList[0];
188 WMPutInPLDictionary(database->defaults, key, plF);
189 notify = True;
190 } else {
191 /* something happened with the file. just overwrite it */
192 wwarning(_("cannot read domain from file '%s' when syncing"),
193 path);
194 WMWritePropListToFile(database->appDomain, path, True);
198 database->dirty = 0;
200 if (stat(path, &stbuf) >= 0)
201 database->timestamp = stbuf.st_mtime;
203 if (notify) {
204 WMPostNotificationName(WMUserDefaultsDidChangeNotification,
205 database, NULL);
209 if (release)
210 wfree(path);
215 void
216 WMSaveUserDefaults(WMUserDefaults *database)
218 if (database->appDomain) {
219 struct stat stbuf;
220 char *path;
221 Bool release = False;
223 if (!database->path) {
224 path = wdefaultspathfordomain(WMGetApplicationName());
225 release = True;
226 } else {
227 path = database->path;
229 WMWritePropListToFile(database->appDomain, path, True);
230 database->dirty = 0;
231 if (stat(path, &stbuf) >= 0)
232 database->timestamp = stbuf.st_mtime;
233 if (release)
234 wfree(path);
239 WMUserDefaults*
240 WMGetStandardUserDefaults(void)
242 WMUserDefaults *defaults;
243 WMPropList *domain;
244 WMPropList *key;
245 struct stat stbuf;
246 char *path;
247 int i;
249 if (sharedUserDefaults) {
250 defaults = sharedUserDefaults;
251 while (defaults) {
252 /* path == NULL only for StandardUserDefaults db */
253 if (defaults->path == NULL)
254 return defaults;
255 defaults = defaults->next;
259 /* we didn't found the database we are looking for. Go read it. */
260 defaults = wmalloc(sizeof(WMUserDefaults));
261 memset(defaults, 0, sizeof(WMUserDefaults));
263 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
265 defaults->searchList = wmalloc(sizeof(WMPropList*)*3);
267 /* application domain */
268 key = WMCreatePLString(WMGetApplicationName());
269 defaults->searchList[0] = key;
271 /* temporary kluge. wmaker handles synchronization itself */
272 if (strcmp(WMGetApplicationName(), "WindowMaker")==0) {
273 defaults->dontSync = 1;
276 path = wdefaultspathfordomain(WMGetFromPLString(key));
278 if (stat(path, &stbuf) >= 0)
279 defaults->timestamp = stbuf.st_mtime;
281 domain = WMReadPropListFromFile(path);
283 if (!domain)
284 domain = WMCreatePLDictionary(NULL, NULL);
286 if (path)
287 wfree(path);
289 defaults->appDomain = domain;
291 if (domain)
292 WMPutInPLDictionary(defaults->defaults, key, domain);
294 /* global domain */
295 key = WMCreatePLString("WMGLOBAL");
296 defaults->searchList[1] = key;
298 path = wdefaultspathfordomain(WMGetFromPLString(key));
300 domain = WMReadPropListFromFile(path);
302 wfree(path);
304 if (!domain)
305 domain = WMCreatePLDictionary(NULL, NULL);
307 if (domain)
308 WMPutInPLDictionary(defaults->defaults, key, domain);
310 /* terminate list */
311 defaults->searchList[2] = NULL;
313 defaults->searchListArray = WMCreatePLArray(NULL,NULL);
315 i = 0;
316 while (defaults->searchList[i]) {
317 WMAddToPLArray(defaults->searchListArray,
318 defaults->searchList[i]);
319 i++;
322 if (sharedUserDefaults)
323 defaults->next = sharedUserDefaults;
324 sharedUserDefaults = defaults;
326 registerSaveOnExit();
328 return defaults;
332 WMUserDefaults*
333 WMGetDefaultsFromPath(char *path)
335 WMUserDefaults *defaults;
336 WMPropList *domain;
337 WMPropList *key;
338 struct stat stbuf;
339 char *name;
340 int i;
342 assert(path != NULL);
344 if (sharedUserDefaults) {
345 defaults = sharedUserDefaults;
346 while (defaults) {
347 if (defaults->path && strcmp(defaults->path, path) == 0)
348 return defaults;
349 defaults = defaults->next;
353 /* we didn't found the database we are looking for. Go read it. */
354 defaults = wmalloc(sizeof(WMUserDefaults));
355 memset(defaults, 0, sizeof(WMUserDefaults));
357 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
359 defaults->searchList = wmalloc(sizeof(WMPropList*)*2);
361 /* the domain we want, go in the first position */
362 name = strrchr(path, '/');
363 if (!name)
364 name = path;
365 else
366 name++;
368 key = WMCreatePLString(name);
369 defaults->searchList[0] = key;
371 if (stat(path, &stbuf) >= 0)
372 defaults->timestamp = stbuf.st_mtime;
374 domain = WMReadPropListFromFile(path);
376 if (!domain)
377 domain = WMCreatePLDictionary(NULL, NULL);
379 defaults->path = wstrdup(path);
381 defaults->appDomain = domain;
383 if (domain)
384 WMPutInPLDictionary(defaults->defaults, key, domain);
386 /* terminate list */
387 defaults->searchList[1] = NULL;
389 defaults->searchListArray = WMCreatePLArray(NULL,NULL);
391 i = 0;
392 while (defaults->searchList[i]) {
393 WMAddToPLArray(defaults->searchListArray,
394 defaults->searchList[i]);
395 i++;
398 if (sharedUserDefaults)
399 defaults->next = sharedUserDefaults;
400 sharedUserDefaults = defaults;
402 registerSaveOnExit();
404 return defaults;
408 /* Returns a WMPropList array with all keys in the user defaults database.
409 * Free the array with WMReleasePropList() when no longer needed,
410 * but do not free the elements of the array! They're just references. */
411 WMPropList*
412 WMGetUDKeys(WMUserDefaults *database)
414 return WMGetPLDictionaryKeys(database->appDomain);
418 WMPropList*
419 WMGetUDObjectForKey(WMUserDefaults *database, char *defaultName)
421 WMPropList *domainName, *domain;
422 WMPropList *object = NULL;
423 WMPropList *key = WMCreatePLString(defaultName);
424 int i = 0;
426 while (database->searchList[i] && !object) {
427 domainName = database->searchList[i];
428 domain = WMGetFromPLDictionary(database->defaults, domainName);
429 if (domain) {
430 object = WMGetFromPLDictionary(domain, key);
432 i++;
434 WMReleasePropList(key);
436 return object;
440 void
441 WMSetUDObjectForKey(WMUserDefaults *database, WMPropList *object,
442 char *defaultName)
444 WMPropList *key = WMCreatePLString(defaultName);
446 database->dirty = 1;
448 WMPutInPLDictionary(database->appDomain, key, object);
449 WMReleasePropList(key);
453 void
454 WMRemoveUDObjectForKey(WMUserDefaults *database, char *defaultName)
456 WMPropList *key = WMCreatePLString(defaultName);
458 database->dirty = 1;
460 WMRemoveFromPLDictionary(database->appDomain, key);
462 WMReleasePropList(key);
466 char*
467 WMGetUDStringForKey(WMUserDefaults *database, char *defaultName)
469 WMPropList *val;
471 val = WMGetUDObjectForKey(database, defaultName);
473 if (!val)
474 return NULL;
476 if (!WMIsPLString(val))
477 return NULL;
479 return WMGetFromPLString(val);
484 WMGetUDIntegerForKey(WMUserDefaults *database, char *defaultName)
486 WMPropList *val;
487 char *str;
488 int value;
490 val = WMGetUDObjectForKey(database, defaultName);
492 if (!val)
493 return 0;
495 if (!WMIsPLString(val))
496 return 0;
498 str = WMGetFromPLString(val);
499 if (!str)
500 return 0;
502 if (sscanf(str, "%i", &value)!=1)
503 return 0;
505 return value;
510 float
511 WMGetUDFloatForKey(WMUserDefaults *database, char *defaultName)
513 WMPropList *val;
514 char *str;
515 float value;
517 val = WMGetUDObjectForKey(database, defaultName);
519 if (!val || !WMIsPLString(val))
520 return 0.0;
522 if (!(str = WMGetFromPLString(val)))
523 return 0.0;
525 if (sscanf(str, "%f", &value)!=1)
526 return 0.0;
528 return value;
533 Bool
534 WMGetUDBoolForKey(WMUserDefaults *database, 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;
565 void
566 WMSetUDIntegerForKey(WMUserDefaults *database, int value, char *defaultName)
568 WMPropList *object;
569 char buffer[128];
571 sprintf(buffer, "%i", value);
572 object = WMCreatePLString(buffer);
574 WMSetUDObjectForKey(database, object, defaultName);
575 WMReleasePropList(object);
581 void
582 WMSetUDStringForKey(WMUserDefaults *database, char *value, char *defaultName)
584 WMPropList *object;
586 object = WMCreatePLString(value);
588 WMSetUDObjectForKey(database, object, defaultName);
589 WMReleasePropList(object);
594 void
595 WMSetUDFloatForKey(WMUserDefaults *database, float value, char *defaultName)
597 WMPropList *object;
598 char buffer[128];
600 sprintf(buffer, "%f", value);
601 object = WMCreatePLString(buffer);
603 WMSetUDObjectForKey(database, object, defaultName);
604 WMReleasePropList(object);
609 void
610 WMSetUDBoolForKey(WMUserDefaults *database, Bool value, char *defaultName)
612 static WMPropList *yes = NULL, *no = NULL;
614 if (!yes) {
615 yes = WMCreatePLString("YES");
616 no = WMCreatePLString("NO");
619 WMSetUDObjectForKey(database, value ? yes : no, defaultName);
623 WMPropList*
624 WMGetUDSearchList(WMUserDefaults *database)
626 return database->searchListArray;
630 void
631 WMSetUDSearchList(WMUserDefaults *database, WMPropList *list)
633 int i, c;
635 if (database->searchList) {
636 i = 0;
637 while (database->searchList[i]) {
638 WMReleasePropList(database->searchList[i]);
639 i++;
641 wfree(database->searchList);
643 if (database->searchListArray) {
644 WMReleasePropList(database->searchListArray);
647 c = WMGetPropListItemCount(list);
648 database->searchList = wmalloc(sizeof(WMPropList*)*(c+1));
650 for (i=0; i<c; i++) {
651 database->searchList[i] = WMGetFromPLArray(list, i);
653 database->searchList[c] = NULL;
655 database->searchListArray = WMDeepCopyPropList(list);