PageRenderTime 73ms CodeModel.GetById 16ms app.highlight 53ms RepoModel.GetById 1ms app.codeStats 0ms

/core/externals/update-engine/externals/google-toolbox-for-mac/AppKit/GTMLoginItems.m

http://macfuse.googlecode.com/
Objective C | 342 lines | 268 code | 29 blank | 45 comment | 56 complexity | 6794bcb4adac07b3bbfa11041df248f5 MD5 | raw file
  1//
  2//  GTMLoginItems.m
  3//  Based on AELoginItems from DTS.
  4//
  5//  Copyright 2007-2008 Google Inc.
  6//
  7//  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  8//  use this file except in compliance with the License.  You may obtain a copy
  9//  of the License at
 10//
 11//  http://www.apache.org/licenses/LICENSE-2.0
 12//
 13//  Unless required by applicable law or agreed to in writing, software
 14//  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 15//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 16//  License for the specific language governing permissions and limitations under
 17//  the License.
 18//
 19
 20#import "GTMLoginItems.h"
 21#import "GTMDefines.h"
 22
 23#include <Carbon/Carbon.h>
 24
 25// Exposed constants
 26NSString * const kGTMLoginItemsNameKey = @"Name";
 27NSString * const kGTMLoginItemsPathKey = @"Path";
 28NSString * const kGTMLoginItemsHiddenKey = @"Hide";
 29
 30// kLSSharedFileListLoginItemHidden is supported on
 31// 10.5, but missing from the 10.5 headers.
 32// http://openradar.appspot.com/6482251
 33#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
 34static NSString * const kLSSharedFileListLoginItemHidden =
 35    @"com.apple.loginitem.HideOnLaunch";
 36#endif  // MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
 37
 38@interface GTMLoginItems (PrivateMethods)
 39+ (NSInteger)indexOfLoginItemWithValue:(id)value
 40                                forKey:(NSString *)key
 41                            loginItems:(NSArray *)items;
 42#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
 43+ (LSSharedFileListRef)loginItemsFileListRef;
 44+ (NSArray *)loginItemsArrayForFileListRef:(LSSharedFileListRef)fileListRef;
 45#else  // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
 46+ (BOOL)compileAndRunScript:(NSString *)script
 47                  withError:(NSError **)errorInfo;
 48#endif  // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
 49@end
 50
 51@implementation GTMLoginItems (PrivateMethods)
 52
 53+ (NSInteger)indexOfLoginItemWithValue:(id)value
 54                                forKey:(NSString *)key
 55                            loginItems:(NSArray *)items {
 56  if (!value || !key || !items) return NSNotFound;
 57  NSDictionary *item = nil;
 58  NSInteger found = -1;
 59  GTM_FOREACH_OBJECT(item, items) {
 60    ++found;
 61    id itemValue = [item objectForKey:key];
 62    if (itemValue && [itemValue isEqual:value]) {
 63      return found;
 64    }
 65  }
 66  return NSNotFound;
 67}
 68
 69#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
 70
 71+ (LSSharedFileListRef)loginItemsFileListRef {
 72  LSSharedFileListRef loginItemsRef =
 73      LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
 74  return (LSSharedFileListRef)GTMCFAutorelease(loginItemsRef);
 75}
 76
 77+ (NSArray *)loginItemsArrayForFileListRef:(LSSharedFileListRef)fileListRef {
 78  UInt32 seedValue;
 79  CFArrayRef filelistArrayRef = LSSharedFileListCopySnapshot(fileListRef,
 80                                                        &seedValue);
 81  return GTMCFAutorelease(filelistArrayRef);
 82}
 83
 84#else  // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
 85
 86+ (BOOL)compileAndRunScript:(NSString *)script
 87                  withError:(NSError **)errorInfo {
 88  if ([script length] == 0) {
 89    // COV_NF_START - no real way to test this
 90    if (errorInfo)
 91      *errorInfo = [NSError errorWithDomain:@"GTMLoginItems" code:-90 userInfo:nil];
 92    return NO;
 93    // COV_NF_END
 94  }
 95  NSAppleScript *query = [[[NSAppleScript alloc] initWithSource:script] autorelease];
 96  NSDictionary *errDict = nil;
 97  if ( ![query compileAndReturnError:&errDict]) {
 98    // COV_NF_START - no real way to test this
 99    if (errorInfo)
100      *errorInfo = [NSError errorWithDomain:@"GTMLoginItems" code:-91 userInfo:errDict];
101    return NO;
102    // COV_NF_END
103  }
104  NSAppleEventDescriptor *scriptResult = [query executeAndReturnError:&errDict];
105  if (!scriptResult) {
106    // COV_NF_START - no real way to test this
107    if (errorInfo)
108      *errorInfo = [NSError errorWithDomain:@"GTMLoginItems" code:-92 userInfo:errDict];
109    return NO;
110    // COV_NF_END
111  }
112  // we don't process the result
113  return YES;
114}
115
116#endif  // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
117
118@end
119
120@implementation GTMLoginItems
121
122#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
123
124+ (NSArray*)loginItems:(NSError **)errorInfo {
125  // get the login items from LaunchServices
126  LSSharedFileListRef loginItemsRef = [self loginItemsFileListRef];
127  if (!loginItemsRef) {
128    // COV_NF_START - no real way to test this
129    if (errorInfo) {
130      *errorInfo = [NSError errorWithDomain:@"GTMLoginItems"
131                                       code:-1
132                                   userInfo:nil];
133    }
134    return nil;
135    // COV_NF_END
136  }
137  NSArray *fileList = [self loginItemsArrayForFileListRef:loginItemsRef];
138
139  // build our results
140  NSMutableArray *result = [NSMutableArray array];
141  for (id fileItem in fileList) {
142    LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)fileItem;
143    // name
144    NSMutableDictionary *item = [NSMutableDictionary dictionary];
145    CFStringRef nameRef = LSSharedFileListItemCopyDisplayName(itemRef);
146    if (nameRef) {
147      [item setObject:[(NSString *)nameRef stringByDeletingPathExtension]
148               forKey:kGTMLoginItemsNameKey];
149      CFRelease(nameRef);
150    }
151    // path
152    CFURLRef urlRef = NULL;
153    if (LSSharedFileListItemResolve(itemRef, 0, &urlRef, NULL) == noErr) {
154      if (urlRef) {
155        NSString *path = [(NSURL *)urlRef path];
156        if (path) {
157          [item setObject:path forKey:kGTMLoginItemsPathKey];
158        }
159        CFRelease(urlRef);
160      }
161    }
162    // hidden
163    CFBooleanRef hiddenRef = LSSharedFileListItemCopyProperty(itemRef,
164        (CFStringRef)kLSSharedFileListLoginItemHidden);
165    if (hiddenRef) {
166      if (hiddenRef == kCFBooleanTrue) {
167        [item setObject:[NSNumber numberWithBool:YES]
168                 forKey:kGTMLoginItemsHiddenKey];
169      }
170      CFRelease(hiddenRef);
171    }
172    [result addObject:item];
173  }
174
175  return result;
176}
177
178#else  // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
179
180+ (NSArray*)loginItems:(NSError **)errorInfo {
181  NSDictionary *errDict = nil;
182  // get the script compiled and saved off
183  static NSAppleScript *query = nil;
184  if (!query) {
185    NSString *querySource = @"tell application \"System Events\" to get properties of login items";
186    query = [[NSAppleScript alloc] initWithSource:querySource];
187    if ( ![query compileAndReturnError:&errDict]) {
188      // COV_NF_START - no real way to test this
189      if (errorInfo)
190        *errorInfo = [NSError errorWithDomain:@"GTMLoginItems" code:-1 userInfo:errDict];
191      [query release];
192      query = nil;
193      return nil;
194      // COV_NF_END
195    }
196  }
197  // run the script
198  NSAppleEventDescriptor *scriptResult = [query executeAndReturnError:&errDict];
199  if (!scriptResult) {
200    // COV_NF_START - no real way to test this
201    if (errorInfo)
202      *errorInfo = [NSError errorWithDomain:@"GTMLoginItems" code:-2 userInfo:errDict];
203    return nil;
204    // COV_NF_END
205  }
206  // build our results
207  NSMutableArray *result = [NSMutableArray array];
208  NSInteger count = [scriptResult numberOfItems];
209  for (NSInteger i = 0; i < count; ++i) {
210    NSAppleEventDescriptor *aeItem = [scriptResult descriptorAtIndex:i+1];
211    NSAppleEventDescriptor *hidn = [aeItem descriptorForKeyword:kAEHidden];
212    NSAppleEventDescriptor *nam = [aeItem descriptorForKeyword:pName];
213    NSAppleEventDescriptor *ppth = [aeItem descriptorForKeyword:'ppth'];
214    NSMutableDictionary *item = [NSMutableDictionary dictionary];
215    if (hidn && [hidn booleanValue]) {
216      [item setObject:[NSNumber numberWithBool:YES] forKey:kGTMLoginItemsHiddenKey];
217    }
218    if (nam) {
219      NSString *name = [nam stringValue];
220      if (name) {
221        [item setObject:name forKey:kGTMLoginItemsNameKey];
222      }
223    }
224    if (ppth) {
225      NSString *path = [ppth stringValue];
226      if (path) {
227        [item setObject:path forKey:kGTMLoginItemsPathKey];
228      }
229    }
230    [result addObject:item];
231  }
232
233  return result;
234}
235
236#endif  // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
237
238+ (BOOL)pathInLoginItems:(NSString *)path {
239  NSArray *loginItems = [self loginItems:nil];
240  NSInteger itemIndex = [self indexOfLoginItemWithValue:path
241                                                 forKey:kGTMLoginItemsPathKey
242                                             loginItems:loginItems];
243  return (itemIndex != NSNotFound) ? YES : NO;
244}
245
246+ (BOOL)itemWithNameInLoginItems:(NSString *)name {
247  NSArray *loginItems = [self loginItems:nil];
248  NSInteger itemIndex = [self indexOfLoginItemWithValue:name
249                                                 forKey:kGTMLoginItemsNameKey
250                                             loginItems:loginItems];
251  return (itemIndex != NSNotFound) ? YES : NO;
252}
253
254+ (void)addPathToLoginItems:(NSString*)path hide:(BOOL)hide {
255  if (!path) return;
256  // make sure it isn't already there
257  if ([self pathInLoginItems:path]) return;
258  // now append it
259#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
260  NSURL *url = [NSURL fileURLWithPath:path];
261  if (url) {
262    LSSharedFileListRef loginItemsRef = [self loginItemsFileListRef];
263    if (loginItemsRef) {
264      NSDictionary *setProperties =
265          [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:hide]
266              forKey:(id)kLSSharedFileListLoginItemHidden];
267      LSSharedFileListItemRef itemRef =
268          LSSharedFileListInsertItemURL(loginItemsRef,
269                                        kLSSharedFileListItemLast, NULL, NULL,
270                                        (CFURLRef)url,
271                                        (CFDictionaryRef)setProperties, NULL);
272      if (itemRef) CFRelease(itemRef);
273    }
274  }
275#else  // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
276  NSString *scriptSource =
277    [NSString stringWithFormat:
278      @"tell application \"System Events\" to make new login item with properties { path:\"%s\", hidden:%s } at end",
279      [path UTF8String],
280      (hide ? "yes" : "no")];
281  [self compileAndRunScript:scriptSource withError:nil];
282#endif  // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
283}
284
285+ (void)removePathFromLoginItems:(NSString*)path {
286  if ([path length] == 0) return;
287#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
288  NSURL *url = [NSURL fileURLWithPath:path];
289  LSSharedFileListRef loginItemsRef = [self loginItemsFileListRef];
290  if (loginItemsRef) {
291    NSArray *fileList = [self loginItemsArrayForFileListRef:loginItemsRef];
292    for (id item in fileList) {
293      LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)item;
294      CFURLRef urlRef = NULL;
295      if (LSSharedFileListItemResolve(itemRef, 0, &urlRef, NULL) == noErr) {
296        if (urlRef) {
297          if (CFEqual(urlRef, (CFURLRef)url)) {
298            LSSharedFileListItemRemove(loginItemsRef, itemRef);
299          }
300          CFRelease(urlRef);
301        }
302      }
303    }
304  }
305#else  // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
306  NSString *scriptSource =
307    [NSString stringWithFormat:
308      @"tell application \"System Events\" to delete (login items whose path is \"%s\")",
309      [path UTF8String]];
310  [self compileAndRunScript:scriptSource withError:nil];
311#endif  // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
312}
313
314+ (void)removeItemWithNameFromLoginItems:(NSString *)name {
315  if ([name length] == 0) return;
316#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
317  LSSharedFileListRef loginItemsRef = [self loginItemsFileListRef];
318  if (loginItemsRef) {
319    NSArray *fileList = [self loginItemsArrayForFileListRef:loginItemsRef];
320    for (id item in fileList) {
321      LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)item;
322      CFStringRef itemNameRef = LSSharedFileListItemCopyDisplayName(itemRef);
323      if (itemNameRef) {
324        NSString *itemName =
325            [(NSString *)itemNameRef stringByDeletingPathExtension];
326        if ([itemName isEqual:name]) {
327          LSSharedFileListItemRemove(loginItemsRef, itemRef);
328        }
329        CFRelease(itemNameRef);
330      }
331    }
332  }
333#else  // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
334  NSString *scriptSource =
335    [NSString stringWithFormat:
336      @"tell application \"System Events\" to delete (login items whose name is \"%s\")",
337      [name UTF8String]];
338  [self compileAndRunScript:scriptSource withError:nil];
339#endif  // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
340}
341
342@end