]> git.saurik.com Git - apple/cf.git/blob - Preferences.subproj/CFApplicationPreferences.c
764e68c78f23aba51e96efe7d50b05b0a4a63fb3
[apple/cf.git] / Preferences.subproj / CFApplicationPreferences.c
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /* CFApplicationPreferences.c
24 Copyright 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Chris Parker
26 */
27
28 #include <CoreFoundation/CFPreferences.h>
29 #include "CFInternal.h"
30 #include <CoreFoundation/CFUniChar.h>
31 #include <CoreFoundation/CFNumber.h>
32
33 static Boolean _CFApplicationPreferencesSynchronizeNoLock(_CFApplicationPreferences *self);
34 void _CFPreferencesDomainSetMultiple(CFPreferencesDomainRef domain, CFDictionaryRef dict);
35 static void updateDictRep(_CFApplicationPreferences *self);
36 Boolean _CFApplicationPreferencesContainsDomainNoLock(_CFApplicationPreferences *self, CFPreferencesDomainRef domain);
37
38 static void *__CFInsertionDomain = NULL;
39 static CFDictionaryRef __CFInsertion = NULL;
40
41 // Bindings internals
42 extern CFSpinLock_t userDefaultsLock;
43 extern void *userDefaults;
44
45 // Management externals
46 extern Boolean _CFPreferencesManagementActive;
47
48
49 #define CF_OBJC_KVO_WILLCHANGE(obj, sel)
50 #define CF_OBJC_KVO_DIDCHANGE(obj, sel)
51
52
53 // Right now, nothing is getting destroyed pretty much ever. We probably don't want this to be the case, but it's very tricky - domains live in the cache as well as a given application's preferences, and since they're not CFTypes, there's no reference count. Also, it's not clear we ever want domains destroyed. When they're synchronized, they clear their internal state (to force reading from the disk again), so they're not very big.... REW, 12/17/98
54
55 CFPropertyListRef CFPreferencesCopyAppValue(CFStringRef key, CFStringRef appName) {
56 _CFApplicationPreferences *standardPrefs;
57 CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__);
58 CFAssert1(key != NULL, __kCFLogAssertion, "%s(): Cannot access preferences with a NULL key", __PRETTY_FUNCTION__);
59
60 standardPrefs = _CFStandardApplicationPreferences(appName);
61 return standardPrefs ? _CFApplicationPreferencesCreateValueForKey(standardPrefs, key) : NULL;
62 }
63
64 CF_EXPORT Boolean CFPreferencesAppBooleanValue(CFStringRef key, CFStringRef appName, Boolean *keyExistsAndHasValidFormat) {
65 CFPropertyListRef value;
66 Boolean result, valid;
67 CFTypeID typeID = 0;
68 CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__);
69 CFAssert1(key != NULL, __kCFLogAssertion, "%s(): Cannot access preferences with a NULL key", __PRETTY_FUNCTION__);
70
71 if (!keyExistsAndHasValidFormat) {
72 keyExistsAndHasValidFormat = &valid;
73 }
74 value = CFPreferencesCopyAppValue(key, appName);
75 if (!value) {
76 *keyExistsAndHasValidFormat = false;
77 return false;
78 }
79 typeID = CFGetTypeID(value);
80 if (typeID == CFStringGetTypeID()) {
81 if (CFStringCompare(value, CFSTR("true"), kCFCompareCaseInsensitive) == kCFCompareEqualTo || CFStringCompare(value, CFSTR("YES"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
82 *keyExistsAndHasValidFormat = true;
83 result = true;
84 } else if (CFStringCompare(value, CFSTR("false"), kCFCompareCaseInsensitive) == kCFCompareEqualTo || CFStringCompare(value, CFSTR("NO"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
85 *keyExistsAndHasValidFormat = true;
86 result = false;
87 } else {
88 *keyExistsAndHasValidFormat = false;
89 result = false;
90 }
91 } else if (typeID == CFNumberGetTypeID()) {
92 if (CFNumberIsFloatType(value)) {
93 *keyExistsAndHasValidFormat = false;
94 result = false;
95 } else {
96 int i;
97 *keyExistsAndHasValidFormat = true;
98 CFNumberGetValue(value, kCFNumberIntType, &i);
99 result = (i == 0) ? false : true;
100 }
101 } else if (typeID == CFBooleanGetTypeID()) {
102 result = (value == kCFBooleanTrue);
103 *keyExistsAndHasValidFormat = true;
104 } else {
105 // Unknown type
106 result = false;
107 *keyExistsAndHasValidFormat = false;
108 }
109 CFRelease(value);
110 return result;
111 }
112
113 __private_extern__ CFIndex CFPreferencesAppIntegerValue(CFStringRef key, CFStringRef appName, Boolean *keyExistsAndHasValidFormat) {
114 CFPropertyListRef value;
115 CFIndex result;
116 CFTypeID typeID = 0;
117 Boolean valid;
118 CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__);
119 CFAssert1(key != NULL, __kCFLogAssertion, "%s(): Cannot access preferences with a NULL key", __PRETTY_FUNCTION__);
120
121 value = CFPreferencesCopyAppValue(key, appName);
122 if (!keyExistsAndHasValidFormat) {
123 keyExistsAndHasValidFormat = &valid;
124 }
125 if (!value) {
126 *keyExistsAndHasValidFormat = false;
127 return 0;
128 }
129 typeID = CFGetTypeID(value);
130 if (typeID == CFStringGetTypeID()) {
131 CFIndex charIndex = 0;
132 SInt32 intVal;
133 CFStringInlineBuffer buf;
134 Boolean success;
135 CFStringInitInlineBuffer(value, &buf, CFRangeMake(0, CFStringGetLength(value)));
136 success = __CFStringScanInteger(&buf, NULL, &charIndex, false, &intVal);
137 *keyExistsAndHasValidFormat = (success && charIndex == CFStringGetLength(value));
138 result = (*keyExistsAndHasValidFormat) ? intVal : 0;
139 } else if (typeID == CFNumberGetTypeID()) {
140 *keyExistsAndHasValidFormat = !CFNumberIsFloatType(value);
141 if (*keyExistsAndHasValidFormat) {
142 CFNumberGetValue(value, kCFNumberCFIndexType, &result);
143 } else {
144 result = 0;
145 }
146 } else {
147 // Unknown type
148 result = 0;
149 *keyExistsAndHasValidFormat = false;
150 }
151 CFRelease(value);
152 return result;
153 }
154
155 Boolean CFPreferencesGetAppBooleanValue(CFStringRef key, CFStringRef appName, Boolean *keyExistsAndHasValidFormat) {
156 CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__);
157 CFAssert1(key != NULL, __kCFLogAssertion, "%s(): Cannot access preferences with a NULL key", __PRETTY_FUNCTION__);
158 return CFPreferencesAppBooleanValue(key, appName, keyExistsAndHasValidFormat);
159 }
160
161 CFIndex CFPreferencesGetAppIntegerValue(CFStringRef key, CFStringRef appName, Boolean *keyExistsAndHasValidFormat) {
162 CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__);
163 CFAssert1(key != NULL, __kCFLogAssertion, "%s(): Cannot access preferences with a NULL key", __PRETTY_FUNCTION__);
164 return CFPreferencesAppIntegerValue(key, appName, keyExistsAndHasValidFormat);
165 }
166
167 void CFPreferencesSetAppValue(CFStringRef key, CFTypeRef value, CFStringRef appName) {
168 _CFApplicationPreferences *standardPrefs;
169 CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__);
170 CFAssert1(key != NULL, __kCFLogAssertion, "%s(): Cannot access preferences with a NULL key", __PRETTY_FUNCTION__);
171
172 standardPrefs = _CFStandardApplicationPreferences(appName);
173 if (standardPrefs) {
174 if (value) _CFApplicationPreferencesSet(standardPrefs, key, value);
175 else _CFApplicationPreferencesRemove(standardPrefs, key);
176 }
177 }
178
179
180 static CFSpinLock_t __CFApplicationPreferencesLock = 0; // Locks access to __CFStandardUserPreferences
181 static CFMutableDictionaryRef __CFStandardUserPreferences = NULL; // Mutable dictionary; keys are app names, values are _CFApplicationPreferences
182
183 Boolean CFPreferencesAppSynchronize(CFStringRef appName) {
184 _CFApplicationPreferences *standardPrefs;
185 Boolean result;
186 CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__);
187 __CFPreferencesCheckFormatType();
188
189 // Do not call _CFStandardApplicationPreferences(), as we do not want to create the preferences only to synchronize
190 __CFSpinLock(&__CFApplicationPreferencesLock);
191 if (__CFStandardUserPreferences) {
192 standardPrefs = (_CFApplicationPreferences *)CFDictionaryGetValue(__CFStandardUserPreferences, appName);
193 } else {
194 standardPrefs = NULL;
195 }
196
197 result = standardPrefs ? _CFApplicationPreferencesSynchronizeNoLock(standardPrefs) : _CFSynchronizeDomainCache();
198 __CFSpinUnlock(&__CFApplicationPreferencesLock);
199 return result;
200 }
201
202 void CFPreferencesFlushCaches(void) {
203 CFAllocatorRef alloc = __CFPreferencesAllocator();
204 __CFSpinLock(&__CFApplicationPreferencesLock);
205 if (__CFStandardUserPreferences) {
206 _CFApplicationPreferences **prefsArray, *prefsBuf[32];
207 CFIndex idx, count = CFDictionaryGetCount(__CFStandardUserPreferences);
208 if (count < 32) {
209 prefsArray = prefsBuf;
210 } else {
211 prefsArray = _CFAllocatorAllocateGC(alloc, count * sizeof(_CFApplicationPreferences *), 0);
212 }
213 CFDictionaryGetKeysAndValues(__CFStandardUserPreferences, NULL, (const void **)prefsArray);
214
215 __CFSpinUnlock(&__CFApplicationPreferencesLock);
216 // DeallocateApplicationPreferences needs the lock
217 for (idx = 0; idx < count; idx ++) {
218 _CFApplicationPreferences *appPrefs = prefsArray[idx];
219 _CFApplicationPreferencesSynchronize(appPrefs);
220 _CFDeallocateApplicationPreferences(appPrefs);
221 }
222 __CFSpinLock(&__CFApplicationPreferencesLock);
223
224 CFRelease(__CFStandardUserPreferences);
225 __CFStandardUserPreferences = NULL;
226 if(prefsArray != prefsBuf) _CFAllocatorDeallocateGC(alloc, prefsArray);
227 }
228 __CFSpinUnlock(&__CFApplicationPreferencesLock);
229 _CFPreferencesPurgeDomainCache();
230 }
231
232 // quick message to indicate that the given domain has changed, and we should go through and invalidate any dictReps that involve this domain.
233 void _CFApplicationPreferencesDomainHasChanged(CFPreferencesDomainRef changedDomain) {
234 CFAllocatorRef alloc = __CFPreferencesAllocator();
235 __CFSpinLock(&__CFApplicationPreferencesLock);
236 if(__CFStandardUserPreferences) { // only grovel over the prefs if there's something there to grovel
237 _CFApplicationPreferences **prefsArray, *prefsBuf[32];
238 CFIndex idx, count = CFDictionaryGetCount(__CFStandardUserPreferences);
239 if(count < 32) {
240 prefsArray = prefsBuf;
241 } else {
242 prefsArray = _CFAllocatorAllocateGC(alloc, count * sizeof(_CFApplicationPreferences *), 0);
243 }
244 CFDictionaryGetKeysAndValues(__CFStandardUserPreferences, NULL, (const void **)prefsArray);
245 // For this operation, giving up the lock is the last thing we want to do, so use the modified flavor of _CFApplicationPreferencesContainsDomain
246 for(idx = 0; idx < count; idx++) {
247 _CFApplicationPreferences *appPrefs = prefsArray[idx];
248 if(_CFApplicationPreferencesContainsDomainNoLock(appPrefs, changedDomain)) {
249 updateDictRep(appPrefs);
250 }
251 }
252 if(prefsArray != prefsBuf) _CFAllocatorDeallocateGC(alloc, prefsArray);
253 }
254 __CFSpinUnlock(&__CFApplicationPreferencesLock);
255 }
256
257
258 // Begin ported code from NSUserDefaults.m
259
260 /*************** Constants ***************/
261
262 // NSString * const NSUserDefaultsDidChangeNotification = @"NSUserDefaultsDidChangeNotification";
263
264 static void updateDictRep(_CFApplicationPreferences *self) {
265 if (self->_dictRep) {
266 CFRelease(self->_dictRep);
267 self->_dictRep = NULL;
268 }
269 }
270
271 static void __addKeysAndValues(const void *key, const void *value, void *context) {
272 CFDictionarySetValue(context, key, value);
273 }
274
275 static void computeDictRep(_CFApplicationPreferences *self) {
276 CFAllocatorRef alloc = __CFPreferencesAllocator();
277 CFMutableArrayRef searchList = self->_search;
278 CFIndex idx;
279 CFIndex cnt = CFArrayGetCount(searchList);
280 CFDictionaryRef subdomainDict;
281
282 if (self->_dictRep) {
283 CFRelease(self->_dictRep);
284 }
285 self->_dictRep = CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks);
286 _CFDictionarySetCapacity(self->_dictRep, 160); // avoid lots of rehashing
287
288 if (!self->_dictRep) return;
289 if (0 == cnt) return;
290
291 // For each subdomain triplet in the domain, iterate over dictionaries, adding them if necessary to the dictRep
292 for (idx = cnt; idx--;) {
293 CFPreferencesDomainRef domain = (CFPreferencesDomainRef)CFArrayGetValueAtIndex(searchList, idx);
294
295 if (!domain) continue;
296
297 subdomainDict = _CFPreferencesDomainDeepCopyDictionary(domain);
298 if(subdomainDict) {
299 CFDictionaryApplyFunction(subdomainDict, __addKeysAndValues, self->_dictRep);
300 CFRelease(subdomainDict);
301 }
302
303 if (__CFInsertionDomain == domain && __CFInsertion) {
304 CFDictionaryApplyFunction(__CFInsertion, __addKeysAndValues, self->_dictRep);
305 }
306 }
307 }
308
309 CFTypeRef _CFApplicationPreferencesSearchDownToDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef stopper, CFStringRef key) {
310 CFTypeRef value = NULL;
311 __CFSpinLock(&__CFApplicationPreferencesLock);
312 CFIndex idx, cnt;
313 cnt = CFArrayGetCount(self->_search);
314 for (idx = 0; idx < cnt; idx++) {
315 CFPreferencesDomainRef domain = (CFPreferencesDomainRef)CFArrayGetValueAtIndex(self->_search, idx);
316 if (domain == stopper) break;
317 value = _CFPreferencesDomainCreateValueForKey(domain, key);
318 if (value) break;
319 }
320 __CFSpinUnlock(&__CFApplicationPreferencesLock);
321 return value;
322 }
323
324
325 void _CFApplicationPreferencesUpdate(_CFApplicationPreferences *self) {
326 __CFSpinLock(&__CFApplicationPreferencesLock);
327 updateDictRep(self);
328 __CFSpinUnlock(&__CFApplicationPreferencesLock);
329 }
330
331 __private_extern__ CFDictionaryRef __CFApplicationPreferencesCopyCurrentState(void) {
332 CFDictionaryRef result;
333 _CFApplicationPreferences *self = _CFStandardApplicationPreferences(kCFPreferencesCurrentApplication);
334 __CFSpinLock(&__CFApplicationPreferencesLock);
335 if (!self->_dictRep) {
336 computeDictRep(self);
337 }
338 result = CFDictionaryCreateCopy(kCFAllocatorSystemDefault, self->_dictRep);
339 __CFSpinUnlock(&__CFApplicationPreferencesLock);
340 return result;
341 }
342
343 // CACHING here - we will only return a value as current as the last time computeDictRep() was called
344 CFTypeRef _CFApplicationPreferencesCreateValueForKey(_CFApplicationPreferences *self, CFStringRef defaultName) {
345 CFTypeRef result;
346 __CFSpinLock(&__CFApplicationPreferencesLock);
347 if (!self->_dictRep) {
348 computeDictRep(self);
349 }
350 result = (self->_dictRep) ? (CFTypeRef )CFDictionaryGetValue(self->_dictRep, defaultName) : NULL;
351 if (result) {
352 CFRetain(result);
353 }
354 __CFSpinUnlock(&__CFApplicationPreferencesLock);
355 return result;
356 }
357
358 void _CFApplicationPreferencesSet(_CFApplicationPreferences *self, CFStringRef defaultName, CFTypeRef value) {
359 CFPreferencesDomainRef applicationDomain;
360 void *defs = NULL;
361 __CFSpinLock(&userDefaultsLock);
362 defs = userDefaults;
363 __CFSpinUnlock(&userDefaultsLock);
364
365 CF_OBJC_KVO_WILLCHANGE(defs, defaultName);
366 __CFSpinLock(&__CFApplicationPreferencesLock);
367 applicationDomain = _CFPreferencesStandardDomain(self->_appName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
368 if(applicationDomain) {
369 _CFPreferencesDomainSet(applicationDomain, defaultName, value);
370 if (CFArrayContainsValue(self->_search, CFRangeMake(0, CFArrayGetCount(self->_search)), applicationDomain)) {
371 // Expensive; can't we just check the relevant value throughout the appropriate sets of domains? -- REW, 7/19/99
372 updateDictRep(self);
373 }
374 }
375 __CFSpinUnlock(&__CFApplicationPreferencesLock);
376 CF_OBJC_KVO_DIDCHANGE(defs, defaultName);
377 }
378
379 void _CFApplicationPreferencesRemove(_CFApplicationPreferences *self, CFStringRef defaultName) {
380 CFPreferencesDomainRef appDomain;
381 void *defs = NULL;
382 __CFSpinLock(&userDefaultsLock);
383 defs = userDefaults;
384 __CFSpinUnlock(&userDefaultsLock);
385 CF_OBJC_KVO_WILLCHANGE(defs, defaultName);
386 __CFSpinLock(&__CFApplicationPreferencesLock);
387 appDomain = _CFPreferencesStandardDomain(self->_appName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
388 if(appDomain) {
389 _CFPreferencesDomainSet(appDomain, defaultName, NULL);
390 if (CFArrayContainsValue(self->_search, CFRangeMake(0, CFArrayGetCount(self->_search)), appDomain)) {
391 // If key exists, it will be in the _dictRep (but possibly overridden)
392 updateDictRep(self);
393 }
394 }
395 __CFSpinUnlock(&__CFApplicationPreferencesLock);
396 CF_OBJC_KVO_DIDCHANGE(defs, defaultName);
397 }
398
399 static Boolean _CFApplicationPreferencesSynchronizeNoLock(_CFApplicationPreferences *self) {
400 Boolean success = _CFSynchronizeDomainCache();
401 if (self->_dictRep) {
402 CFRelease(self->_dictRep);
403 self->_dictRep = NULL;
404 }
405 return success;
406 }
407
408 Boolean _CFApplicationPreferencesSynchronize(_CFApplicationPreferences *self) {
409 Boolean result;
410 __CFPreferencesCheckFormatType();
411 __CFSpinLock(&__CFApplicationPreferencesLock);
412 result = _CFApplicationPreferencesSynchronizeNoLock(self);
413 __CFSpinUnlock(&__CFApplicationPreferencesLock);
414 return result;
415 }
416
417 // appName should not be kCFPreferencesCurrentApplication going in to this call
418 _CFApplicationPreferences *_CFApplicationPreferencesCreateWithUser(CFStringRef userName, CFStringRef appName) {
419 CFAllocatorRef alloc = __CFPreferencesAllocator();
420 _CFApplicationPreferences *self = CFAllocatorAllocate(alloc, sizeof(_CFApplicationPreferences), 0);
421 if (self) {
422 self->_dictRep = NULL;
423 self->_appName = CFRetain(appName);
424 self->_search = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
425 if (!self->_search) {
426 CFAllocatorDeallocate(alloc, self);
427 CFRelease(appName);
428 self = NULL;
429 }
430 }
431 return self;
432 }
433
434 // Do NOT release the domain after adding it to the array; domain_expression should not return a retained object -- REW, 8/26/99
435 #define ADD_DOMAIN(domain_expression) domain = domain_expression; if (domain) {CFArrayAppendValue(search, domain);}
436 void _CFApplicationPreferencesSetStandardSearchList(_CFApplicationPreferences *appPreferences) {
437 /* Now we add the standard domains; they are, in order:
438 this user, this app, this host
439 this user, this app, any host
440 this user, any app, this host
441 this user, any app, any host
442 any user, this app, this host
443 any user, this app, any host
444 any user, any app, this host
445 any user, any app, any host
446
447 note: for MacOS 8, we only add:
448 this user, this app, this host
449 this user, any app, this host
450 any user, this app, this host
451 any user, any app, this host
452 */
453 CFPreferencesDomainRef domain;
454 CFMutableArrayRef search = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
455 if (!search) {
456 // couldn't allocate memory!
457 return;
458 }
459
460 ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost));
461 ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost));
462 __CFInsertionDomain = _CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
463 ADD_DOMAIN(__CFInsertionDomain);
464 ADD_DOMAIN(_CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost));
465 ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesAnyUser, kCFPreferencesCurrentHost));
466 ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesAnyUser, kCFPreferencesAnyHost));
467 ADD_DOMAIN(_CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesAnyUser, kCFPreferencesCurrentHost));
468 ADD_DOMAIN(_CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesAnyUser, kCFPreferencesAnyHost));
469
470 _CFApplicationPreferencesSetSearchList(appPreferences, search);
471 CFRelease(search);
472 }
473 #undef ADD_DOMAIN
474
475
476 __private_extern__ _CFApplicationPreferences *_CFStandardApplicationPreferences(CFStringRef appName) {
477 _CFApplicationPreferences *appPreferences;
478 // CFAssert(appName != kCFPreferencesAnyApplication, __kCFLogAssertion, "Cannot use any of the CFPreferences...App... functions with an appName of kCFPreferencesAnyApplication");
479 __CFSpinLock(&__CFApplicationPreferencesLock);
480 if (!__CFStandardUserPreferences) {
481 __CFStandardUserPreferences = CFDictionaryCreateMutable(NULL, 0, & kCFTypeDictionaryKeyCallBacks, NULL);
482 }
483 if (!__CFStandardUserPreferences) {
484 // Couldn't create
485 __CFSpinUnlock(&__CFApplicationPreferencesLock);
486 return NULL;
487 }
488 if ((appPreferences = (_CFApplicationPreferences *)CFDictionaryGetValue(__CFStandardUserPreferences, appName)) == NULL ) {
489 appPreferences = _CFApplicationPreferencesCreateWithUser(kCFPreferencesCurrentUser, appName);
490 CFDictionarySetValue(__CFStandardUserPreferences, appName, appPreferences);
491 __CFSpinUnlock(&__CFApplicationPreferencesLock);
492 _CFApplicationPreferencesSetStandardSearchList(appPreferences);
493 } else {
494 __CFSpinUnlock(&__CFApplicationPreferencesLock);
495 }
496 return appPreferences;
497 }
498
499 // Exclusively for Foundation's use
500 void _CFApplicationPreferencesSetCacheForApp(_CFApplicationPreferences *appPrefs, CFStringRef appName) {
501 __CFSpinLock(&__CFApplicationPreferencesLock);
502 if (!__CFStandardUserPreferences) {
503 __CFStandardUserPreferences = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
504 CFDictionarySetValue(__CFStandardUserPreferences, appName, appPrefs);
505 __CFSpinUnlock(&__CFApplicationPreferencesLock);
506 } else {
507 _CFApplicationPreferences *oldPrefs = (_CFApplicationPreferences *)CFDictionaryGetValue(__CFStandardUserPreferences, appName);
508 CFDictionarySetValue(__CFStandardUserPreferences, appName, appPrefs);
509 __CFSpinUnlock(&__CFApplicationPreferencesLock);
510 if (oldPrefs) {
511 _CFDeallocateApplicationPreferences(oldPrefs);
512 }
513 }
514 }
515
516
517 void _CFDeallocateApplicationPreferences(_CFApplicationPreferences *self) {
518 CFAllocatorRef alloc = __CFPreferencesAllocator();
519 _CFApplicationPreferences *cachedPrefs = NULL;
520 __CFSpinLock(&__CFApplicationPreferencesLock);
521
522 // Get us out of the cache before destroying!
523 if (__CFStandardUserPreferences) {
524 cachedPrefs = (_CFApplicationPreferences *)CFDictionaryGetValue(__CFStandardUserPreferences, self->_appName);
525 }
526 if (cachedPrefs == self) {
527 CFDictionaryRemoveValue(__CFStandardUserPreferences, self->_appName);
528 }
529
530 if (self->_dictRep) CFRelease(self->_dictRep);
531 CFRelease(self->_search);
532 CFRelease(self->_appName);
533 CFAllocatorDeallocate(alloc, self);
534 __CFSpinUnlock(&__CFApplicationPreferencesLock);
535 }
536
537 // For Foundation's use
538 CFDictionaryRef _CFApplicationPreferencesCopyRepresentationWithHint(_CFApplicationPreferences *self, CFDictionaryRef hint) {
539 CFDictionaryRef dict;
540 __CFSpinLock(&__CFApplicationPreferencesLock);
541 if (!self->_dictRep) {
542 computeDictRep(self);
543 }
544 if (self->_dictRep && (self->_dictRep != hint)) {
545 CFRetain(self->_dictRep);
546 }
547 dict = self->_dictRep;
548 __CFSpinUnlock(&__CFApplicationPreferencesLock);
549 return dict;
550 }
551
552 // For Foundation's use; does not do what it would seem to from the name
553 CFDictionaryRef _CFApplicationPreferencesCopyRepresentation3(_CFApplicationPreferences *self, CFDictionaryRef hint, CFDictionaryRef insertion, CFPreferencesDomainRef afterDomain) {
554 __CFSpinLock(&__CFApplicationPreferencesLock);
555 if (0 == self && 0 == hint && 0 == afterDomain) {
556 // This is so so gross.
557 if (__CFInsertion) CFRelease(__CFInsertion);
558 __CFInsertion = insertion ? CFRetain(insertion) : NULL;
559 }
560 __CFSpinUnlock(&__CFApplicationPreferencesLock);
561 return 0;
562 }
563
564 CF_EXPORT
565 CFDictionaryRef _CFApplicationPreferencesCopyRepresentation(_CFApplicationPreferences *self) {
566 return _CFApplicationPreferencesCopyRepresentationWithHint(self, NULL);
567 }
568
569 __private_extern__ void _CFApplicationPreferencesSetSearchList(_CFApplicationPreferences *self, CFArrayRef newSearchList) {
570 CFIndex idx, count;
571 __CFSpinLock(&__CFApplicationPreferencesLock);
572 CFArrayRemoveAllValues(self->_search);
573 count = CFArrayGetCount(newSearchList);
574 for (idx = 0; idx < count; idx ++) {
575 CFArrayAppendValue(self->_search, CFArrayGetValueAtIndex(newSearchList, idx));
576 }
577 updateDictRep(self);
578 __CFSpinUnlock(&__CFApplicationPreferencesLock);
579 }
580
581 void CFPreferencesAddSuitePreferencesToApp(CFStringRef appName, CFStringRef suiteName) {
582 _CFApplicationPreferences *appPrefs;
583
584 appPrefs = _CFStandardApplicationPreferences(appName);
585 _CFApplicationPreferencesAddSuitePreferences(appPrefs, suiteName);
586 }
587
588 void _CFApplicationPreferencesAddSuitePreferences(_CFApplicationPreferences *appPrefs, CFStringRef suiteName) {
589 CFPreferencesDomainRef domain;
590 CFIndex idx;
591 CFRange range;
592
593 // Find where to insert the new suite
594 __CFSpinLock(&__CFApplicationPreferencesLock);
595 domain = _CFPreferencesStandardDomain(appPrefs->_appName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
596 range.location = 0;
597 range.length = CFArrayGetCount(appPrefs->_search);
598 idx = domain ? CFArrayGetFirstIndexOfValue(appPrefs->_search, range, domain) : kCFNotFound;
599 __CFSpinUnlock(&__CFApplicationPreferencesLock);
600 idx ++; // We want just below the app domain. Coincidentally, this gives us the top of the list if the app domain has been removed.
601 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
602 if (domain) {
603 __CFSpinLock(&__CFApplicationPreferencesLock);
604 CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain);
605 __CFSpinUnlock(&__CFApplicationPreferencesLock);
606 range.length ++;
607 }
608 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
609 if (domain) {
610 __CFSpinLock(&__CFApplicationPreferencesLock);
611 CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain);
612 __CFSpinUnlock(&__CFApplicationPreferencesLock);
613 range.length ++;
614 }
615
616 // Now the AnyUser domains
617 domain = _CFPreferencesStandardDomain(appPrefs->_appName, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
618 idx = domain ? CFArrayGetFirstIndexOfValue(appPrefs->_search, range, domain) : kCFNotFound;
619 if (idx == kCFNotFound) {
620 // Someone blew away the app domain. Can only happen through -[NSUserDefaults setSearchList:]. For the any user case, we look for right below the global domain
621 // Can this happen anymore? -[NSUserDefaults setSearchList:] is bailing. -- ctp - - 3 Jan 2002
622 domain = _CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
623 idx = domain ? CFArrayGetFirstIndexOfValue(appPrefs->_search, range, domain) : kCFNotFound;
624 if (idx == kCFNotFound) {
625 // Try the "any host" choice
626 domain = _CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
627 idx = domain ? CFArrayGetFirstIndexOfValue(appPrefs->_search, range, domain) : kCFNotFound;
628 if (idx == kCFNotFound) {
629 // We give up; put the new domains at the bottom
630 idx = CFArrayGetCount(appPrefs->_search) - 1;
631 }
632 }
633 }
634 idx ++;
635 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
636 if (domain) {
637 __CFSpinLock(&__CFApplicationPreferencesLock);
638 CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain);
639 __CFSpinUnlock(&__CFApplicationPreferencesLock);
640 }
641 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
642 if (domain) {
643 __CFSpinLock(&__CFApplicationPreferencesLock);
644 CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain);
645 __CFSpinUnlock(&__CFApplicationPreferencesLock);
646 }
647 __CFSpinLock(&__CFApplicationPreferencesLock);
648 updateDictRep(appPrefs);
649 __CFSpinUnlock(&__CFApplicationPreferencesLock);
650 }
651
652 void CFPreferencesRemoveSuitePreferencesFromApp(CFStringRef appName, CFStringRef suiteName) {
653 _CFApplicationPreferences *appPrefs;
654
655 appPrefs = _CFStandardApplicationPreferences(appName);
656
657 _CFApplicationPreferencesRemoveSuitePreferences(appPrefs, suiteName);
658 }
659
660 void _CFApplicationPreferencesRemoveSuitePreferences(_CFApplicationPreferences *appPrefs, CFStringRef suiteName) {
661 CFPreferencesDomainRef domain;
662
663 __CFSpinLock(&__CFApplicationPreferencesLock);
664 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
665 __CFSpinUnlock(&__CFApplicationPreferencesLock);
666 if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain);
667
668 __CFSpinLock(&__CFApplicationPreferencesLock);
669 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
670 __CFSpinUnlock(&__CFApplicationPreferencesLock);
671 if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain);
672
673 __CFSpinLock(&__CFApplicationPreferencesLock);
674 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
675 __CFSpinUnlock(&__CFApplicationPreferencesLock);
676 if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain);
677
678 __CFSpinLock(&__CFApplicationPreferencesLock);
679 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
680 __CFSpinUnlock(&__CFApplicationPreferencesLock);
681 if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain);
682 }
683
684 void _CFApplicationPreferencesAddDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef domain, Boolean addAtTop) {
685 __CFSpinLock(&__CFApplicationPreferencesLock);
686 if (addAtTop) {
687 CFArrayInsertValueAtIndex(self->_search, 0, domain);
688 } else {
689 CFArrayAppendValue(self->_search, domain);
690 }
691 updateDictRep(self);
692 __CFSpinUnlock(&__CFApplicationPreferencesLock);
693 }
694
695 Boolean _CFApplicationPreferencesContainsDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef domain) {
696 Boolean result;
697 __CFSpinLock(&__CFApplicationPreferencesLock);
698 result = CFArrayContainsValue(self->_search, CFRangeMake(0, CFArrayGetCount(self->_search)), domain);
699 __CFSpinUnlock(&__CFApplicationPreferencesLock);
700 return result;
701 }
702
703 Boolean _CFApplicationPreferencesContainsDomainNoLock(_CFApplicationPreferences *self, CFPreferencesDomainRef domain) {
704 Boolean result;
705 result = CFArrayContainsValue(self->_search, CFRangeMake(0, CFArrayGetCount(self->_search)), domain);
706 return result;
707 }
708
709 void _CFApplicationPreferencesRemoveDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef domain) {
710 CFIndex idx;
711 CFRange range;
712 __CFSpinLock(&__CFApplicationPreferencesLock);
713 range.location = 0;
714 range.length = CFArrayGetCount(self->_search);
715 while ((idx = CFArrayGetFirstIndexOfValue(self->_search, range, domain)) != kCFNotFound) {
716 CFArrayRemoveValueAtIndex(self->_search, idx);
717 range.location = idx;
718 range.length = range.length - idx - 1;
719 }
720 updateDictRep(self);
721 __CFSpinUnlock(&__CFApplicationPreferencesLock);
722 }
723
724