diff options
author | Teddy Wing | 2016-12-02 13:00:19 -0500 |
---|---|---|
committer | Teddy Wing | 2016-12-02 13:00:19 -0500 |
commit | a77a053f90a7b2588dbaabedbf25f908680f2f30 (patch) | |
tree | b1dcf8706c1e6a82e8505f2fa09dc22e0a197ecd | |
parent | 055471fad0187e654302034a0875a417e73e089f (diff) | |
download | Low-Battery-Yup-a77a053f90a7b2588dbaabedbf25f908680f2f30.tar.bz2 |
Add "Start at login" checkbox that [un]installs launch agent
A new checkbox in the UI that asks whether the app should start at
login. Checking and unchecking the box moves a LaunchAgent plist into
and out of `~/Library/LaunchAgents/`. This plist file will define
instructions to start the daemon on login.
Also add a `DaemonLauncher` class that will launch or quit the daemon
when the checkbox is clicked.
Bug:
Currently the app always starts with the checkbox checked. That's not
what should happen. Instead, we should save the checkbox value to
`NSUserDefaults` so that it has the previous value when the program is
launched.
-rw-r--r-- | Low Battery Yup.d.xcodeproj/project.pbxproj | 16 | ||||
-rw-r--r-- | Low Battery Yup/AppDelegate.h | 4 | ||||
-rw-r--r-- | Low Battery Yup/AppDelegate.m | 21 | ||||
-rw-r--r-- | Low Battery Yup/DaemonLauncher.h | 13 | ||||
-rw-r--r-- | Low Battery Yup/DaemonLauncher.m | 13 | ||||
-rw-r--r-- | Low Battery Yup/LaunchAgentManager.h | 20 | ||||
-rw-r--r-- | Low Battery Yup/LaunchAgentManager.m | 52 | ||||
-rw-r--r-- | Low Battery Yup/com.teddywing.Low-Battery-Yup.StartAtLogin.plist | 5 | ||||
-rw-r--r-- | Low Battery Yup/en.lproj/MainMenu.xib | 23 |
9 files changed, 165 insertions, 2 deletions
diff --git a/Low Battery Yup.d.xcodeproj/project.pbxproj b/Low Battery Yup.d.xcodeproj/project.pbxproj index f1c9910..b625f3b 100644 --- a/Low Battery Yup.d.xcodeproj/project.pbxproj +++ b/Low Battery Yup.d.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ D123F5A81DDF9D2400A27B7A /* DDHotKeyCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = D123F5A71DDF9D2400A27B7A /* DDHotKeyCenter.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; + D131EB381DF1E8AB00504A74 /* com.teddywing.Low-Battery-Yup.StartAtLogin.plist in Resources */ = {isa = PBXBuildFile; fileRef = D131EB371DF1E8AB00504A74 /* com.teddywing.Low-Battery-Yup.StartAtLogin.plist */; }; D15D90B71DF0465E001700CD /* ShortcutView.m in Sources */ = {isa = PBXBuildFile; fileRef = D15D90B61DF0465E001700CD /* ShortcutView.m */; }; D1871D071DE094AB00B8030D /* DDHotKeyTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D1871D061DE094AB00B8030D /* DDHotKeyTextField.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; D1871D081DE094C200B8030D /* DDHotKeyUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = D1A37AF01DE001770022434D /* DDHotKeyUtilities.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; @@ -21,6 +22,8 @@ D18C94C51DDC355400E03F87 /* Mouse.m in Sources */ = {isa = PBXBuildFile; fileRef = D18C94C41DDC355400E03F87 /* Mouse.m */; }; D195AE5F1DDC776000A53A18 /* MASShortcut.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D195AE5A1DDC774300A53A18 /* MASShortcut.framework */; }; D195AE601DDC776F00A53A18 /* MASShortcut.framework in Resources */ = {isa = PBXBuildFile; fileRef = D195AE5A1DDC774300A53A18 /* MASShortcut.framework */; }; + D19DF20F1DF1AD3D0094C50F /* LaunchAgentManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D19DF20E1DF1AD3D0094C50F /* LaunchAgentManager.m */; }; + D19DF2121DF1AD480094C50F /* DaemonLauncher.m in Sources */ = {isa = PBXBuildFile; fileRef = D19DF2111DF1AD480094C50F /* DaemonLauncher.m */; }; D1A37AEE1DE0012C0022434D /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1A37AED1DE0012C0022434D /* Carbon.framework */; }; D1A37AF11DE001770022434D /* DDHotKeyUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = D1A37AF01DE001770022434D /* DDHotKeyUtilities.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; D1F809E11DDC6AA0001671E9 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D18C94A21DDC33CF00E03F87 /* Cocoa.framework */; }; @@ -58,6 +61,7 @@ /* Begin PBXFileReference section */ D123F5A61DDF9D2400A27B7A /* DDHotKeyCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDHotKeyCenter.h; path = DDHotKey/DDHotKeyCenter.h; sourceTree = "<group>"; }; D123F5A71DDF9D2400A27B7A /* DDHotKeyCenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDHotKeyCenter.m; path = DDHotKey/DDHotKeyCenter.m; sourceTree = "<group>"; }; + D131EB371DF1E8AB00504A74 /* com.teddywing.Low-Battery-Yup.StartAtLogin.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "com.teddywing.Low-Battery-Yup.StartAtLogin.plist"; sourceTree = "<group>"; }; D15D90B51DF0465E001700CD /* ShortcutView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShortcutView.h; sourceTree = "<group>"; }; D15D90B61DF0465E001700CD /* ShortcutView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShortcutView.m; sourceTree = "<group>"; }; D1871D051DE094AB00B8030D /* DDHotKeyTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDHotKeyTextField.h; path = DDHotKey/DDHotKeyTextField.h; sourceTree = "<group>"; }; @@ -78,6 +82,10 @@ D18C94C41DDC355400E03F87 /* Mouse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Mouse.m; sourceTree = "<group>"; }; D195AE4F1DDC774200A53A18 /* MASShortcut.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = MASShortcut.xcodeproj; path = MASShortcut/MASShortcut.xcodeproj; sourceTree = "<group>"; }; D19DF1F41DF09CF30094C50F /* Constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = "<group>"; }; + D19DF20D1DF1AD3D0094C50F /* LaunchAgentManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LaunchAgentManager.h; sourceTree = "<group>"; }; + D19DF20E1DF1AD3D0094C50F /* LaunchAgentManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LaunchAgentManager.m; sourceTree = "<group>"; }; + D19DF2101DF1AD480094C50F /* DaemonLauncher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DaemonLauncher.h; sourceTree = "<group>"; }; + D19DF2111DF1AD480094C50F /* DaemonLauncher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DaemonLauncher.m; sourceTree = "<group>"; }; D1A37AED1DE0012C0022434D /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; D1A37AEF1DE001770022434D /* DDHotKeyUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDHotKeyUtilities.h; path = DDHotKey/DDHotKeyUtilities.h; sourceTree = "<group>"; }; D1A37AF01DE001770022434D /* DDHotKeyUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDHotKeyUtilities.m; path = DDHotKey/DDHotKeyUtilities.m; sourceTree = "<group>"; }; @@ -207,6 +215,10 @@ D195AE4F1DDC774200A53A18 /* MASShortcut.xcodeproj */, D1F809EE1DDC6AA0001671E9 /* AppDelegate.h */, D1F809EF1DDC6AA0001671E9 /* AppDelegate.m */, + D19DF20D1DF1AD3D0094C50F /* LaunchAgentManager.h */, + D19DF20E1DF1AD3D0094C50F /* LaunchAgentManager.m */, + D19DF2101DF1AD480094C50F /* DaemonLauncher.h */, + D19DF2111DF1AD480094C50F /* DaemonLauncher.m */, D19DF1F41DF09CF30094C50F /* Constants.h */, D15D90B51DF0465E001700CD /* ShortcutView.h */, D15D90B61DF0465E001700CD /* ShortcutView.m */, @@ -224,6 +236,7 @@ D1F809E81DDC6AA0001671E9 /* main.m */, D1F809EA1DDC6AA0001671E9 /* Low Battery Yup-Prefix.pch */, D1F809EB1DDC6AA0001671E9 /* Credits.rtf */, + D131EB371DF1E8AB00504A74 /* com.teddywing.Low-Battery-Yup.StartAtLogin.plist */, ); name = "Supporting Files"; sourceTree = "<group>"; @@ -346,6 +359,7 @@ D1F809ED1DDC6AA0001671E9 /* Credits.rtf in Resources */, D1F809F31DDC6AA0001671E9 /* MainMenu.xib in Resources */, D195AE601DDC776F00A53A18 /* MASShortcut.framework in Resources */, + D131EB381DF1E8AB00504A74 /* com.teddywing.Low-Battery-Yup.StartAtLogin.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -374,6 +388,8 @@ D1871D081DE094C200B8030D /* DDHotKeyUtilities.m in Sources */, D1871D091DE0955E00B8030D /* DDHotKeyCenter.m in Sources */, D15D90B71DF0465E001700CD /* ShortcutView.m in Sources */, + D19DF20F1DF1AD3D0094C50F /* LaunchAgentManager.m in Sources */, + D19DF2121DF1AD480094C50F /* DaemonLauncher.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Low Battery Yup/AppDelegate.h b/Low Battery Yup/AppDelegate.h index cc38038..4ae3e9c 100644 --- a/Low Battery Yup/AppDelegate.h +++ b/Low Battery Yup/AppDelegate.h @@ -9,13 +9,17 @@ #import <Cocoa/Cocoa.h> #import <MASShortcut/MASShortcut.h> #import "ShortcutView.h" +#import "LaunchAgentManager.h" @interface AppDelegate : NSObject <NSApplicationDelegate> { IBOutlet NSWindow *window; IBOutlet ShortcutView *_shortcut_view; IBOutlet NSButton *_start_at_login; + + LaunchAgentManager *_launchagent; } - (void)initializeShortcutView; +- (IBAction)performStartAtLogin:(id)sender; @end diff --git a/Low Battery Yup/AppDelegate.m b/Low Battery Yup/AppDelegate.m index 1c77f41..365b1bf 100644 --- a/Low Battery Yup/AppDelegate.m +++ b/Low Battery Yup/AppDelegate.m @@ -11,14 +11,25 @@ @implementation AppDelegate +- (id)init +{ + self = [super init]; + if (self) { + _launchagent = [[LaunchAgentManager alloc] init]; + } + return self; +} + - (void)dealloc { + [_launchagent release]; [super dealloc]; } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { [self initializeShortcutView]; + [self performStartAtLogin:self]; } - (void)initializeShortcutView @@ -33,6 +44,16 @@ } } +- (IBAction)performStartAtLogin:(id)sender +{ + if ([_start_at_login state] == NSOnState) { + [_launchagent install]; + } + else { + [_launchagent uninstall]; + } +} + - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication { return YES; diff --git a/Low Battery Yup/DaemonLauncher.h b/Low Battery Yup/DaemonLauncher.h new file mode 100644 index 0000000..a62a256 --- /dev/null +++ b/Low Battery Yup/DaemonLauncher.h @@ -0,0 +1,13 @@ +// +// DaemonLauncher.h +// Low Battery Yup.d +// +// Created by TW on 12/2/16. +// Copyright (c) 2016 TW. All rights reserved. +// + +#import <Foundation/Foundation.h> + +@interface DaemonLauncher : NSObject + +@end diff --git a/Low Battery Yup/DaemonLauncher.m b/Low Battery Yup/DaemonLauncher.m new file mode 100644 index 0000000..4c6449c --- /dev/null +++ b/Low Battery Yup/DaemonLauncher.m @@ -0,0 +1,13 @@ +// +// DaemonLauncher.m +// Low Battery Yup.d +// +// Created by TW on 12/2/16. +// Copyright (c) 2016 TW. All rights reserved. +// + +#import "DaemonLauncher.h" + +@implementation DaemonLauncher + +@end diff --git a/Low Battery Yup/LaunchAgentManager.h b/Low Battery Yup/LaunchAgentManager.h new file mode 100644 index 0000000..5a9fa44 --- /dev/null +++ b/Low Battery Yup/LaunchAgentManager.h @@ -0,0 +1,20 @@ +// +// LaunchAgentManager.h +// Low Battery Yup.d +// +// Created by TW on 12/2/16. +// Copyright (c) 2016 TW. All rights reserved. +// + +#import <Foundation/Foundation.h> + +#define LAUNCH_AGENTS_PATH @"~/Library/LaunchAgents" + +@interface LaunchAgentManager : NSObject { + NSFileManager *_file_manager; +} + +- (BOOL)install; +- (BOOL)uninstall; + +@end diff --git a/Low Battery Yup/LaunchAgentManager.m b/Low Battery Yup/LaunchAgentManager.m new file mode 100644 index 0000000..fd75795 --- /dev/null +++ b/Low Battery Yup/LaunchAgentManager.m @@ -0,0 +1,52 @@ +// +// LaunchAgentManager.m +// Low Battery Yup.d +// +// Created by TW on 12/2/16. +// Copyright (c) 2016 TW. All rights reserved. +// + +#import "LaunchAgentManager.h" + +@implementation LaunchAgentManager + +- (id)init +{ + self = [super init]; + if (self) { + _file_manager = [NSFileManager defaultManager]; + } + return self; +} + +- (BOOL)install +{ + NSBundle *main_bundle = [NSBundle mainBundle]; + NSURL *launchagents_url = [NSURL fileURLWithPath: + [[LAUNCH_AGENTS_PATH stringByAppendingString:@"/com.teddywing.Low-Battery-Yup.StartAtLogin.plist"] stringByExpandingTildeInPath] + isDirectory:YES]; + + NSError *error; + BOOL success = [_file_manager copyItemAtURL: + [main_bundle URLForResource:@"com.teddywing.Low-Battery-Yup.StartAtLogin" withExtension:@"plist"] + toURL:launchagents_url + error:&error]; + + if (!success) { + NSLog(@"%@", error); + } + + return success; +} + +- (BOOL)uninstall +{ + return [[NSWorkspace sharedWorkspace] + performFileOperation:NSWorkspaceRecycleOperation + source:[LAUNCH_AGENTS_PATH stringByExpandingTildeInPath] + destination:@"" + files:[NSArray arrayWithObject:@"com.teddywing.Low-Battery-Yup.StartAtLogin.plist"] + tag:nil]; +} + +@end diff --git a/Low Battery Yup/com.teddywing.Low-Battery-Yup.StartAtLogin.plist b/Low Battery Yup/com.teddywing.Low-Battery-Yup.StartAtLogin.plist new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/Low Battery Yup/com.teddywing.Low-Battery-Yup.StartAtLogin.plist @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict/> +</plist> diff --git a/Low Battery Yup/en.lproj/MainMenu.xib b/Low Battery Yup/en.lproj/MainMenu.xib index e649cab..5e48c4e 100644 --- a/Low Battery Yup/en.lproj/MainMenu.xib +++ b/Low Battery Yup/en.lproj/MainMenu.xib @@ -1358,7 +1358,7 @@ <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="489226571"/> </object> - <string key="NSScreenRect">{{0, 0}, {2560, 1578}}</string> + <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string> <string key="NSMinSize">{480, 207}</string> <string key="NSMaxSize">{480, 207}</string> <bool key="NSWindowIsRestorable">YES</bool> @@ -2068,6 +2068,14 @@ </object> <int key="connectionID">544</int> </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">performStartAtLogin:</string> + <reference key="source" ref="976324537"/> + <reference key="destination" ref="1065652370"/> + </object> + <int key="connectionID">545</int> + </object> </array> <object class="IBMutableOrderedSet" key="objectRecords"> <array key="orderedObjects"> @@ -3256,13 +3264,24 @@ <nil key="activeLocalization"/> <dictionary class="NSMutableDictionary" key="localizations"/> <nil key="sourceID"/> - <int key="maxID">544</int> + <int key="maxID">545</int> </object> <object class="IBClassDescriber" key="IBDocument.Classes"> <array class="NSMutableArray" key="referencedPartialClassDescriptions"> <object class="IBPartialClassDescription"> <string key="className">AppDelegate</string> <string key="superclassName">NSObject</string> + <object class="NSMutableDictionary" key="actions"> + <string key="NS.key.0">performStartAtLogin:</string> + <string key="NS.object.0">id</string> + </object> + <object class="NSMutableDictionary" key="actionInfosByName"> + <string key="NS.key.0">performStartAtLogin:</string> + <object class="IBActionInfo" key="NS.object.0"> + <string key="name">performStartAtLogin:</string> + <string key="candidateClassName">id</string> + </object> + </object> <dictionary class="NSMutableDictionary" key="outlets"> <string key="_shortcut_view">ShortcutView</string> <string key="_start_at_login">NSButton</string> |