source: trunk/Sparkle/SUHost.m @ 1046

Revision 1044, 7.2 KB checked in by speck, 4 months ago (diff)

2 minor clang fixes.

Line 
1//
2//  SUHost.m
3//  Sparkle
4//
5//  Copyright 2008 Andy Matuschak. All rights reserved.
6//
7
8#import "SUHost.h"
9
10#import "SUSystemProfiler.h"
11#import <sys/mount.h> // For statfs for isRunningOnReadOnlyVolume
12
13@implementation SUHost
14
15- (id)initWithBundle:(NSBundle *)aBundle
16{
17    if (aBundle == nil) aBundle = [NSBundle mainBundle];
18    if ((self = [super init]))
19    {
20        bundle = [aBundle retain];
21        if (![bundle bundleIdentifier])
22            NSLog(@"Sparkle Error: the bundle being updated at %@ has no CFBundleIdentifier! This will cause preference read/write to not work properly.", [bundle bundlePath]);
23    }
24    return self;
25}
26
27- (void)dealloc
28{
29    [bundle release];
30    [super dealloc];
31}
32
33- (NSString *)description { return [NSString stringWithFormat:@"%@ <%@>", [self class], [self bundlePath]]; }
34
35- (NSBundle *)bundle
36{
37    return bundle;
38}
39
40- (NSString *)bundlePath
41{
42    return [bundle bundlePath];
43}
44
45- (NSString *)name
46{
47    NSString *name = [bundle objectForInfoDictionaryKey:@"CFBundleDisplayName"];
48    if (name) return name;
49   
50    name = [self objectForInfoDictionaryKey:@"CFBundleName"];
51    if (name) return name;
52   
53    return [[[NSFileManager defaultManager] displayNameAtPath:[bundle bundlePath]] stringByDeletingPathExtension];
54}
55
56- (NSString *)version
57{
58    return [bundle objectForInfoDictionaryKey:@"CFBundleVersion"];
59}
60
61- (NSString *)displayVersion
62{
63    NSString *shortVersionString = [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
64    if (shortVersionString)
65        return shortVersionString;
66    else
67        return [self version]; // Fall back on the normal version string.
68}
69
70- (NSImage *)icon
71{
72    // Cache the application icon.
73    NSString *iconPath = [bundle pathForResource:[bundle objectForInfoDictionaryKey:@"CFBundleIconFile"] ofType:@"icns"];
74    // According to the OS X docs, "CFBundleIconFile - This key identifies the file containing
75    // the icon for the bundle. The filename you specify does not need to include the .icns
76    // extension, although it may."
77    //
78    // However, if it *does* include the '.icns' the above method fails (tested on OS X 10.3.9) so we'll also try:
79    if (!iconPath)
80        iconPath = [bundle pathForResource:[bundle objectForInfoDictionaryKey:@"CFBundleIconFile"] ofType: nil];
81    NSImage *icon = [[[NSImage alloc] initWithContentsOfFile:iconPath] autorelease];
82    // Use a default icon if none is defined.
83    if (!icon) { icon = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGenericApplicationIcon)]; }
84    return icon;
85}
86
87- (BOOL)isRunningOnReadOnlyVolume
88{   
89    struct statfs statfs_info;
90    statfs([[bundle bundlePath] fileSystemRepresentation], &statfs_info);
91    return (statfs_info.f_flags & MNT_RDONLY);
92}
93
94- (BOOL)isBackgroundApplication
95{
96    ProcessSerialNumber PSN;
97    GetCurrentProcess(&PSN);
98    NSDictionary * processInfo = (NSDictionary *)ProcessInformationCopyDictionary(&PSN, kProcessDictionaryIncludeAllInformationMask);
99    BOOL isElement = [[processInfo objectForKey:@"LSUIElement"] boolValue];
100    if (processInfo)
101        CFRelease(processInfo);
102    return isElement;
103}
104
105- (NSString *)publicDSAKey
106{
107    // Maybe the key is just a string in the Info.plist.
108    NSString *key = [bundle objectForInfoDictionaryKey:SUPublicDSAKeyKey];
109    if (key) { return key; }
110   
111    // More likely, we've got a reference to a Resources file by filename:
112    NSString *keyFilename = [self objectForInfoDictionaryKey:SUPublicDSAKeyFileKey];
113    if (!keyFilename) { return nil; }
114    NSError *ignoreErr;
115    return [NSString stringWithContentsOfFile:[bundle pathForResource:keyFilename ofType:nil] encoding:NSASCIIStringEncoding error: &ignoreErr];
116}
117
118- (NSArray *)systemProfile
119{
120    return [[SUSystemProfiler sharedSystemProfiler] systemProfileArrayForHost:self];
121}
122
123- (id)objectForInfoDictionaryKey:(NSString *)key
124{
125    return [bundle objectForInfoDictionaryKey:key];
126}
127
128- (BOOL)boolForInfoDictionaryKey:(NSString *)key
129{
130    return [[self objectForInfoDictionaryKey:key] boolValue];
131}
132
133- (id)objectForUserDefaultsKey:(NSString *)defaultName
134{
135    // Under Tiger, CFPreferencesCopyAppValue doesn't get values from NSRegistratioDomain, so anything
136    // passed into -[NSUserDefaults registerDefaults:] is ignored.  The following line falls
137    // back to using NSUserDefaults, but only if the host bundle is the main bundle.
138    if (bundle == [NSBundle mainBundle])
139        return [[NSUserDefaults standardUserDefaults] objectForKey:defaultName];
140   
141    CFPropertyListRef obj = CFPreferencesCopyAppValue((CFStringRef)defaultName, (CFStringRef)[bundle bundleIdentifier]);
142#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
143    return [NSMakeCollectable(obj) autorelease];
144#else
145    return [(id)obj autorelease];
146#endif 
147}
148
149- (void)setObject:(id)value forUserDefaultsKey:(NSString *)defaultName;
150{
151    // If we're using a .app, we'll use the standard user defaults mechanism; otherwise, we have to get CF-y.
152    if (bundle == [NSBundle mainBundle])
153    {
154        [[NSUserDefaults standardUserDefaults] setObject:value forKey:defaultName];
155    }
156    else
157    {
158        CFPreferencesSetValue((CFStringRef)defaultName, value, (CFStringRef)[bundle bundleIdentifier],  kCFPreferencesCurrentUser,  kCFPreferencesAnyHost);
159        CFPreferencesSynchronize((CFStringRef)[bundle bundleIdentifier], kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
160    }
161}
162
163- (BOOL)boolForUserDefaultsKey:(NSString *)defaultName
164{
165    if (bundle == [NSBundle mainBundle])
166        return [[NSUserDefaults standardUserDefaults] boolForKey:defaultName];
167   
168    BOOL value;
169    CFPropertyListRef plr = CFPreferencesCopyAppValue((CFStringRef)defaultName, (CFStringRef)[bundle bundleIdentifier]);
170    if (plr == NULL)
171        value = NO;
172    else
173    {
174        value = (BOOL)CFBooleanGetValue((CFBooleanRef)plr);
175        CFRelease(plr);
176    }
177    return value;
178}
179
180- (void)setBool:(BOOL)value forUserDefaultsKey:(NSString *)defaultName
181{
182    // If we're using a .app, we'll use the standard user defaults mechanism; otherwise, we have to get CF-y.
183    if (bundle == [NSBundle mainBundle])
184    {
185        [[NSUserDefaults standardUserDefaults] setBool:value forKey:defaultName];
186    }
187    else
188    {
189        CFPreferencesSetValue((CFStringRef)defaultName, (CFBooleanRef)[NSNumber numberWithBool:value], (CFStringRef)[bundle bundleIdentifier],  kCFPreferencesCurrentUser,  kCFPreferencesAnyHost);
190        CFPreferencesSynchronize((CFStringRef)[bundle bundleIdentifier], kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
191    }
192}
193
194- (id)objectForKey:(NSString *)key {
195    return [self objectForUserDefaultsKey:key] ?: [self objectForInfoDictionaryKey:key];
196}
197
198- (BOOL)boolForKey:(NSString *)key {
199    return [self objectForUserDefaultsKey:key] ? [self boolForUserDefaultsKey:key] : [self boolForInfoDictionaryKey:key];
200}
201
202+ (NSString *)systemVersionString
203{
204    // This returns a version string of the form X.Y.Z
205    // There may be a better way to deal with the problem that gestaltSystemVersionMajor
206    //  et al. are not defined in 10.3, but this is probably good enough.
207    NSString* verStr = nil;
208#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4
209    SInt32 major, minor, bugfix;
210    OSErr err1 = Gestalt(gestaltSystemVersionMajor, &major);
211    OSErr err2 = Gestalt(gestaltSystemVersionMinor, &minor);
212    OSErr err3 = Gestalt(gestaltSystemVersionBugFix, &bugfix);
213    if (!err1 && !err2 && !err3)
214    {
215        verStr = [NSString stringWithFormat:@"%d.%d.%d", major, minor, bugfix];
216    }
217    else
218#endif
219    {
220        NSString *versionPlistPath = @"/System/Library/CoreServices/SystemVersion.plist";
221        verStr = [[[NSDictionary dictionaryWithContentsOfFile:versionPlistPath] objectForKey:@"ProductVersion"] retain];
222    }
223    return verStr;
224}
225
226@end
Note: See TracBrowser for help on using the repository browser.