Alexander Afanasyev | cc5c671 | 2013-09-30 17:43:54 -0700 | [diff] [blame] | 1 | // |
| 2 | // LaunchAtLoginController.m |
| 3 | // |
| 4 | // Copyright 2011 Tomáš Znamenáček |
| 5 | // Copyright 2010 Ben Clark-Robinson |
| 6 | // |
| 7 | // Permission is hereby granted, free of charge, to any person obtaining |
| 8 | // a copy of this software and associated documentation files (the ‘Software’), |
| 9 | // to deal in the Software without restriction, including without limitation |
| 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 11 | // and/or sell copies of the Software, and to permit persons to whom the |
| 12 | // Software is furnished to do so, subject to the following conditions: |
| 13 | // |
| 14 | // The above copyright notice and this permission notice shall be |
| 15 | // included in all copies or substantial portions of the Software. |
| 16 | // |
| 17 | // THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, |
| 18 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 19 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| 20 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| 21 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| 22 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| 23 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 24 | |
| 25 | #import "launch-at-login-controller.h" |
| 26 | |
| 27 | static NSString *const StartAtLoginKey = @"launchAtLogin"; |
| 28 | |
| 29 | @interface LaunchAtLoginController () |
| 30 | @property(assign) LSSharedFileListRef loginItems; |
| 31 | @end |
| 32 | |
| 33 | @implementation LaunchAtLoginController |
| 34 | @synthesize loginItems; |
| 35 | |
| 36 | #pragma mark Change Observing |
| 37 | |
| 38 | void sharedFileListDidChange(LSSharedFileListRef inList, void *context) |
| 39 | { |
| 40 | LaunchAtLoginController *self = (__bridge id) context; |
| 41 | [self willChangeValueForKey:StartAtLoginKey]; |
| 42 | [self didChangeValueForKey:StartAtLoginKey]; |
| 43 | } |
| 44 | |
| 45 | #pragma mark Initialization |
| 46 | |
| 47 | - (id) init |
| 48 | { |
| 49 | self = [super init]; |
| 50 | loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); |
| 51 | LSSharedFileListAddObserver(loginItems, CFRunLoopGetMain(), |
Alexander Afanasyev | b6392e3 | 2014-05-12 23:43:50 -0700 | [diff] [blame^] | 52 | (__bridge CFStringRef)NSDefaultRunLoopMode, sharedFileListDidChange, (voidPtr)CFBridgingRetain(self)); |
Alexander Afanasyev | cc5c671 | 2013-09-30 17:43:54 -0700 | [diff] [blame] | 53 | return self; |
| 54 | } |
| 55 | |
| 56 | - (void) dealloc |
| 57 | { |
| 58 | LSSharedFileListRemoveObserver(loginItems, CFRunLoopGetMain(), |
Alexander Afanasyev | b6392e3 | 2014-05-12 23:43:50 -0700 | [diff] [blame^] | 59 | (__bridge CFStringRef)NSDefaultRunLoopMode, sharedFileListDidChange, (__bridge void *)(self)); |
Alexander Afanasyev | cc5c671 | 2013-09-30 17:43:54 -0700 | [diff] [blame] | 60 | CFRelease(loginItems); |
| 61 | } |
| 62 | |
| 63 | #pragma mark Launch List Control |
| 64 | |
| 65 | - (LSSharedFileListItemRef) findItemWithURL: (NSURL*) wantedURL inFileList: (LSSharedFileListRef) fileList |
| 66 | { |
| 67 | if (wantedURL == NULL || fileList == NULL) |
| 68 | return NULL; |
| 69 | |
| 70 | NSArray *listSnapshot = (__bridge NSArray *)(LSSharedFileListCopySnapshot(fileList, NULL)); |
| 71 | for (id itemObject in listSnapshot) { |
| 72 | LSSharedFileListItemRef item = (__bridge LSSharedFileListItemRef) itemObject; |
| 73 | UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes; |
| 74 | CFURLRef currentItemURL = NULL; |
| 75 | LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, NULL); |
| 76 | if (currentItemURL && CFEqual(currentItemURL, (__bridge CFTypeRef)(wantedURL))) |
| 77 | { |
| 78 | CFRelease(currentItemURL); |
| 79 | return item; |
| 80 | } |
| 81 | if (currentItemURL) |
| 82 | CFRelease(currentItemURL); |
| 83 | } |
| 84 | |
| 85 | return NULL; |
| 86 | } |
| 87 | |
| 88 | - (BOOL) willLaunchAtLogin: (NSURL*) itemURL |
| 89 | { |
| 90 | return !![self findItemWithURL:itemURL inFileList:loginItems]; |
| 91 | } |
| 92 | |
| 93 | - (void) setLaunchAtLogin: (BOOL) enabled forURL: (NSURL*) itemURL |
| 94 | { |
| 95 | LSSharedFileListItemRef appItem = [self findItemWithURL:itemURL inFileList:loginItems]; |
| 96 | if (enabled && !appItem) { |
| 97 | LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, |
| 98 | NULL, NULL, (__bridge CFURLRef)itemURL, NULL, NULL); |
| 99 | } else if (!enabled && appItem) |
| 100 | LSSharedFileListItemRemove(loginItems, appItem); |
| 101 | } |
| 102 | |
| 103 | #pragma mark Basic Interface |
| 104 | |
| 105 | - (NSURL*) appURL |
| 106 | { |
| 107 | return [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]; |
| 108 | } |
| 109 | |
| 110 | - (void) setLaunchAtLogin: (BOOL) enabled |
| 111 | { |
| 112 | [self willChangeValueForKey:StartAtLoginKey]; |
| 113 | [self setLaunchAtLogin:enabled forURL:[self appURL]]; |
| 114 | [self didChangeValueForKey:StartAtLoginKey]; |
| 115 | } |
| 116 | |
| 117 | - (BOOL) launchAtLogin |
| 118 | { |
| 119 | return [self willLaunchAtLogin:[self appURL]]; |
| 120 | } |
| 121 | |
| 122 | @end |