preference: add autostart feature

Refs #73111

Change-Id: I5a6d2e8b911b154100e204a6c60696b8ea5c6c31
diff --git a/src/GeneralPrefsVC.mm b/src/GeneralPrefsVC.mm
index 4608528..2cf7cdd 100644
--- a/src/GeneralPrefsVC.mm
+++ b/src/GeneralPrefsVC.mm
@@ -36,12 +36,14 @@
 @interface GeneralPrefsVC ()
 @property (assign) IBOutlet NSTextField *historyChangedLabel;
 @property (assign) IBOutlet NSView *advancedGeneralSettings;
+@property (unsafe_unretained) IBOutlet NSButton *startUpButton;
 
 @end
 
 @implementation GeneralPrefsVC
 @synthesize historyChangedLabel;
 @synthesize advancedGeneralSettings;
+@synthesize startUpButton;
 
 - (void)loadView
 {
@@ -49,6 +51,8 @@
     [[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:Preferences::HistoryLimit options:NSKeyValueObservingOptionNew context:NULL];
     [[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:Preferences::ShowAdvanced options:NSKeyValueObservingOptionNew context:NULL];
 
+    [startUpButton setState:[self isLaunchAtStartup]];
+
     [advancedGeneralSettings setHidden:![[NSUserDefaults standardUserDefaults] boolForKey:Preferences::ShowAdvanced]];
 }
 
@@ -68,4 +72,70 @@
     }
 }
 
+#pragma mark - Startup API
+
+// MIT license by Brian Dunagan
+- (BOOL)isLaunchAtStartup {
+    // See if the app is currently in LoginItems.
+    LSSharedFileListItemRef itemRef = [self itemRefInLoginItems];
+    // Store away that boolean.
+    BOOL isInList = itemRef != nil;
+    // Release the reference if it exists.
+    if (itemRef != nil) CFRelease(itemRef);
+
+    return isInList;
+}
+
+- (IBAction)toggleLaunchAtStartup:(id)sender {
+    // Toggle the state.
+    BOOL shouldBeToggled = ![self isLaunchAtStartup];
+    // Get the LoginItems list.
+    LSSharedFileListRef loginItemsRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
+    if (loginItemsRef == nil) return;
+    if (shouldBeToggled) {
+        // Add the app to the LoginItems list.
+        CFURLRef appUrl = (CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
+        LSSharedFileListItemRef itemRef = LSSharedFileListInsertItemURL(loginItemsRef, kLSSharedFileListItemLast, NULL, NULL, appUrl, NULL, NULL);
+        if (itemRef) CFRelease(itemRef);
+    }
+    else {
+        // Remove the app from the LoginItems list.
+        LSSharedFileListItemRef itemRef = [self itemRefInLoginItems];
+        LSSharedFileListItemRemove(loginItemsRef,itemRef);
+        if (itemRef != nil) CFRelease(itemRef);
+    }
+    CFRelease(loginItemsRef);
+}
+
+- (LSSharedFileListItemRef)itemRefInLoginItems {
+    LSSharedFileListItemRef itemRef = nil;
+    NSURL *itemUrl = nil;
+
+    // Get the app's URL.
+    NSURL *appUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
+    // Get the LoginItems list.
+    LSSharedFileListRef loginItemsRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
+    if (loginItemsRef == nil) return nil;
+    // Iterate over the LoginItems.
+    NSArray *loginItems = (NSArray *)LSSharedFileListCopySnapshot(loginItemsRef, nil);
+    for (int currentIndex = 0; currentIndex < [loginItems count]; currentIndex++) {
+        // Get the current LoginItem and resolve its URL.
+        LSSharedFileListItemRef currentItemRef = (LSSharedFileListItemRef)[loginItems objectAtIndex:currentIndex];
+        if (LSSharedFileListItemResolve(currentItemRef, 0, (CFURLRef *) &itemUrl, NULL) == noErr) {
+            // Compare the URLs for the current LoginItem and the app.
+            if ([itemUrl isEqual:appUrl]) {
+                // Save the LoginItem reference.
+                itemRef = currentItemRef;
+            }
+        }
+    }
+    // Retain the LoginItem reference.
+    if (itemRef != nil) CFRetain(itemRef);
+    // Release the LoginItems lists.
+    [loginItems release];
+    CFRelease(loginItemsRef);
+
+    return itemRef;
+}
+
 @end