14 typedef struct W_UserDefaults
{
17 WMPropList
*appDomain
;
19 WMPropList
*searchListArray
;
20 WMPropList
**searchList
; /* cache for searchListArray */
26 char *path
; /* where is db located */
28 time_t timestamp
; /* last modification time */
30 struct W_UserDefaults
*next
;
34 static UserDefaults
*sharedUserDefaults
= NULL
;
36 char *WMUserDefaultsDidChangeNotification
= "WMUserDefaultsDidChangeNotification";
38 static void synchronizeUserDefaults(void *foo
);
40 #define DEFAULTS_DIR "/Defaults"
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
47 const char *wusergnusteppath()
49 static const char subdir
[] = "/GNUstep";
50 static char *path
= NULL
;
55 /* Value have been already computed, re-use it */
58 gspath
= getenv("GNUSTEP_USER_ROOT");
60 gspath
= wexpandpath(gspath
);
65 wwarning(_("variable GNUSTEP_USER_ROOT defined with invalid path, not used"));
73 path
= wmalloc(pathlen
+ sizeof(subdir
));
75 strcpy(path
+ pathlen
, subdir
);
80 char *wdefaultspathfordomain(const char *domain
)
86 gspath
= wusergnusteppath();
87 slen
= strlen(gspath
) + strlen(DEFAULTS_DIR
) + strlen(domain
) + 4;
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
) {
101 /* XXX: doesn't quite belong to *user*defaults.c */
102 #ifndef GLOBAL_DEFAULTS_SUBDIR
103 #define GLOBAL_DEFAULTS_SUBDIR "WindowMaker"
105 char *wglobaldefaultspathfordomain(const char *domain
)
110 len
= strlen( SYSCONFDIR
) + strlen( GLOBAL_DEFAULTS_SUBDIR
) + strlen(domain
) + 3;
112 snprintf(t
, len
, "%s/%s/%s", SYSCONFDIR
, GLOBAL_DEFAULTS_SUBDIR
, domain
);
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
;
140 if (!database
->dontSync
)
141 WMSynchronizeUserDefaults(database
);
142 database
= database
->next
;
147 static void addSynchronizeTimerHandler(void)
149 static Bool initialized
= False
;
152 WMAddPersistentTimerHandler(UD_SYNC_INTERVAL
,
153 synchronizeUserDefaults
, NULL
);
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
;
171 if (!database
->path
) {
172 path
= wdefaultspathfordomain(WMGetApplicationName());
175 path
= database
->path
;
178 if (stat(path
, &stbuf
) >= 0 && stbuf
.st_mtime
> database
->timestamp
)
181 if (database
->appDomain
&& (database
->dirty
|| fileIsNewer
)) {
182 if (database
->dirty
&& fileIsNewer
) {
183 plF
= WMReadPropListFromFile(path
);
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
);
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
);
201 WMReleasePropList(database
->appDomain
);
202 database
->appDomain
= plF
;
203 key
= database
->searchList
[0];
204 WMPutInPLDictionary(database
->defaults
, key
, plF
);
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
);
215 if (stat(path
, &stbuf
) >= 0)
216 database
->timestamp
= stbuf
.st_mtime
;
219 WMPostNotificationName(WMUserDefaultsDidChangeNotification
, database
, NULL
);
228 void WMSaveUserDefaults(WMUserDefaults
* database
)
230 if (database
->appDomain
) {
233 Bool release
= False
;
235 if (!database
->path
) {
236 path
= wdefaultspathfordomain(WMGetApplicationName());
239 path
= database
->path
;
241 WMWritePropListToFile(database
->appDomain
, path
);
243 if (stat(path
, &stbuf
) >= 0)
244 database
->timestamp
= stbuf
.st_mtime
;
250 WMUserDefaults
*WMGetStandardUserDefaults(void)
252 WMUserDefaults
*defaults
;
259 if (sharedUserDefaults
) {
260 defaults
= sharedUserDefaults
;
262 /* path == NULL only for StandardUserDefaults db */
263 if (defaults
->path
== NULL
)
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
);
291 domain
= WMCreatePLDictionary(NULL
, NULL
);
296 defaults
->appDomain
= domain
;
299 WMPutInPLDictionary(defaults
->defaults
, key
, domain
);
302 key
= WMCreatePLString("WMGLOBAL");
303 defaults
->searchList
[1] = key
;
305 path
= wdefaultspathfordomain(WMGetFromPLString(key
));
307 domain
= WMReadPropListFromFile(path
);
312 domain
= WMCreatePLDictionary(NULL
, NULL
);
315 WMPutInPLDictionary(defaults
->defaults
, key
, domain
);
318 defaults
->searchList
[2] = NULL
;
320 defaults
->searchListArray
= WMCreatePLArray(NULL
, NULL
);
323 while (defaults
->searchList
[i
]) {
324 WMAddToPLArray(defaults
->searchListArray
, defaults
->searchList
[i
]);
328 if (sharedUserDefaults
)
329 defaults
->next
= sharedUserDefaults
;
330 sharedUserDefaults
= defaults
;
333 addSynchronizeTimerHandler();
335 registerSaveOnExit();
340 WMUserDefaults
*WMGetDefaultsFromPath(const char *path
)
342 WMUserDefaults
*defaults
;
349 assert(path
!= NULL
);
351 if (sharedUserDefaults
) {
352 defaults
= sharedUserDefaults
;
354 if (defaults
->path
&& strcmp(defaults
->path
, path
) == 0)
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
, '/');
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
);
381 domain
= WMCreatePLDictionary(NULL
, NULL
);
383 defaults
->path
= wstrdup(path
);
385 defaults
->appDomain
= domain
;
388 WMPutInPLDictionary(defaults
->defaults
, key
, domain
);
391 defaults
->searchList
[1] = NULL
;
393 defaults
->searchListArray
= WMCreatePLArray(NULL
, NULL
);
396 while (defaults
->searchList
[i
]) {
397 WMAddToPLArray(defaults
->searchListArray
, defaults
->searchList
[i
]);
401 if (sharedUserDefaults
)
402 defaults
->next
= sharedUserDefaults
;
403 sharedUserDefaults
= defaults
;
406 addSynchronizeTimerHandler();
408 registerSaveOnExit();
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
);
428 while (database
->searchList
[i
] && !object
) {
429 domainName
= database
->searchList
[i
];
430 domain
= WMGetFromPLDictionary(database
->defaults
, domainName
);
432 object
= WMGetFromPLDictionary(domain
, key
);
436 WMReleasePropList(key
);
441 void WMSetUDObjectForKey(WMUserDefaults
* database
, WMPropList
* object
, const char *defaultName
)
443 WMPropList
*key
= WMCreatePLString(defaultName
);
447 WMPutInPLDictionary(database
->appDomain
, key
, object
);
448 WMReleasePropList(key
);
451 void WMRemoveUDObjectForKey(WMUserDefaults
* database
, const char *defaultName
)
453 WMPropList
*key
= WMCreatePLString(defaultName
);
457 WMRemoveFromPLDictionary(database
->appDomain
, key
);
459 WMReleasePropList(key
);
462 char *WMGetUDStringForKey(WMUserDefaults
* database
, const char *defaultName
)
466 val
= WMGetUDObjectForKey(database
, defaultName
);
471 if (!WMIsPLString(val
))
474 return WMGetFromPLString(val
);
477 int WMGetUDIntegerForKey(WMUserDefaults
* database
, const char *defaultName
)
483 val
= WMGetUDObjectForKey(database
, defaultName
);
488 if (!WMIsPLString(val
))
491 str
= WMGetFromPLString(val
);
495 if (sscanf(str
, "%i", &value
) != 1)
501 float WMGetUDFloatForKey(WMUserDefaults
* database
, const char *defaultName
)
507 val
= WMGetUDObjectForKey(database
, defaultName
);
509 if (!val
|| !WMIsPLString(val
))
512 if (!(str
= WMGetFromPLString(val
)))
515 if (sscanf(str
, "%f", &value
) != 1)
521 Bool
WMGetUDBoolForKey(WMUserDefaults
* database
, const char *defaultName
)
527 val
= WMGetUDObjectForKey(database
, defaultName
);
532 if (!WMIsPLString(val
))
535 str
= WMGetFromPLString(val
);
539 if (sscanf(str
, "%i", &value
) == 1 && value
!= 0)
542 if (strcasecmp(str
, "YES") == 0)
545 if (strcasecmp(str
, "Y") == 0)
551 void WMSetUDIntegerForKey(WMUserDefaults
* database
, int value
, const char *defaultName
)
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
)
567 object
= WMCreatePLString(value
);
569 WMSetUDObjectForKey(database
, object
, defaultName
);
570 WMReleasePropList(object
);
573 void WMSetUDFloatForKey(WMUserDefaults
* database
, float value
, const char *defaultName
)
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
;
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
)
606 if (database
->searchList
) {
608 while (database
->searchList
[i
]) {
609 WMReleasePropList(database
->searchList
[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
);