Update Serbian translation from master branch
[wmaker-crm.git] / WINGs / userdefaults.c
blobbc01723c6abef2bf6b47e4f06c668e3095f8fe8c
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 #ifndef HAVE_INOTIFY
44 /* Check defaults database for changes every this many milliseconds */
45 /* XXX: this is shared with src/ stuff, put it in some common header */
46 #define UD_SYNC_INTERVAL 2000
47 #endif
49 const char *wusergnusteppath(void)
51 static const char subdir[] = "/" GSUSER_SUBDIR;
52 static char *path = NULL;
53 char *gspath;
54 const char *h;
55 int pathlen;
57 if (path)
58 /* Value have been already computed, re-use it */
59 return path;
61 gspath = GETENV("WMAKER_USER_ROOT");
62 if (gspath) {
63 gspath = wexpandpath(gspath);
64 if (gspath) {
65 path = gspath;
66 return path;
68 wwarning(_("variable WMAKER_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 const char *wuserdatapath(void)
85 static char *path = NULL;
87 if (path)
88 /* Value have been already computed, re-use it */
89 return path;
91 path = wstrconcat(wusergnusteppath(), "/" USERDATA_SUBDIR);
93 return path;
96 char *wdefaultspathfordomain(const char *domain)
98 char *path;
99 const char *gspath;
100 size_t slen;
102 gspath = wusergnusteppath();
103 slen = strlen(gspath) + strlen("/" DEFAULTS_SUBDIR "/") + strlen(domain) + 1;
104 path = wmalloc(slen);
106 strcpy(path, gspath);
107 strcat(path, "/" DEFAULTS_SUBDIR "/");
108 strcat(path, domain);
110 return path;
113 /* XXX: doesn't quite belong to *user*defaults.c */
114 char *wglobaldefaultspathfordomain(const char *domain)
116 return wstrconcat(PKGCONFDIR "/", domain);
119 void w_save_defaults_changes(void)
121 if (WMApplication.applicationName == NULL) {
123 * This means that the user has properly exited by calling the
124 * function 'WMReleaseApplication' (which has already called us)
125 * but we're being called again by the fallback 'atexit' method
126 * (the legacy way of saving changes on exit which is kept for
127 * application that would forget to call 'WMReleaseApplication')
129 return;
132 /* save the user defaults databases */
133 synchronizeUserDefaults(NULL);
136 /* set to save changes in defaults when program is exited */
137 static void registerSaveOnExit(void)
139 static Bool registeredSaveOnExit = False;
141 if (!registeredSaveOnExit) {
142 atexit(w_save_defaults_changes);
143 registeredSaveOnExit = True;
147 static void synchronizeUserDefaults(void *foo)
149 UserDefaults *database = sharedUserDefaults;
151 /* Parameter not used, but tell the compiler that it is ok */
152 (void) foo;
154 while (database) {
155 if (!database->dontSync)
156 WMSynchronizeUserDefaults(database);
157 database = database->next;
161 #ifndef HAVE_INOTIFY
162 static void addSynchronizeTimerHandler(void)
164 static Bool initialized = False;
166 if (!initialized) {
167 WMAddPersistentTimerHandler(UD_SYNC_INTERVAL,
168 synchronizeUserDefaults, NULL);
169 initialized = True;
172 #endif
174 void WMEnableUDPeriodicSynchronization(WMUserDefaults * database, Bool enable)
176 database->dontSync = !enable;
179 void WMSynchronizeUserDefaults(WMUserDefaults * database)
181 Bool fileIsNewer = False, release = False, notify = False;
182 WMPropList *plF, *key;
183 char *path;
184 struct stat stbuf;
186 if (!database->path) {
187 path = wdefaultspathfordomain(WMGetApplicationName());
188 release = True;
189 } else {
190 path = database->path;
193 if (stat(path, &stbuf) >= 0 && stbuf.st_mtime > database->timestamp)
194 fileIsNewer = True;
196 if (database->appDomain && (database->dirty || fileIsNewer)) {
197 if (database->dirty && fileIsNewer) {
198 plF = WMReadPropListFromFile(path);
199 if (plF) {
200 plF = WMMergePLDictionaries(plF, database->appDomain, False);
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);
211 } else if (database->dirty) {
212 WMWritePropListToFile(database->appDomain, path);
213 } else if (fileIsNewer) {
214 plF = WMReadPropListFromFile(path);
215 if (plF) {
216 WMReleasePropList(database->appDomain);
217 database->appDomain = plF;
218 key = database->searchList[0];
219 WMPutInPLDictionary(database->defaults, key, plF);
220 notify = True;
221 } else {
222 /* something happened with the file. just overwrite it */
223 wwarning(_("cannot read domain from file '%s' when syncing"), path);
224 WMWritePropListToFile(database->appDomain, path);
228 database->dirty = 0;
230 if (stat(path, &stbuf) >= 0)
231 database->timestamp = stbuf.st_mtime;
233 if (notify) {
234 WMPostNotificationName(WMUserDefaultsDidChangeNotification, database, NULL);
238 if (release)
239 wfree(path);
243 void WMSaveUserDefaults(WMUserDefaults * database)
245 if (database->appDomain) {
246 struct stat stbuf;
247 char *path;
248 Bool release = False;
250 if (!database->path) {
251 path = wdefaultspathfordomain(WMGetApplicationName());
252 release = True;
253 } else {
254 path = database->path;
256 WMWritePropListToFile(database->appDomain, path);
257 database->dirty = 0;
258 if (stat(path, &stbuf) >= 0)
259 database->timestamp = stbuf.st_mtime;
260 if (release)
261 wfree(path);
265 WMUserDefaults *WMGetStandardUserDefaults(void)
267 WMUserDefaults *defaults;
268 WMPropList *domain;
269 WMPropList *key;
270 struct stat stbuf;
271 char *path;
272 int i;
274 if (sharedUserDefaults) {
275 defaults = sharedUserDefaults;
276 while (defaults) {
277 /* path == NULL only for StandardUserDefaults db */
278 if (defaults->path == NULL)
279 return defaults;
280 defaults = defaults->next;
284 /* we didn't found the database we are looking for. Go read it. XXX: wtf? */
285 defaults = wmalloc(sizeof(WMUserDefaults));
286 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
287 defaults->searchList = wmalloc(sizeof(WMPropList *) * 3);
289 /* application domain */
290 key = WMCreatePLString(WMGetApplicationName());
291 defaults->searchList[0] = key;
293 /* temporary kluge. wmaker handles synchronization itself */
294 if (strcmp(WMGetApplicationName(), "WindowMaker") == 0) {
295 defaults->dontSync = 1;
298 path = wdefaultspathfordomain(WMGetFromPLString(key));
300 if (stat(path, &stbuf) >= 0)
301 defaults->timestamp = stbuf.st_mtime;
303 domain = WMReadPropListFromFile(path);
305 if (!domain)
306 domain = WMCreatePLDictionary(NULL, NULL);
308 wfree(path);
310 defaults->appDomain = domain;
312 if (domain)
313 WMPutInPLDictionary(defaults->defaults, key, domain);
315 /* global domain */
316 key = WMCreatePLString("WMGLOBAL");
317 defaults->searchList[1] = key;
319 path = wdefaultspathfordomain(WMGetFromPLString(key));
321 domain = WMReadPropListFromFile(path);
323 wfree(path);
325 if (!domain)
326 domain = WMCreatePLDictionary(NULL, NULL);
328 if (domain)
329 WMPutInPLDictionary(defaults->defaults, key, domain);
331 /* terminate list */
332 defaults->searchList[2] = NULL;
334 defaults->searchListArray = WMCreatePLArray(NULL, NULL);
336 i = 0;
337 while (defaults->searchList[i]) {
338 WMAddToPLArray(defaults->searchListArray, defaults->searchList[i]);
339 i++;
342 if (sharedUserDefaults)
343 defaults->next = sharedUserDefaults;
344 sharedUserDefaults = defaults;
346 #ifndef HAVE_INOTIFY
347 addSynchronizeTimerHandler();
348 #endif
349 registerSaveOnExit();
351 return defaults;
354 WMUserDefaults *WMGetDefaultsFromPath(const char *path)
356 WMUserDefaults *defaults;
357 WMPropList *domain;
358 WMPropList *key;
359 struct stat stbuf;
360 const char *name;
361 int i;
363 assert(path != NULL);
365 if (sharedUserDefaults) {
366 defaults = sharedUserDefaults;
367 while (defaults) {
368 if (defaults->path && strcmp(defaults->path, path) == 0)
369 return defaults;
370 defaults = defaults->next;
374 /* we didn't found the database we are looking for. Go read it. XXX wtf? */
375 defaults = wmalloc(sizeof(WMUserDefaults));
376 defaults->defaults = WMCreatePLDictionary(NULL, NULL);
377 defaults->searchList = wmalloc(sizeof(WMPropList *) * 2);
379 /* the domain we want, go in the first position */
380 name = strrchr(path, '/');
381 if (!name)
382 name = path;
383 else
384 name++;
386 key = WMCreatePLString(name);
387 defaults->searchList[0] = key;
389 if (stat(path, &stbuf) >= 0)
390 defaults->timestamp = stbuf.st_mtime;
392 domain = WMReadPropListFromFile(path);
394 if (!domain)
395 domain = WMCreatePLDictionary(NULL, NULL);
397 defaults->path = wstrdup(path);
399 defaults->appDomain = domain;
401 if (domain)
402 WMPutInPLDictionary(defaults->defaults, key, domain);
404 /* terminate list */
405 defaults->searchList[1] = NULL;
407 defaults->searchListArray = WMCreatePLArray(NULL, NULL);
409 i = 0;
410 while (defaults->searchList[i]) {
411 WMAddToPLArray(defaults->searchListArray, defaults->searchList[i]);
412 i++;
415 if (sharedUserDefaults)
416 defaults->next = sharedUserDefaults;
417 sharedUserDefaults = defaults;
419 #ifndef HAVE_INOTIFY
420 addSynchronizeTimerHandler();
421 #endif
422 registerSaveOnExit();
424 return defaults;
427 /* Returns a WMPropList array with all keys in the user defaults database.
428 * Free the array with WMReleasePropList() when no longer needed,
429 * but do not free the elements of the array! They're just references. */
430 WMPropList *WMGetUDKeys(WMUserDefaults * database)
432 return WMGetPLDictionaryKeys(database->appDomain);
435 WMPropList *WMGetUDObjectForKey(WMUserDefaults * database, const char *defaultName)
437 WMPropList *domainName, *domain;
438 WMPropList *object = NULL;
439 WMPropList *key = WMCreatePLString(defaultName);
440 int i = 0;
442 while (database->searchList[i] && !object) {
443 domainName = database->searchList[i];
444 domain = WMGetFromPLDictionary(database->defaults, domainName);
445 if (domain) {
446 object = WMGetFromPLDictionary(domain, key);
448 i++;
450 WMReleasePropList(key);
452 return object;
455 void WMSetUDObjectForKey(WMUserDefaults * database, WMPropList * object, const char *defaultName)
457 WMPropList *key = WMCreatePLString(defaultName);
459 database->dirty = 1;
461 WMPutInPLDictionary(database->appDomain, key, object);
462 WMReleasePropList(key);
465 void WMRemoveUDObjectForKey(WMUserDefaults * database, const char *defaultName)
467 WMPropList *key = WMCreatePLString(defaultName);
469 database->dirty = 1;
471 WMRemoveFromPLDictionary(database->appDomain, key);
473 WMReleasePropList(key);
476 char *WMGetUDStringForKey(WMUserDefaults * database, const char *defaultName)
478 WMPropList *val;
480 val = WMGetUDObjectForKey(database, defaultName);
482 if (!val)
483 return NULL;
485 if (!WMIsPLString(val))
486 return NULL;
488 return WMGetFromPLString(val);
491 int WMGetUDIntegerForKey(WMUserDefaults * database, const char *defaultName)
493 WMPropList *val;
494 char *str;
495 int value;
497 val = WMGetUDObjectForKey(database, defaultName);
499 if (!val)
500 return 0;
502 if (!WMIsPLString(val))
503 return 0;
505 str = WMGetFromPLString(val);
506 if (!str)
507 return 0;
509 if (sscanf(str, "%i", &value) != 1)
510 return 0;
512 return value;
515 float WMGetUDFloatForKey(WMUserDefaults * database, const char *defaultName)
517 WMPropList *val;
518 char *str;
519 float value;
521 val = WMGetUDObjectForKey(database, defaultName);
523 if (!val || !WMIsPLString(val))
524 return 0.0;
526 if (!(str = WMGetFromPLString(val)))
527 return 0.0;
529 if (sscanf(str, "%f", &value) != 1)
530 return 0.0;
532 return value;
535 Bool WMGetUDBoolForKey(WMUserDefaults * database, const char *defaultName)
537 WMPropList *val;
538 int value;
539 char *str;
541 val = WMGetUDObjectForKey(database, defaultName);
543 if (!val)
544 return False;
546 if (!WMIsPLString(val))
547 return False;
549 str = WMGetFromPLString(val);
550 if (!str)
551 return False;
553 if (sscanf(str, "%i", &value) == 1 && value != 0)
554 return True;
556 if (strcasecmp(str, "YES") == 0)
557 return True;
559 if (strcasecmp(str, "Y") == 0)
560 return True;
562 return False;
565 void WMSetUDIntegerForKey(WMUserDefaults * database, int value, const char *defaultName)
567 WMPropList *object;
568 char buffer[128];
570 sprintf(buffer, "%i", value);
571 object = WMCreatePLString(buffer);
573 WMSetUDObjectForKey(database, object, defaultName);
574 WMReleasePropList(object);
577 void WMSetUDStringForKey(WMUserDefaults * database, const char *value, const char *defaultName)
579 WMPropList *object;
581 object = WMCreatePLString(value);
583 WMSetUDObjectForKey(database, object, defaultName);
584 WMReleasePropList(object);
587 void WMSetUDFloatForKey(WMUserDefaults * database, float value, const char *defaultName)
589 WMPropList *object;
590 char buffer[128];
592 sprintf(buffer, "%f", (double)value);
593 object = WMCreatePLString(buffer);
595 WMSetUDObjectForKey(database, object, defaultName);
596 WMReleasePropList(object);
599 void WMSetUDBoolForKey(WMUserDefaults * database, Bool value, const char *defaultName)
601 static WMPropList *yes = NULL, *no = NULL;
603 if (!yes) {
604 yes = WMCreatePLString("YES");
605 no = WMCreatePLString("NO");
608 WMSetUDObjectForKey(database, value ? yes : no, defaultName);
611 WMPropList *WMGetUDSearchList(WMUserDefaults * database)
613 return database->searchListArray;
616 void WMSetUDSearchList(WMUserDefaults * database, WMPropList * list)
618 int i, c;
620 if (database->searchList) {
621 i = 0;
622 while (database->searchList[i]) {
623 WMReleasePropList(database->searchList[i]);
624 i++;
626 wfree(database->searchList);
628 if (database->searchListArray) {
629 WMReleasePropList(database->searchListArray);
632 c = WMGetPropListItemCount(list);
633 database->searchList = wmalloc(sizeof(WMPropList *) * (c + 1));
635 for (i = 0; i < c; i++) {
636 database->searchList[i] = WMGetFromPLArray(list, i);
638 database->searchList[c] = NULL;
640 database->searchListArray = WMDeepCopyPropList(list);