]> git.saurik.com Git - apple/cf.git/blob - Preferences.subproj/CFApplicationPreferences.c
CF-368.1.tar.gz
[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 __CFSpinLock(&__CFApplicationPreferencesLock);
382 appDomain = _CFPreferencesStandardDomain(self->_appName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
383 if(appDomain) {
384 _CFPreferencesDomainSet(appDomain, defaultName, NULL);
385 if (CFArrayContainsValue(self->_search, CFRangeMake(0, CFArrayGetCount(self->_search)), appDomain)) {
386 // If key exists, it will be in the _dictRep (but possibly overridden)
387 updateDictRep(self);
388 }
389 }
390 __CFSpinUnlock(&__CFApplicationPreferencesLock);
391 }
392
393 static Boolean _CFApplicationPreferencesSynchronizeNoLock(_CFApplicationPreferences *self) {
394 Boolean success = _CFSynchronizeDomainCache();
395 if (self->_dictRep) {
396 CFRelease(self->_dictRep);
397 self->_dictRep = NULL;
398 }
399 return success;
400 }
401
402 Boolean _CFApplicationPreferencesSynchronize(_CFApplicationPreferences *self) {
403 Boolean result;
404 __CFPreferencesCheckFormatType();
405 __CFSpinLock(&__CFApplicationPreferencesLock);
406 result = _CFApplicationPreferencesSynchronizeNoLock(self);
407 __CFSpinUnlock(&__CFApplicationPreferencesLock);
408 return result;
409 }
410
411 // appName should not be kCFPreferencesCurrentApplication going in to this call
412 _CFApplicationPreferences *_CFApplicationPreferencesCreateWithUser(CFStringRef userName, CFStringRef appName) {
413 CFAllocatorRef alloc = __CFPreferencesAllocator();
414 _CFApplicationPreferences *self = CFAllocatorAllocate(alloc, sizeof(_CFApplicationPreferences), 0);
415 if (self) {
416 self->_dictRep = NULL;
417 self->_appName = CFRetain(appName);
418 self->_search = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
419 if (!self->_search) {
420 CFAllocatorDeallocate(alloc, self);
421 CFRelease(appName);
422 self = NULL;
423 }
424 }
425 return self;
426 }
427
428 // Do NOT release the domain after adding it to the array; domain_expression should not return a retained object -- REW, 8/26/99
429 #define ADD_DOMAIN(domain_expression) domain = domain_expression; if (domain) {CFArrayAppendValue(search, domain);}
430 void _CFApplicationPreferencesSetStandardSearchList(_CFApplicationPreferences *appPreferences) {
431 /* Now we add the standard domains; they are, in order:
432 this user, this app, this host
433 this user, this app, any host
434 this user, any app, this host
435 this user, any app, any host
436 any user, this app, this host
437 any user, this app, any host
438 any user, any app, this host
439 any user, any app, any host
440
441 note: for MacOS 8, we only add:
442 this user, this app, this host
443 this user, any app, this host
444 any user, this app, this host
445 any user, any app, this host
446 */
447 CFPreferencesDomainRef domain;
448 CFMutableArrayRef search = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
449 if (!search) {
450 // couldn't allocate memory!
451 return;
452 }
453
454 ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost));
455 ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost));
456 __CFInsertionDomain = _CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
457 ADD_DOMAIN(__CFInsertionDomain);
458 ADD_DOMAIN(_CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost));
459 ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesAnyUser, kCFPreferencesCurrentHost));
460 ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesAnyUser, kCFPreferencesAnyHost));
461 ADD_DOMAIN(_CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesAnyUser, kCFPreferencesCurrentHost));
462 ADD_DOMAIN(_CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesAnyUser, kCFPreferencesAnyHost));
463
464 _CFApplicationPreferencesSetSearchList(appPreferences, search);
465 CFRelease(search);
466 }
467 #undef ADD_DOMAIN
468
469
470 __private_extern__ _CFApplicationPreferences *_CFStandardApplicationPreferences(CFStringRef appName) {
471 _CFApplicationPreferences *appPreferences;
472 // CFAssert(appName != kCFPreferencesAnyApplication, __kCFLogAssertion, "Cannot use any of the CFPreferences...App... functions with an appName of kCFPreferencesAnyApplication");
473 __CFSpinLock(&__CFApplicationPreferencesLock);
474 if (!__CFStandardUserPreferences) {
475 __CFStandardUserPreferences = CFDictionaryCreateMutable(NULL, 0, & kCFTypeDictionaryKeyCallBacks, NULL);
476 }
477 if (!__CFStandardUserPreferences) {
478 // Couldn't create
479 __CFSpinUnlock(&__CFApplicationPreferencesLock);
480 return NULL;
481 }
482 if ((appPreferences = (_CFApplicationPreferences *)CFDictionaryGetValue(__CFStandardUserPreferences, appName)) == NULL ) {
483 appPreferences = _CFApplicationPreferencesCreateWithUser(kCFPreferencesCurrentUser, appName);
484 CFDictionarySetValue(__CFStandardUserPreferences, appName, appPreferences);
485 __CFSpinUnlock(&__CFApplicationPreferencesLock);
486 _CFApplicationPreferencesSetStandardSearchList(appPreferences);
487 } else {
488 __CFSpinUnlock(&__CFApplicationPreferencesLock);
489 }
490 return appPreferences;
491 }
492
493 // Exclusively for Foundation's use
494 void _CFApplicationPreferencesSetCacheForApp(_CFApplicationPreferences *appPrefs, CFStringRef appName) {
495 __CFSpinLock(&__CFApplicationPreferencesLock);
496 if (!__CFStandardUserPreferences) {
497 __CFStandardUserPreferences = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
498 CFDictionarySetValue(__CFStandardUserPreferences, appName, appPrefs);
499 __CFSpinUnlock(&__CFApplicationPreferencesLock);
500 } else {
501 _CFApplicationPreferences *oldPrefs = (_CFApplicationPreferences *)CFDictionaryGetValue(__CFStandardUserPreferences, appName);
502 CFDictionarySetValue(__CFStandardUserPreferences, appName, appPrefs);
503 __CFSpinUnlock(&__CFApplicationPreferencesLock);
504 if (oldPrefs) {
505 _CFDeallocateApplicationPreferences(oldPrefs);
506 }
507 }
508 }
509
510
511 void _CFDeallocateApplicationPreferences(_CFApplicationPreferences *self) {
512 CFAllocatorRef alloc = __CFPreferencesAllocator();
513 _CFApplicationPreferences *cachedPrefs = NULL;
514 __CFSpinLock(&__CFApplicationPreferencesLock);
515
516 // Get us out of the cache before destroying!
517 if (__CFStandardUserPreferences) {
518 cachedPrefs = (_CFApplicationPreferences *)CFDictionaryGetValue(__CFStandardUserPreferences, self->_appName);
519 }
520 if (cachedPrefs == self) {
521 CFDictionaryRemoveValue(__CFStandardUserPreferences, self->_appName);
522 }
523
524 if (self->_dictRep) CFRelease(self->_dictRep);
525 CFRelease(self->_search);
526 CFRelease(self->_appName);
527 CFAllocatorDeallocate(alloc, self);
528 __CFSpinUnlock(&__CFApplicationPreferencesLock);
529 }
530
531 // For Foundation's use
532 CFDictionaryRef _CFApplicationPreferencesCopyRepresentationWithHint(_CFApplicationPreferences *self, CFDictionaryRef hint) {
533 CFDictionaryRef dict;
534 __CFSpinLock(&__CFApplicationPreferencesLock);
535 if (!self->_dictRep) {
536 computeDictRep(self);
537 }
538 if (self->_dictRep && (self->_dictRep != hint)) {
539 CFRetain(self->_dictRep);
540 }
541 dict = self->_dictRep;
542 __CFSpinUnlock(&__CFApplicationPreferencesLock);
543 return dict;
544 }
545
546 // For Foundation's use; does not do what it would seem to from the name
547 CFDictionaryRef _CFApplicationPreferencesCopyRepresentation3(_CFApplicationPreferences *self, CFDictionaryRef hint, CFDictionaryRef insertion, CFPreferencesDomainRef afterDomain) {
548 __CFSpinLock(&__CFApplicationPreferencesLock);
549 if (0 == self && 0 == hint && 0 == afterDomain) {
550 // This is so so gross.
551 if (__CFInsertion) CFRelease(__CFInsertion);
552 __CFInsertion = insertion ? CFRetain(insertion) : NULL;
553 }
554 __CFSpinUnlock(&__CFApplicationPreferencesLock);
555 return 0;
556 }
557
558 CF_EXPORT
559 CFDictionaryRef _CFApplicationPreferencesCopyRepresentation(_CFApplicationPreferences *self) {
560 return _CFApplicationPreferencesCopyRepresentationWithHint(self, NULL);
561 }
562
563 __private_extern__ void _CFApplicationPreferencesSetSearchList(_CFApplicationPreferences *self, CFArrayRef newSearchList) {
564 CFIndex idx, count;
565 __CFSpinLock(&__CFApplicationPreferencesLock);
566 CFArrayRemoveAllValues(self->_search);
567 count = CFArrayGetCount(newSearchList);
568 for (idx = 0; idx < count; idx ++) {
569 CFArrayAppendValue(self->_search, CFArrayGetValueAtIndex(newSearchList, idx));
570 }
571 updateDictRep(self);
572 __CFSpinUnlock(&__CFApplicationPreferencesLock);
573 }
574
575 void CFPreferencesAddSuitePreferencesToApp(CFStringRef appName, CFStringRef suiteName) {
576 _CFApplicationPreferences *appPrefs;
577
578 appPrefs = _CFStandardApplicationPreferences(appName);
579 _CFApplicationPreferencesAddSuitePreferences(appPrefs, suiteName);
580 }
581
582 void _CFApplicationPreferencesAddSuitePreferences(_CFApplicationPreferences *appPrefs, CFStringRef suiteName) {
583 CFPreferencesDomainRef domain;
584 CFIndex idx;
585 CFRange range;
586
587 // Find where to insert the new suite
588 __CFSpinLock(&__CFApplicationPreferencesLock);
589 domain = _CFPreferencesStandardDomain(appPrefs->_appName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
590 range.location = 0;
591 range.length = CFArrayGetCount(appPrefs->_search);
592 idx = domain ? CFArrayGetFirstIndexOfValue(appPrefs->_search, range, domain) : kCFNotFound;
593 __CFSpinUnlock(&__CFApplicationPreferencesLock);
594 idx ++; // We want just below the app domain. Coincidentally, this gives us the top of the list if the app domain has been removed.
595 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
596 if (domain) {
597 __CFSpinLock(&__CFApplicationPreferencesLock);
598 CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain);
599 __CFSpinUnlock(&__CFApplicationPreferencesLock);
600 range.length ++;
601 }
602 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
603 if (domain) {
604 __CFSpinLock(&__CFApplicationPreferencesLock);
605 CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain);
606 __CFSpinUnlock(&__CFApplicationPreferencesLock);
607 range.length ++;
608 }
609
610 // Now the AnyUser domains
611 domain = _CFPreferencesStandardDomain(appPrefs->_appName, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
612 idx = domain ? CFArrayGetFirstIndexOfValue(appPrefs->_search, range, domain) : kCFNotFound;
613 if (idx == kCFNotFound) {
614 // 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
615 // Can this happen anymore? -[NSUserDefaults setSearchList:] is bailing. -- ctp - - 3 Jan 2002
616 domain = _CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
617 idx = domain ? CFArrayGetFirstIndexOfValue(appPrefs->_search, range, domain) : kCFNotFound;
618 if (idx == kCFNotFound) {
619 // Try the "any host" choice
620 domain = _CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
621 idx = domain ? CFArrayGetFirstIndexOfValue(appPrefs->_search, range, domain) : kCFNotFound;
622 if (idx == kCFNotFound) {
623 // We give up; put the new domains at the bottom
624 idx = CFArrayGetCount(appPrefs->_search) - 1;
625 }
626 }
627 }
628 idx ++;
629 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
630 if (domain) {
631 __CFSpinLock(&__CFApplicationPreferencesLock);
632 CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain);
633 __CFSpinUnlock(&__CFApplicationPreferencesLock);
634 }
635 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
636 if (domain) {
637 __CFSpinLock(&__CFApplicationPreferencesLock);
638 CFArrayInsertValueAtIndex(appPrefs->_search, idx, domain);
639 __CFSpinUnlock(&__CFApplicationPreferencesLock);
640 }
641 __CFSpinLock(&__CFApplicationPreferencesLock);
642 updateDictRep(appPrefs);
643 __CFSpinUnlock(&__CFApplicationPreferencesLock);
644 }
645
646 void CFPreferencesRemoveSuitePreferencesFromApp(CFStringRef appName, CFStringRef suiteName) {
647 _CFApplicationPreferences *appPrefs;
648
649 appPrefs = _CFStandardApplicationPreferences(appName);
650
651 _CFApplicationPreferencesRemoveSuitePreferences(appPrefs, suiteName);
652 }
653
654 void _CFApplicationPreferencesRemoveSuitePreferences(_CFApplicationPreferences *appPrefs, CFStringRef suiteName) {
655 CFPreferencesDomainRef domain;
656
657 __CFSpinLock(&__CFApplicationPreferencesLock);
658 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
659 __CFSpinUnlock(&__CFApplicationPreferencesLock);
660 if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain);
661
662 __CFSpinLock(&__CFApplicationPreferencesLock);
663 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
664 __CFSpinUnlock(&__CFApplicationPreferencesLock);
665 if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain);
666
667 __CFSpinLock(&__CFApplicationPreferencesLock);
668 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
669 __CFSpinUnlock(&__CFApplicationPreferencesLock);
670 if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain);
671
672 __CFSpinLock(&__CFApplicationPreferencesLock);
673 domain = _CFPreferencesStandardDomain(suiteName, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
674 __CFSpinUnlock(&__CFApplicationPreferencesLock);
675 if (domain) _CFApplicationPreferencesRemoveDomain(appPrefs, domain);
676 }
677
678 void _CFApplicationPreferencesAddDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef domain, Boolean addAtTop) {
679 __CFSpinLock(&__CFApplicationPreferencesLock);
680 if (addAtTop) {
681 CFArrayInsertValueAtIndex(self->_search, 0, domain);
682 } else {
683 CFArrayAppendValue(self->_search, domain);
684 }
685 updateDictRep(self);
686 __CFSpinUnlock(&__CFApplicationPreferencesLock);
687 }
688
689 Boolean _CFApplicationPreferencesContainsDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef domain) {
690 Boolean result;
691 __CFSpinLock(&__CFApplicationPreferencesLock);
692 result = CFArrayContainsValue(self->_search, CFRangeMake(0, CFArrayGetCount(self->_search)), domain);
693 __CFSpinUnlock(&__CFApplicationPreferencesLock);
694 return result;
695 }
696
697 Boolean _CFApplicationPreferencesContainsDomainNoLock(_CFApplicationPreferences *self, CFPreferencesDomainRef domain) {
698 Boolean result;
699 result = CFArrayContainsValue(self->_search, CFRangeMake(0, CFArrayGetCount(self->_search)), domain);
700 return result;
701 }
702
703 void _CFApplicationPreferencesRemoveDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef domain) {
704 CFIndex idx;
705 CFRange range;
706 __CFSpinLock(&__CFApplicationPreferencesLock);
707 range.location = 0;
708 range.length = CFArrayGetCount(self->_search);
709 while ((idx = CFArrayGetFirstIndexOfValue(self->_search, range, domain)) != kCFNotFound) {
710 CFArrayRemoveValueAtIndex(self->_search, idx);
711 range.location = idx;
712 range.length = range.length - idx - 1;
713 }
714 updateDictRep(self);
715 __CFSpinUnlock(&__CFApplicationPreferencesLock);
716 }
717
718