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
;
55 gspath
= getenv("GNUSTEP_USER_ROOT");
57 gspath
= wexpandpath(gspath
);
58 pathlen
= strlen(gspath
) + 4;
59 path
= wmalloc(pathlen
);
63 pathlen
= strlen(wgethomedir()) + 10;
64 path
= wmalloc(pathlen
);
65 strcpy(path
, wgethomedir());
66 strcat(path
, "/GNUstep");
73 char *wdefaultspathfordomain(char *domain
)
78 gspath
= wusergnusteppath();
79 path
= wmalloc(strlen(gspath
) + strlen(DEFAULTS_DIR
) + strlen(domain
) + 4);
81 strcat(path
, DEFAULTS_DIR
);
88 /* XXX: doesn't quite belong to *user*defaults.c */
89 #ifndef GLOBAL_DEFAULTS_SUBDIR
90 #define GLOBAL_DEFAULTS_SUBDIR "WindowMaker"
92 char *wglobaldefaultspathfordomain(const char *domain
)
97 len
= strlen( SYSCONFDIR
) + strlen( GLOBAL_DEFAULTS_SUBDIR
) + strlen(domain
) + 3;
99 snprintf(t
, len
, "%s/%s/%s", SYSCONFDIR
, GLOBAL_DEFAULTS_SUBDIR
, domain
);
106 saveDefaultsChanges(void)
108 saveDefaultsChanges(int foo
, void *bar
)
111 /* save the user defaults databases */
112 synchronizeUserDefaults(NULL
);
115 /* set to save changes in defaults when program is exited */
116 static void registerSaveOnExit(void)
118 static Bool registeredSaveOnExit
= False
;
120 if (!registeredSaveOnExit
) {
122 atexit(saveDefaultsChanges
);
124 on_exit(saveDefaultsChanges
, (void *)NULL
);
126 registeredSaveOnExit
= True
;
130 static void synchronizeUserDefaults(void *foo
)
132 UserDefaults
*database
= sharedUserDefaults
;
135 if (!database
->dontSync
)
136 WMSynchronizeUserDefaults(database
);
137 database
= database
->next
;
142 static void addSynchronizeTimerHandler(void)
144 static Bool initialized
= False
;
147 WMAddPersistentTimerHandler(UD_SYNC_INTERVAL
,
148 synchronizeUserDefaults
, NULL
);
154 void WMEnableUDPeriodicSynchronization(WMUserDefaults
* database
, Bool enable
)
156 database
->dontSync
= !enable
;
159 void WMSynchronizeUserDefaults(WMUserDefaults
* database
)
161 Bool fileIsNewer
= False
, release
= False
, notify
= False
;
162 WMPropList
*plF
, *key
;
166 if (!database
->path
) {
167 path
= wdefaultspathfordomain(WMGetApplicationName());
170 path
= database
->path
;
173 if (stat(path
, &stbuf
) >= 0 && stbuf
.st_mtime
> database
->timestamp
)
176 if (database
->appDomain
&& (database
->dirty
|| fileIsNewer
)) {
177 if (database
->dirty
&& fileIsNewer
) {
178 plF
= WMReadPropListFromFile(path
);
180 plF
= WMMergePLDictionaries(plF
, database
->appDomain
, False
);
181 WMReleasePropList(database
->appDomain
);
182 database
->appDomain
= plF
;
183 key
= database
->searchList
[0];
184 WMPutInPLDictionary(database
->defaults
, key
, plF
);
187 /* something happened with the file. just overwrite it */
188 wwarning(_("cannot read domain from file '%s' when syncing"), path
);
189 WMWritePropListToFile(database
->appDomain
, path
);
191 } else if (database
->dirty
) {
192 WMWritePropListToFile(database
->appDomain
, path
);
193 } else if (fileIsNewer
) {
194 plF
= WMReadPropListFromFile(path
);
196 WMReleasePropList(database
->appDomain
);
197 database
->appDomain
= plF
;
198 key
= database
->searchList
[0];
199 WMPutInPLDictionary(database
->defaults
, key
, plF
);
202 /* something happened with the file. just overwrite it */
203 wwarning(_("cannot read domain from file '%s' when syncing"), path
);
204 WMWritePropListToFile(database
->appDomain
, path
);
210 if (stat(path
, &stbuf
) >= 0)
211 database
->timestamp
= stbuf
.st_mtime
;
214 WMPostNotificationName(WMUserDefaultsDidChangeNotification
, database
, NULL
);
223 void WMSaveUserDefaults(WMUserDefaults
* database
)
225 if (database
->appDomain
) {
228 Bool release
= False
;
230 if (!database
->path
) {
231 path
= wdefaultspathfordomain(WMGetApplicationName());
234 path
= database
->path
;
236 WMWritePropListToFile(database
->appDomain
, path
);
238 if (stat(path
, &stbuf
) >= 0)
239 database
->timestamp
= stbuf
.st_mtime
;
245 WMUserDefaults
*WMGetStandardUserDefaults(void)
247 WMUserDefaults
*defaults
;
254 if (sharedUserDefaults
) {
255 defaults
= sharedUserDefaults
;
257 /* path == NULL only for StandardUserDefaults db */
258 if (defaults
->path
== NULL
)
260 defaults
= defaults
->next
;
264 /* we didn't found the database we are looking for. Go read it. */
265 defaults
= wmalloc(sizeof(WMUserDefaults
));
266 memset(defaults
, 0, sizeof(WMUserDefaults
));
268 defaults
->defaults
= WMCreatePLDictionary(NULL
, NULL
);
270 defaults
->searchList
= wmalloc(sizeof(WMPropList
*) * 3);
272 /* application domain */
273 key
= WMCreatePLString(WMGetApplicationName());
274 defaults
->searchList
[0] = key
;
276 /* temporary kluge. wmaker handles synchronization itself */
277 if (strcmp(WMGetApplicationName(), "WindowMaker") == 0) {
278 defaults
->dontSync
= 1;
281 path
= wdefaultspathfordomain(WMGetFromPLString(key
));
283 if (stat(path
, &stbuf
) >= 0)
284 defaults
->timestamp
= stbuf
.st_mtime
;
286 domain
= WMReadPropListFromFile(path
);
289 domain
= WMCreatePLDictionary(NULL
, NULL
);
294 defaults
->appDomain
= domain
;
297 WMPutInPLDictionary(defaults
->defaults
, key
, domain
);
300 key
= WMCreatePLString("WMGLOBAL");
301 defaults
->searchList
[1] = key
;
303 path
= wdefaultspathfordomain(WMGetFromPLString(key
));
305 domain
= WMReadPropListFromFile(path
);
310 domain
= WMCreatePLDictionary(NULL
, NULL
);
313 WMPutInPLDictionary(defaults
->defaults
, key
, domain
);
316 defaults
->searchList
[2] = NULL
;
318 defaults
->searchListArray
= WMCreatePLArray(NULL
, NULL
);
321 while (defaults
->searchList
[i
]) {
322 WMAddToPLArray(defaults
->searchListArray
, defaults
->searchList
[i
]);
326 if (sharedUserDefaults
)
327 defaults
->next
= sharedUserDefaults
;
328 sharedUserDefaults
= defaults
;
331 addSynchronizeTimerHandler();
333 registerSaveOnExit();
338 WMUserDefaults
*WMGetDefaultsFromPath(char *path
)
340 WMUserDefaults
*defaults
;
347 assert(path
!= NULL
);
349 if (sharedUserDefaults
) {
350 defaults
= sharedUserDefaults
;
352 if (defaults
->path
&& strcmp(defaults
->path
, path
) == 0)
354 defaults
= defaults
->next
;
358 /* we didn't found the database we are looking for. Go read it. */
359 defaults
= wmalloc(sizeof(WMUserDefaults
));
360 memset(defaults
, 0, sizeof(WMUserDefaults
));
362 defaults
->defaults
= WMCreatePLDictionary(NULL
, NULL
);
364 defaults
->searchList
= wmalloc(sizeof(WMPropList
*) * 2);
366 /* the domain we want, go in the first position */
367 name
= strrchr(path
, '/');
373 key
= WMCreatePLString(name
);
374 defaults
->searchList
[0] = key
;
376 if (stat(path
, &stbuf
) >= 0)
377 defaults
->timestamp
= stbuf
.st_mtime
;
379 domain
= WMReadPropListFromFile(path
);
382 domain
= WMCreatePLDictionary(NULL
, NULL
);
384 defaults
->path
= wstrdup(path
);
386 defaults
->appDomain
= domain
;
389 WMPutInPLDictionary(defaults
->defaults
, key
, domain
);
392 defaults
->searchList
[1] = NULL
;
394 defaults
->searchListArray
= WMCreatePLArray(NULL
, NULL
);
397 while (defaults
->searchList
[i
]) {
398 WMAddToPLArray(defaults
->searchListArray
, defaults
->searchList
[i
]);
402 if (sharedUserDefaults
)
403 defaults
->next
= sharedUserDefaults
;
404 sharedUserDefaults
= defaults
;
407 addSynchronizeTimerHandler();
409 registerSaveOnExit();
414 /* Returns a WMPropList array with all keys in the user defaults database.
415 * Free the array with WMReleasePropList() when no longer needed,
416 * but do not free the elements of the array! They're just references. */
417 WMPropList
*WMGetUDKeys(WMUserDefaults
* database
)
419 return WMGetPLDictionaryKeys(database
->appDomain
);
422 WMPropList
*WMGetUDObjectForKey(WMUserDefaults
* database
, char *defaultName
)
424 WMPropList
*domainName
, *domain
;
425 WMPropList
*object
= NULL
;
426 WMPropList
*key
= WMCreatePLString(defaultName
);
429 while (database
->searchList
[i
] && !object
) {
430 domainName
= database
->searchList
[i
];
431 domain
= WMGetFromPLDictionary(database
->defaults
, domainName
);
433 object
= WMGetFromPLDictionary(domain
, key
);
437 WMReleasePropList(key
);
442 void WMSetUDObjectForKey(WMUserDefaults
* database
, WMPropList
* object
, char *defaultName
)
444 WMPropList
*key
= WMCreatePLString(defaultName
);
448 WMPutInPLDictionary(database
->appDomain
, key
, object
);
449 WMReleasePropList(key
);
452 void WMRemoveUDObjectForKey(WMUserDefaults
* database
, char *defaultName
)
454 WMPropList
*key
= WMCreatePLString(defaultName
);
458 WMRemoveFromPLDictionary(database
->appDomain
, key
);
460 WMReleasePropList(key
);
463 char *WMGetUDStringForKey(WMUserDefaults
* database
, char *defaultName
)
467 val
= WMGetUDObjectForKey(database
, defaultName
);
472 if (!WMIsPLString(val
))
475 return WMGetFromPLString(val
);
478 int WMGetUDIntegerForKey(WMUserDefaults
* database
, char *defaultName
)
484 val
= WMGetUDObjectForKey(database
, defaultName
);
489 if (!WMIsPLString(val
))
492 str
= WMGetFromPLString(val
);
496 if (sscanf(str
, "%i", &value
) != 1)
502 float WMGetUDFloatForKey(WMUserDefaults
* database
, char *defaultName
)
508 val
= WMGetUDObjectForKey(database
, defaultName
);
510 if (!val
|| !WMIsPLString(val
))
513 if (!(str
= WMGetFromPLString(val
)))
516 if (sscanf(str
, "%f", &value
) != 1)
522 Bool
WMGetUDBoolForKey(WMUserDefaults
* database
, char *defaultName
)
528 val
= WMGetUDObjectForKey(database
, defaultName
);
533 if (!WMIsPLString(val
))
536 str
= WMGetFromPLString(val
);
540 if (sscanf(str
, "%i", &value
) == 1 && value
!= 0)
543 if (strcasecmp(str
, "YES") == 0)
546 if (strcasecmp(str
, "Y") == 0)
552 void WMSetUDIntegerForKey(WMUserDefaults
* database
, int value
, char *defaultName
)
557 sprintf(buffer
, "%i", value
);
558 object
= WMCreatePLString(buffer
);
560 WMSetUDObjectForKey(database
, object
, defaultName
);
561 WMReleasePropList(object
);
564 void WMSetUDStringForKey(WMUserDefaults
* database
, char *value
, char *defaultName
)
568 object
= WMCreatePLString(value
);
570 WMSetUDObjectForKey(database
, object
, defaultName
);
571 WMReleasePropList(object
);
574 void WMSetUDFloatForKey(WMUserDefaults
* database
, float value
, char *defaultName
)
579 sprintf(buffer
, "%f", value
);
580 object
= WMCreatePLString(buffer
);
582 WMSetUDObjectForKey(database
, object
, defaultName
);
583 WMReleasePropList(object
);
586 void WMSetUDBoolForKey(WMUserDefaults
* database
, Bool value
, char *defaultName
)
588 static WMPropList
*yes
= NULL
, *no
= NULL
;
591 yes
= WMCreatePLString("YES");
592 no
= WMCreatePLString("NO");
595 WMSetUDObjectForKey(database
, value
? yes
: no
, defaultName
);
598 WMPropList
*WMGetUDSearchList(WMUserDefaults
* database
)
600 return database
->searchListArray
;
603 void WMSetUDSearchList(WMUserDefaults
* database
, WMPropList
* list
)
607 if (database
->searchList
) {
609 while (database
->searchList
[i
]) {
610 WMReleasePropList(database
->searchList
[i
]);
613 wfree(database
->searchList
);
615 if (database
->searchListArray
) {
616 WMReleasePropList(database
->searchListArray
);
619 c
= WMGetPropListItemCount(list
);
620 database
->searchList
= wmalloc(sizeof(WMPropList
*) * (c
+ 1));
622 for (i
= 0; i
< c
; i
++) {
623 database
->searchList
[i
] = WMGetFromPLArray(list
, i
);
625 database
->searchList
[c
] = NULL
;
627 database
->searchListArray
= WMDeepCopyPropList(list
);