13 typedef struct W_UserDefaults
{
16 WMPropList
*appDomain
;
18 WMPropList
*searchListArray
;
19 WMPropList
**searchList
; /* cache for searchListArray */
25 char *path
; /* where is db located */
27 time_t timestamp
; /* last modification time */
29 struct W_UserDefaults
*next
;
33 static UserDefaults
*sharedUserDefaults
= NULL
;
35 char *WMUserDefaultsDidChangeNotification
= "WMUserDefaultsDidChangeNotification";
37 static void synchronizeUserDefaults(void *foo
);
39 extern char *WMGetApplicationName();
41 #define DEFAULTS_DIR "/Defaults"
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
48 char *wusergnusteppath()
50 static char *path
= NULL
;
54 gspath
= getenv("GNUSTEP_USER_ROOT");
56 gspath
= wexpandpath(gspath
);
58 pathlen
= strlen(gspath
) + 4;
59 path
= wmalloc(pathlen
);
60 if (wstrlcpy(path
, gspath
, pathlen
) >= pathlen
) {
67 char *h
= wgethomedir();
70 pathlen
= strlen(h
) + 8 /* /GNUstep */ + 1;
71 path
= wmalloc(pathlen
);
72 if (wstrlcpy(path
, h
, pathlen
) >= pathlen
||
73 wstrlcat(path
, "/GNUstep", pathlen
) >= pathlen
) {
82 char *wdefaultspathfordomain(char *domain
)
88 gspath
= wusergnusteppath();
89 slen
= strlen(gspath
) + strlen(DEFAULTS_DIR
) + strlen(domain
) + 4;
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
) {
103 /* XXX: doesn't quite belong to *user*defaults.c */
104 #ifndef GLOBAL_DEFAULTS_SUBDIR
105 #define GLOBAL_DEFAULTS_SUBDIR "WindowMaker"
107 char *wglobaldefaultspathfordomain(const char *domain
)
112 len
= strlen( SYSCONFDIR
) + strlen( GLOBAL_DEFAULTS_SUBDIR
) + strlen(domain
) + 3;
114 snprintf(t
, len
, "%s/%s/%s", SYSCONFDIR
, GLOBAL_DEFAULTS_SUBDIR
, domain
);
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
;
142 if (!database
->dontSync
)
143 WMSynchronizeUserDefaults(database
);
144 database
= database
->next
;
149 static void addSynchronizeTimerHandler(void)
151 static Bool initialized
= False
;
154 WMAddPersistentTimerHandler(UD_SYNC_INTERVAL
,
155 synchronizeUserDefaults
, NULL
);
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
;
173 if (!database
->path
) {
174 path
= wdefaultspathfordomain(WMGetApplicationName());
177 path
= database
->path
;
180 if (stat(path
, &stbuf
) >= 0 && stbuf
.st_mtime
> database
->timestamp
)
183 if (database
->appDomain
&& (database
->dirty
|| fileIsNewer
)) {
184 if (database
->dirty
&& fileIsNewer
) {
185 plF
= WMReadPropListFromFile(path
);
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
);
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
);
203 WMReleasePropList(database
->appDomain
);
204 database
->appDomain
= plF
;
205 key
= database
->searchList
[0];
206 WMPutInPLDictionary(database
->defaults
, key
, plF
);
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
);
217 if (stat(path
, &stbuf
) >= 0)
218 database
->timestamp
= stbuf
.st_mtime
;
221 WMPostNotificationName(WMUserDefaultsDidChangeNotification
, database
, NULL
);
230 void WMSaveUserDefaults(WMUserDefaults
* database
)
232 if (database
->appDomain
) {
235 Bool release
= False
;
237 if (!database
->path
) {
238 path
= wdefaultspathfordomain(WMGetApplicationName());
241 path
= database
->path
;
243 WMWritePropListToFile(database
->appDomain
, path
);
245 if (stat(path
, &stbuf
) >= 0)
246 database
->timestamp
= stbuf
.st_mtime
;
252 WMUserDefaults
*WMGetStandardUserDefaults(void)
254 WMUserDefaults
*defaults
;
261 if (sharedUserDefaults
) {
262 defaults
= sharedUserDefaults
;
264 /* path == NULL only for StandardUserDefaults db */
265 if (defaults
->path
== NULL
)
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
);
293 domain
= WMCreatePLDictionary(NULL
, NULL
);
298 defaults
->appDomain
= domain
;
301 WMPutInPLDictionary(defaults
->defaults
, key
, domain
);
304 key
= WMCreatePLString("WMGLOBAL");
305 defaults
->searchList
[1] = key
;
307 path
= wdefaultspathfordomain(WMGetFromPLString(key
));
309 domain
= WMReadPropListFromFile(path
);
314 domain
= WMCreatePLDictionary(NULL
, NULL
);
317 WMPutInPLDictionary(defaults
->defaults
, key
, domain
);
320 defaults
->searchList
[2] = NULL
;
322 defaults
->searchListArray
= WMCreatePLArray(NULL
, NULL
);
325 while (defaults
->searchList
[i
]) {
326 WMAddToPLArray(defaults
->searchListArray
, defaults
->searchList
[i
]);
330 if (sharedUserDefaults
)
331 defaults
->next
= sharedUserDefaults
;
332 sharedUserDefaults
= defaults
;
335 addSynchronizeTimerHandler();
337 registerSaveOnExit();
342 WMUserDefaults
*WMGetDefaultsFromPath(char *path
)
344 WMUserDefaults
*defaults
;
351 assert(path
!= NULL
);
353 if (sharedUserDefaults
) {
354 defaults
= sharedUserDefaults
;
356 if (defaults
->path
&& strcmp(defaults
->path
, path
) == 0)
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
, '/');
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
);
383 domain
= WMCreatePLDictionary(NULL
, NULL
);
385 defaults
->path
= wstrdup(path
);
387 defaults
->appDomain
= domain
;
390 WMPutInPLDictionary(defaults
->defaults
, key
, domain
);
393 defaults
->searchList
[1] = NULL
;
395 defaults
->searchListArray
= WMCreatePLArray(NULL
, NULL
);
398 while (defaults
->searchList
[i
]) {
399 WMAddToPLArray(defaults
->searchListArray
, defaults
->searchList
[i
]);
403 if (sharedUserDefaults
)
404 defaults
->next
= sharedUserDefaults
;
405 sharedUserDefaults
= defaults
;
408 addSynchronizeTimerHandler();
410 registerSaveOnExit();
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
);
430 while (database
->searchList
[i
] && !object
) {
431 domainName
= database
->searchList
[i
];
432 domain
= WMGetFromPLDictionary(database
->defaults
, domainName
);
434 object
= WMGetFromPLDictionary(domain
, key
);
438 WMReleasePropList(key
);
443 void WMSetUDObjectForKey(WMUserDefaults
* database
, WMPropList
* object
, char *defaultName
)
445 WMPropList
*key
= WMCreatePLString(defaultName
);
449 WMPutInPLDictionary(database
->appDomain
, key
, object
);
450 WMReleasePropList(key
);
453 void WMRemoveUDObjectForKey(WMUserDefaults
* database
, char *defaultName
)
455 WMPropList
*key
= WMCreatePLString(defaultName
);
459 WMRemoveFromPLDictionary(database
->appDomain
, key
);
461 WMReleasePropList(key
);
464 char *WMGetUDStringForKey(WMUserDefaults
* database
, char *defaultName
)
468 val
= WMGetUDObjectForKey(database
, defaultName
);
473 if (!WMIsPLString(val
))
476 return WMGetFromPLString(val
);
479 int WMGetUDIntegerForKey(WMUserDefaults
* database
, char *defaultName
)
485 val
= WMGetUDObjectForKey(database
, defaultName
);
490 if (!WMIsPLString(val
))
493 str
= WMGetFromPLString(val
);
497 if (sscanf(str
, "%i", &value
) != 1)
503 float WMGetUDFloatForKey(WMUserDefaults
* database
, char *defaultName
)
509 val
= WMGetUDObjectForKey(database
, defaultName
);
511 if (!val
|| !WMIsPLString(val
))
514 if (!(str
= WMGetFromPLString(val
)))
517 if (sscanf(str
, "%f", &value
) != 1)
523 Bool
WMGetUDBoolForKey(WMUserDefaults
* database
, char *defaultName
)
529 val
= WMGetUDObjectForKey(database
, defaultName
);
534 if (!WMIsPLString(val
))
537 str
= WMGetFromPLString(val
);
541 if (sscanf(str
, "%i", &value
) == 1 && value
!= 0)
544 if (strcasecmp(str
, "YES") == 0)
547 if (strcasecmp(str
, "Y") == 0)
553 void WMSetUDIntegerForKey(WMUserDefaults
* database
, int value
, char *defaultName
)
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
)
569 object
= WMCreatePLString(value
);
571 WMSetUDObjectForKey(database
, object
, defaultName
);
572 WMReleasePropList(object
);
575 void WMSetUDFloatForKey(WMUserDefaults
* database
, float value
, char *defaultName
)
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
;
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
)
608 if (database
->searchList
) {
610 while (database
->searchList
[i
]) {
611 WMReleasePropList(database
->searchList
[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
);