PageRenderTime 117ms CodeModel.GetById 20ms 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
Possible License(s): Apache-2.0, BSD-3-Clause, GPL-2.0
  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. #import "GTMLoginItems.h"
  20. #import "GTMDefines.h"
  21. #include <Carbon/Carbon.h>
  22. // Exposed constants
  23. NSString * const kGTMLoginItemsNameKey = @"Name";
  24. NSString * const kGTMLoginItemsPathKey = @"Path";
  25. NSString * const kGTMLoginItemsHiddenKey = @"Hide";
  26. // kLSSharedFileListLoginItemHidden is supported on
  27. // 10.5, but missing from the 10.5 headers.
  28. // http://openradar.appspot.com/6482251
  29. #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
  30. static NSString * const kLSSharedFileListLoginItemHidden =
  31. @"com.apple.loginitem.HideOnLaunch";
  32. #endif // MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
  33. @interface GTMLoginItems (PrivateMethods)
  34. + (NSInteger)indexOfLoginItemWithValue:(id)value
  35. forKey:(NSString *)key
  36. loginItems:(NSArray *)items;
  37. #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  38. + (LSSharedFileListRef)loginItemsFileListRef;
  39. + (NSArray *)loginItemsArrayForFileListRef:(LSSharedFileListRef)fileListRef;
  40. #else // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  41. + (BOOL)compileAndRunScript:(NSString *)script
  42. withError:(NSError **)errorInfo;
  43. #endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  44. @end
  45. @implementation GTMLoginItems (PrivateMethods)
  46. + (NSInteger)indexOfLoginItemWithValue:(id)value
  47. forKey:(NSString *)key
  48. loginItems:(NSArray *)items {
  49. if (!value || !key || !items) return NSNotFound;
  50. NSDictionary *item = nil;
  51. NSInteger found = -1;
  52. GTM_FOREACH_OBJECT(item, items) {
  53. ++found;
  54. id itemValue = [item objectForKey:key];
  55. if (itemValue && [itemValue isEqual:value]) {
  56. return found;
  57. }
  58. }
  59. return NSNotFound;
  60. }
  61. #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  62. + (LSSharedFileListRef)loginItemsFileListRef {
  63. LSSharedFileListRef loginItemsRef =
  64. LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
  65. return (LSSharedFileListRef)GTMCFAutorelease(loginItemsRef);
  66. }
  67. + (NSArray *)loginItemsArrayForFileListRef:(LSSharedFileListRef)fileListRef {
  68. UInt32 seedValue;
  69. CFArrayRef filelistArrayRef = LSSharedFileListCopySnapshot(fileListRef,
  70. &seedValue);
  71. return GTMCFAutorelease(filelistArrayRef);
  72. }
  73. #else // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  74. + (BOOL)compileAndRunScript:(NSString *)script
  75. withError:(NSError **)errorInfo {
  76. if ([script length] == 0) {
  77. // COV_NF_START - no real way to test this
  78. if (errorInfo)
  79. *errorInfo = [NSError errorWithDomain:@"GTMLoginItems" code:-90 userInfo:nil];
  80. return NO;
  81. // COV_NF_END
  82. }
  83. NSAppleScript *query = [[[NSAppleScript alloc] initWithSource:script] autorelease];
  84. NSDictionary *errDict = nil;
  85. if ( ![query compileAndReturnError:&errDict]) {
  86. // COV_NF_START - no real way to test this
  87. if (errorInfo)
  88. *errorInfo = [NSError errorWithDomain:@"GTMLoginItems" code:-91 userInfo:errDict];
  89. return NO;
  90. // COV_NF_END
  91. }
  92. NSAppleEventDescriptor *scriptResult = [query executeAndReturnError:&errDict];
  93. if (!scriptResult) {
  94. // COV_NF_START - no real way to test this
  95. if (errorInfo)
  96. *errorInfo = [NSError errorWithDomain:@"GTMLoginItems" code:-92 userInfo:errDict];
  97. return NO;
  98. // COV_NF_END
  99. }
  100. // we don't process the result
  101. return YES;
  102. }
  103. #endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  104. @end
  105. @implementation GTMLoginItems
  106. #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  107. + (NSArray*)loginItems:(NSError **)errorInfo {
  108. // get the login items from LaunchServices
  109. LSSharedFileListRef loginItemsRef = [self loginItemsFileListRef];
  110. if (!loginItemsRef) {
  111. // COV_NF_START - no real way to test this
  112. if (errorInfo) {
  113. *errorInfo = [NSError errorWithDomain:@"GTMLoginItems"
  114. code:-1
  115. userInfo:nil];
  116. }
  117. return nil;
  118. // COV_NF_END
  119. }
  120. NSArray *fileList = [self loginItemsArrayForFileListRef:loginItemsRef];
  121. // build our results
  122. NSMutableArray *result = [NSMutableArray array];
  123. for (id fileItem in fileList) {
  124. LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)fileItem;
  125. // name
  126. NSMutableDictionary *item = [NSMutableDictionary dictionary];
  127. CFStringRef nameRef = LSSharedFileListItemCopyDisplayName(itemRef);
  128. if (nameRef) {
  129. [item setObject:[(NSString *)nameRef stringByDeletingPathExtension]
  130. forKey:kGTMLoginItemsNameKey];
  131. CFRelease(nameRef);
  132. }
  133. // path
  134. CFURLRef urlRef = NULL;
  135. if (LSSharedFileListItemResolve(itemRef, 0, &urlRef, NULL) == noErr) {
  136. if (urlRef) {
  137. NSString *path = [(NSURL *)urlRef path];
  138. if (path) {
  139. [item setObject:path forKey:kGTMLoginItemsPathKey];
  140. }
  141. CFRelease(urlRef);
  142. }
  143. }
  144. // hidden
  145. CFBooleanRef hiddenRef = LSSharedFileListItemCopyProperty(itemRef,
  146. (CFStringRef)kLSSharedFileListLoginItemHidden);
  147. if (hiddenRef) {
  148. if (hiddenRef == kCFBooleanTrue) {
  149. [item setObject:[NSNumber numberWithBool:YES]
  150. forKey:kGTMLoginItemsHiddenKey];
  151. }
  152. CFRelease(hiddenRef);
  153. }
  154. [result addObject:item];
  155. }
  156. return result;
  157. }
  158. #else // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  159. + (NSArray*)loginItems:(NSError **)errorInfo {
  160. NSDictionary *errDict = nil;
  161. // get the script compiled and saved off
  162. static NSAppleScript *query = nil;
  163. if (!query) {
  164. NSString *querySource = @"tell application \"System Events\" to get properties of login items";
  165. query = [[NSAppleScript alloc] initWithSource:querySource];
  166. if ( ![query compileAndReturnError:&errDict]) {
  167. // COV_NF_START - no real way to test this
  168. if (errorInfo)
  169. *errorInfo = [NSError errorWithDomain:@"GTMLoginItems" code:-1 userInfo:errDict];
  170. [query release];
  171. query = nil;
  172. return nil;
  173. // COV_NF_END
  174. }
  175. }
  176. // run the script
  177. NSAppleEventDescriptor *scriptResult = [query executeAndReturnError:&errDict];
  178. if (!scriptResult) {
  179. // COV_NF_START - no real way to test this
  180. if (errorInfo)
  181. *errorInfo = [NSError errorWithDomain:@"GTMLoginItems" code:-2 userInfo:errDict];
  182. return nil;
  183. // COV_NF_END
  184. }
  185. // build our results
  186. NSMutableArray *result = [NSMutableArray array];
  187. NSInteger count = [scriptResult numberOfItems];
  188. for (NSInteger i = 0; i < count; ++i) {
  189. NSAppleEventDescriptor *aeItem = [scriptResult descriptorAtIndex:i+1];
  190. NSAppleEventDescriptor *hidn = [aeItem descriptorForKeyword:kAEHidden];
  191. NSAppleEventDescriptor *nam = [aeItem descriptorForKeyword:pName];
  192. NSAppleEventDescriptor *ppth = [aeItem descriptorForKeyword:'ppth'];
  193. NSMutableDictionary *item = [NSMutableDictionary dictionary];
  194. if (hidn && [hidn booleanValue]) {
  195. [item setObject:[NSNumber numberWithBool:YES] forKey:kGTMLoginItemsHiddenKey];
  196. }
  197. if (nam) {
  198. NSString *name = [nam stringValue];
  199. if (name) {
  200. [item setObject:name forKey:kGTMLoginItemsNameKey];
  201. }
  202. }
  203. if (ppth) {
  204. NSString *path = [ppth stringValue];
  205. if (path) {
  206. [item setObject:path forKey:kGTMLoginItemsPathKey];
  207. }
  208. }
  209. [result addObject:item];
  210. }
  211. return result;
  212. }
  213. #endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  214. + (BOOL)pathInLoginItems:(NSString *)path {
  215. NSArray *loginItems = [self loginItems:nil];
  216. NSInteger itemIndex = [self indexOfLoginItemWithValue:path
  217. forKey:kGTMLoginItemsPathKey
  218. loginItems:loginItems];
  219. return (itemIndex != NSNotFound) ? YES : NO;
  220. }
  221. + (BOOL)itemWithNameInLoginItems:(NSString *)name {
  222. NSArray *loginItems = [self loginItems:nil];
  223. NSInteger itemIndex = [self indexOfLoginItemWithValue:name
  224. forKey:kGTMLoginItemsNameKey
  225. loginItems:loginItems];
  226. return (itemIndex != NSNotFound) ? YES : NO;
  227. }
  228. + (void)addPathToLoginItems:(NSString*)path hide:(BOOL)hide {
  229. if (!path) return;
  230. // make sure it isn't already there
  231. if ([self pathInLoginItems:path]) return;
  232. // now append it
  233. #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  234. NSURL *url = [NSURL fileURLWithPath:path];
  235. if (url) {
  236. LSSharedFileListRef loginItemsRef = [self loginItemsFileListRef];
  237. if (loginItemsRef) {
  238. NSDictionary *setProperties =
  239. [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:hide]
  240. forKey:(id)kLSSharedFileListLoginItemHidden];
  241. LSSharedFileListItemRef itemRef =
  242. LSSharedFileListInsertItemURL(loginItemsRef,
  243. kLSSharedFileListItemLast, NULL, NULL,
  244. (CFURLRef)url,
  245. (CFDictionaryRef)setProperties, NULL);
  246. if (itemRef) CFRelease(itemRef);
  247. }
  248. }
  249. #else // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  250. NSString *scriptSource =
  251. [NSString stringWithFormat:
  252. @"tell application \"System Events\" to make new login item with properties { path:\"%s\", hidden:%s } at end",
  253. [path UTF8String],
  254. (hide ? "yes" : "no")];
  255. [self compileAndRunScript:scriptSource withError:nil];
  256. #endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  257. }
  258. + (void)removePathFromLoginItems:(NSString*)path {
  259. if ([path length] == 0) return;
  260. #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  261. NSURL *url = [NSURL fileURLWithPath:path];
  262. LSSharedFileListRef loginItemsRef = [self loginItemsFileListRef];
  263. if (loginItemsRef) {
  264. NSArray *fileList = [self loginItemsArrayForFileListRef:loginItemsRef];
  265. for (id item in fileList) {
  266. LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)item;
  267. CFURLRef urlRef = NULL;
  268. if (LSSharedFileListItemResolve(itemRef, 0, &urlRef, NULL) == noErr) {
  269. if (urlRef) {
  270. if (CFEqual(urlRef, (CFURLRef)url)) {
  271. LSSharedFileListItemRemove(loginItemsRef, itemRef);
  272. }
  273. CFRelease(urlRef);
  274. }
  275. }
  276. }
  277. }
  278. #else // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  279. NSString *scriptSource =
  280. [NSString stringWithFormat:
  281. @"tell application \"System Events\" to delete (login items whose path is \"%s\")",
  282. [path UTF8String]];
  283. [self compileAndRunScript:scriptSource withError:nil];
  284. #endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  285. }
  286. + (void)removeItemWithNameFromLoginItems:(NSString *)name {
  287. if ([name length] == 0) return;
  288. #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  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. CFStringRef itemNameRef = LSSharedFileListItemCopyDisplayName(itemRef);
  295. if (itemNameRef) {
  296. NSString *itemName =
  297. [(NSString *)itemNameRef stringByDeletingPathExtension];
  298. if ([itemName isEqual:name]) {
  299. LSSharedFileListItemRemove(loginItemsRef, itemRef);
  300. }
  301. CFRelease(itemNameRef);
  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 name is \"%s\")",
  309. [name UTF8String]];
  310. [self compileAndRunScript:scriptSource withError:nil];
  311. #endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  312. }
  313. @end