Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 5 commits
  • 19 files changed
  • 0 comments
  • 1 contributor
81 Battery Time Remaining.xcodeproj/project.pbxproj
@@ -17,9 +17,42 @@
17 17 28833BB215D7D4FF00741727 /* Readme.md in Resources */ = {isa = PBXBuildFile; fileRef = 28833BB115D7D4FF00741727 /* Readme.md */; };
18 18 28833BB415D7D61100741727 /* build_version in Resources */ = {isa = PBXBuildFile; fileRef = 28833BB315D7D61100741727 /* build_version */; };
19 19 28BA61A815D1B12500EDB674 /* icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 28BA61A715D1B12500EDB674 /* icon.icns */; };
  20 + 28FEDA5E15DA5C9D00320B72 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28FEDA5D15DA5C9D00320B72 /* ServiceManagement.framework */; };
  21 + 28FEDA6E15DA5ECA00320B72 /* LaunchAtLoginHelper.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = 28FEDA6B15DA5EB200320B72 /* LaunchAtLoginHelper.app */; };
  22 + 28FEDA6F15DA5F8C00320B72 /* LLManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 28FEDA6315DA5EB200320B72 /* LLManager.m */; };
20 23 D58C7EF815CD7C6100C07E0C /* StartAtLoginHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = D58C7EF715CD7C6100C07E0C /* StartAtLoginHelper.m */; };
21 24 /* End PBXBuildFile section */
22 25
  26 +/* Begin PBXContainerItemProxy section */
  27 + 28FEDA6A15DA5EB200320B72 /* PBXContainerItemProxy */ = {
  28 + isa = PBXContainerItemProxy;
  29 + containerPortal = 28FEDA5F15DA5EB200320B72 /* LaunchAtLoginHelper.xcodeproj */;
  30 + proxyType = 2;
  31 + remoteGlobalIDString = 734C379415414CE200994189;
  32 + remoteInfo = LaunchAtLoginHelper;
  33 + };
  34 + 28FEDA6C15DA5EC200320B72 /* PBXContainerItemProxy */ = {
  35 + isa = PBXContainerItemProxy;
  36 + containerPortal = 28FEDA5F15DA5EB200320B72 /* LaunchAtLoginHelper.xcodeproj */;
  37 + proxyType = 1;
  38 + remoteGlobalIDString = 734C379315414CE200994189;
  39 + remoteInfo = LaunchAtLoginHelper;
  40 + };
  41 +/* End PBXContainerItemProxy section */
  42 +
  43 +/* Begin PBXCopyFilesBuildPhase section */
  44 + 28FEDA5B15DA5B5900320B72 /* CopyFiles */ = {
  45 + isa = PBXCopyFilesBuildPhase;
  46 + buildActionMask = 2147483647;
  47 + dstPath = Contents/Library/LoginItems;
  48 + dstSubfolderSpec = 1;
  49 + files = (
  50 + 28FEDA6E15DA5ECA00320B72 /* LaunchAtLoginHelper.app in CopyFiles */,
  51 + );
  52 + runOnlyForDeploymentPostprocessing = 0;
  53 + };
  54 +/* End PBXCopyFilesBuildPhase section */
  55 +
23 56 /* Begin PBXFileReference section */
24 57 2841C7DC15C91CC100F4F15F /* Battery Time Remaining.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Battery Time Remaining.app"; sourceTree = BUILT_PRODUCTS_DIR; };
25 58 2841C7E015C91CC100F4F15F /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
@@ -40,6 +73,11 @@
40 73 28833BB315D7D61100741727 /* build_version */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = build_version; sourceTree = SOURCE_ROOT; };
41 74 28BA61A715D1B12500EDB674 /* icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = icon.icns; path = ../icon.icns; sourceTree = "<group>"; };
42 75 28BA61A915D1B63300EDB674 /* Battery Time Remaining.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "Battery Time Remaining.entitlements"; sourceTree = "<group>"; };
  76 + 28FEDA5D15DA5C9D00320B72 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; };
  77 + 28FEDA5F15DA5EB200320B72 /* LaunchAtLoginHelper.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = LaunchAtLoginHelper.xcodeproj; path = LaunchAtLoginHelper/LaunchAtLoginHelper.xcodeproj; sourceTree = "<group>"; };
  78 + 28FEDA6215DA5EB200320B72 /* LLManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = LLManager.h; path = ../LaunchAtLoginHelper/LLManager.h; sourceTree = "<group>"; };
  79 + 28FEDA6315DA5EB200320B72 /* LLManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = LLManager.m; path = ../LaunchAtLoginHelper/LLManager.m; sourceTree = "<group>"; };
  80 + 28FEDA6415DA5EB200320B72 /* LLStrings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = LLStrings.h; path = ../LaunchAtLoginHelper/LLStrings.h; sourceTree = "<group>"; };
43 81 D58C7EF615CD7C6100C07E0C /* StartAtLoginHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StartAtLoginHelper.h; sourceTree = "<group>"; };
44 82 D58C7EF715CD7C6100C07E0C /* StartAtLoginHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StartAtLoginHelper.m; sourceTree = "<group>"; };
45 83 /* End PBXFileReference section */
@@ -49,6 +87,7 @@
49 87 isa = PBXFrameworksBuildPhase;
50 88 buildActionMask = 2147483647;
51 89 files = (
  90 + 28FEDA5E15DA5C9D00320B72 /* ServiceManagement.framework in Frameworks */,
52 91 2841C7FE15C91CEF00F4F15F /* IOKit.framework in Frameworks */,
53 92 2841C7E115C91CC100F4F15F /* Cocoa.framework in Frameworks */,
54 93 );
@@ -60,6 +99,7 @@
60 99 2841C7D115C91CC100F4F15F = {
61 100 isa = PBXGroup;
62 101 children = (
  102 + 28FEDA5F15DA5EB200320B72 /* LaunchAtLoginHelper.xcodeproj */,
63 103 2841C7E615C91CC100F4F15F /* Battery Time Remaining */,
64 104 2841C7DF15C91CC100F4F15F /* Frameworks */,
65 105 2841C7DD15C91CC100F4F15F /* Products */,
@@ -77,6 +117,7 @@
77 117 2841C7DF15C91CC100F4F15F /* Frameworks */ = {
78 118 isa = PBXGroup;
79 119 children = (
  120 + 28FEDA5D15DA5C9D00320B72 /* ServiceManagement.framework */,
80 121 2841C7FD15C91CEF00F4F15F /* IOKit.framework */,
81 122 2841C7E015C91CC100F4F15F /* Cocoa.framework */,
82 123 2841C7E215C91CC100F4F15F /* Other Frameworks */,
@@ -97,6 +138,9 @@
97 138 2841C7E615C91CC100F4F15F /* Battery Time Remaining */ = {
98 139 isa = PBXGroup;
99 140 children = (
  141 + 28FEDA6215DA5EB200320B72 /* LLManager.h */,
  142 + 28FEDA6315DA5EB200320B72 /* LLManager.m */,
  143 + 28FEDA6415DA5EB200320B72 /* LLStrings.h */,
100 144 2841C7F215C91CC100F4F15F /* AppDelegate.h */,
101 145 2841C7F315C91CC100F4F15F /* AppDelegate.m */,
102 146 28833BAC15D7B90B00741727 /* HttpGet.h */,
@@ -124,6 +168,14 @@
124 168 name = "Supporting Files";
125 169 sourceTree = "<group>";
126 170 };
  171 + 28FEDA6015DA5EB200320B72 /* Products */ = {
  172 + isa = PBXGroup;
  173 + children = (
  174 + 28FEDA6B15DA5EB200320B72 /* LaunchAtLoginHelper.app */,
  175 + );
  176 + name = Products;
  177 + sourceTree = "<group>";
  178 + };
127 179 /* End PBXGroup section */
128 180
129 181 /* Begin PBXNativeTarget section */
@@ -134,10 +186,12 @@
134 186 2841C7D815C91CC100F4F15F /* Sources */,
135 187 2841C7D915C91CC100F4F15F /* Frameworks */,
136 188 2841C7DA15C91CC100F4F15F /* Resources */,
  189 + 28FEDA5B15DA5B5900320B72 /* CopyFiles */,
137 190 );
138 191 buildRules = (
139 192 );
140 193 dependencies = (
  194 + 28FEDA6D15DA5EC200320B72 /* PBXTargetDependency */,
141 195 );
142 196 name = "Battery Time Remaining";
143 197 productName = "Battery Time Remaining";
@@ -163,6 +217,12 @@
163 217 mainGroup = 2841C7D115C91CC100F4F15F;
164 218 productRefGroup = 2841C7DD15C91CC100F4F15F /* Products */;
165 219 projectDirPath = "";
  220 + projectReferences = (
  221 + {
  222 + ProductGroup = 28FEDA6015DA5EB200320B72 /* Products */;
  223 + ProjectRef = 28FEDA5F15DA5EB200320B72 /* LaunchAtLoginHelper.xcodeproj */;
  224 + },
  225 + );
166 226 projectRoot = "";
167 227 targets = (
168 228 2841C7DB15C91CC100F4F15F /* Battery Time Remaining */,
@@ -170,6 +230,16 @@
170 230 };
171 231 /* End PBXProject section */
172 232
  233 +/* Begin PBXReferenceProxy section */
  234 + 28FEDA6B15DA5EB200320B72 /* LaunchAtLoginHelper.app */ = {
  235 + isa = PBXReferenceProxy;
  236 + fileType = wrapper.application;
  237 + path = LaunchAtLoginHelper.app;
  238 + remoteRef = 28FEDA6A15DA5EB200320B72 /* PBXContainerItemProxy */;
  239 + sourceTree = BUILT_PRODUCTS_DIR;
  240 + };
  241 +/* End PBXReferenceProxy section */
  242 +
173 243 /* Begin PBXResourcesBuildPhase section */
174 244 2841C7DA15C91CC100F4F15F /* Resources */ = {
175 245 isa = PBXResourcesBuildPhase;
@@ -190,6 +260,7 @@
190 260 isa = PBXSourcesBuildPhase;
191 261 buildActionMask = 2147483647;
192 262 files = (
  263 + 28FEDA6F15DA5F8C00320B72 /* LLManager.m in Sources */,
193 264 2841C7ED15C91CC100F4F15F /* main.m in Sources */,
194 265 2841C7F415C91CC100F4F15F /* AppDelegate.m in Sources */,
195 266 D58C7EF815CD7C6100C07E0C /* StartAtLoginHelper.m in Sources */,
@@ -199,6 +270,14 @@
199 270 };
200 271 /* End PBXSourcesBuildPhase section */
201 272
  273 +/* Begin PBXTargetDependency section */
  274 + 28FEDA6D15DA5EC200320B72 /* PBXTargetDependency */ = {
  275 + isa = PBXTargetDependency;
  276 + name = LaunchAtLoginHelper;
  277 + targetProxy = 28FEDA6C15DA5EC200320B72 /* PBXContainerItemProxy */;
  278 + };
  279 +/* End PBXTargetDependency section */
  280 +
202 281 /* Begin PBXVariantGroup section */
203 282 2841C7E915C91CC100F4F15F /* InfoPlist.strings */ = {
204 283 isa = PBXVariantGroup;
@@ -271,6 +350,7 @@
271 350 2841C7FB15C91CC200F4F15F /* Debug */ = {
272 351 isa = XCBuildConfiguration;
273 352 buildSettings = {
  353 + CODE_SIGN_ENTITLEMENTS = "Battery Time Remaining/Battery Time Remaining.entitlements";
274 354 CODE_SIGN_IDENTITY = "Developer ID Application: Han Lin Yap";
275 355 COMBINE_HIDPI_IMAGES = YES;
276 356 GCC_PRECOMPILE_PREFIX_HEADER = YES;
@@ -285,6 +365,7 @@
285 365 2841C7FC15C91CC200F4F15F /* Release */ = {
286 366 isa = XCBuildConfiguration;
287 367 buildSettings = {
  368 + CODE_SIGN_ENTITLEMENTS = "Battery Time Remaining/Battery Time Remaining.entitlements";
288 369 CODE_SIGN_IDENTITY = "Developer ID Application: Han Lin Yap";
289 370 COMBINE_HIDPI_IMAGES = YES;
290 371 GCC_PRECOMPILE_PREFIX_HEADER = YES;
1  Battery Time Remaining/AppDelegate.h
@@ -12,6 +12,7 @@
12 12
13 13 - (void)updateStatusItem;
14 14 - (NSImage *)getBatteryIconNamed:(NSString *)iconName;
  15 +- (NSImage *)getBatteryIconPercent:(NSInteger)percent;
15 16
16 17 @property (strong) NSStatusItem *statusItem;
17 18 @property (strong) NSMenuItem *startupToggle;
96 Battery Time Remaining/AppDelegate.m
@@ -8,6 +8,7 @@
8 8
9 9 #import "AppDelegate.h"
10 10 #import "HttpGet.h"
  11 +#import "LLManager.h"
11 12 #import "StartAtLoginHelper.h"
12 13 #import <IOKit/ps/IOPowerSources.h>
13 14 #import <IOKit/ps/IOPSKeys.h>
@@ -53,7 +54,8 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
53 54 // Create the startup at login toggle
54 55 self.startupToggle = [[NSMenuItem alloc] initWithTitle:@"Start at login" action:@selector(toggleStartAtLogin:) keyEquivalent:@""];
55 56 self.startupToggle.target = self;
56   - self.startupToggle.state = ([StartAtLoginHelper isInLoginItems]) ? NSOnState : NSOffState;
  57 + self.startupToggle.state = ([LLManager launchAtLogin]) ? NSOnState : NSOffState;
  58 + //self.startupToggle.state = ([StartAtLoginHelper isInLoginItems]) ? NSOnState : NSOffState;
57 59 #endif
58 60
59 61 // Build the notification submenu
@@ -170,8 +172,12 @@ - (void)updateStatusItem
170 172 NSNumber *currentBatteryCapacity = CFDictionaryGetValue(description, CFSTR(kIOPSCurrentCapacityKey));
171 173 NSNumber *maxBatteryCapacity = CFDictionaryGetValue(description, CFSTR(kIOPSMaxCapacityKey));
172 174
173   - if ([currentBatteryCapacity intValue] == [maxBatteryCapacity intValue]) {
  175 + if ([currentBatteryCapacity intValue] == [maxBatteryCapacity intValue] &&
  176 + self.previousPercent != percent &&
  177 + [[self.notifications valueForKey:@"100"] boolValue]) {
  178 +
174 179 [self notify:@"Charged"];
  180 + self.previousPercent = percent;
175 181 }
176 182 }
177 183
@@ -179,7 +185,7 @@ - (void)updateStatusItem
179 185 // Still calculating the estimated time remaining...
180 186 else if (kIOPSTimeRemainingUnknown == timeRemaining)
181 187 {
182   - self.statusItem.image = [self getBatteryIconNamed:@"BatteryEmpty"];
  188 + self.statusItem.image = [self getBatteryIconPercent:percent];
183 189 self.statusItem.title = @" Calculating…";
184 190 }
185 191 // Time is known!
@@ -189,36 +195,8 @@ - (void)updateStatusItem
189 195 NSInteger hour = (int)timeRemaining / 3600;
190 196 NSInteger minute = (int)timeRemaining % 3600 / 60;
191 197
192   - // Make dynamic battery icon
193   - NSImage *batteryDynamic = [self getBatteryIconNamed:@"BatteryEmpty"];
194   -
195   - [batteryDynamic lockFocus];
196   -
197   - NSRect sourceRect;
198   - sourceRect.origin = NSZeroPoint;
199   - sourceRect.origin.x += [batteryDynamic size].width / 100 * 15;
200   - sourceRect.origin.y += [batteryDynamic size].height / 50 * 15;
201   - sourceRect.size = [batteryDynamic size];
202   - sourceRect.size.width -= [batteryDynamic size].width / 100 * 43;
203   - sourceRect.size.height -= [batteryDynamic size].height / 50 * 30;
204   -
205   - sourceRect.size.width -= [batteryDynamic size].width / 100 * (60.f - (60.f / 100.f * percent));
206   -
207   - if (percent > 15)
208   - {
209   - [[NSColor blackColor] set];
210   - }
211   - else
212   - {
213   - [[NSColor redColor] set];
214   - }
215   -
216   - NSRectFill(sourceRect);
217   -
218   - [batteryDynamic unlockFocus];
219   -
220 198 // Return the time remaining string
221   - self.statusItem.image = batteryDynamic;
  199 + self.statusItem.image = [self getBatteryIconPercent:percent];
222 200 self.statusItem.title = [NSString stringWithFormat:@" %ld:%02ld", hour, minute];
223 201
224 202 for (NSString *key in self.notifications) {
@@ -236,6 +214,39 @@ - (void)updateStatusItem
236 214 }
237 215 }
238 216
  217 +- (NSImage *)getBatteryIconPercent:(NSInteger)percent
  218 +{
  219 + // Make dynamic battery icon
  220 + NSImage *batteryDynamic = [self getBatteryIconNamed:@"BatteryEmpty"];
  221 +
  222 + [batteryDynamic lockFocus];
  223 +
  224 + NSRect sourceRect;
  225 + sourceRect.origin = NSZeroPoint;
  226 + sourceRect.origin.x += [batteryDynamic size].width / 100 * 15;
  227 + sourceRect.origin.y += [batteryDynamic size].height / 50 * 15;
  228 + sourceRect.size = [batteryDynamic size];
  229 + sourceRect.size.width -= [batteryDynamic size].width / 100 * 43;
  230 + sourceRect.size.height -= [batteryDynamic size].height / 50 * 30;
  231 +
  232 + sourceRect.size.width -= [batteryDynamic size].width / 100 * (60.f - (60.f / 100.f * percent));
  233 +
  234 + if (percent > 15)
  235 + {
  236 + [[NSColor blackColor] set];
  237 + }
  238 + else
  239 + {
  240 + [[NSColor redColor] set];
  241 + }
  242 +
  243 + NSRectFill(sourceRect);
  244 +
  245 + [batteryDynamic unlockFocus];
  246 +
  247 + return batteryDynamic;
  248 +}
  249 +
239 250 - (NSImage *)getBatteryIconNamed:(NSString *)iconName
240 251 {
241 252 NSString *fileName = [NSString stringWithFormat:@"/System/Library/CoreServices/Menu Extras/Battery.menu/Contents/Resources/%@.pdf", iconName];
@@ -255,6 +266,14 @@ - (void)openHomeUrl:(id)sender
255 266 #ifndef SANDBOX
256 267 - (void)toggleStartAtLogin:(id)sender
257 268 {
  269 + if ([LLManager launchAtLogin]) {
  270 + [LLManager setLaunchAtLogin:NO];
  271 + self.startupToggle.state = NSOffState;
  272 + } else {
  273 + [LLManager setLaunchAtLogin:YES];
  274 + self.startupToggle.state = NSOnState;
  275 + }
  276 + /*
258 277 // Check the state of start at login
259 278 if ([StartAtLoginHelper isInLoginItems])
260 279 {
@@ -265,7 +284,7 @@ - (void)toggleStartAtLogin:(id)sender
265 284 {
266 285 [StartAtLoginHelper addToLoginItems];
267 286 self.startupToggle.state = NSOnState;
268   - }
  287 + }*/
269 288 }
270 289 #endif
271 290
@@ -312,12 +331,23 @@ - (void)toggleNotification:(id)sender
312 331 [self saveNotificationSettings];
313 332 }
314 333
  334 +#pragma mark - NSUserNotificationCenterDelegate methods
  335 +
315 336 // Force show notification
316 337 - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification
317 338 {
318 339 return YES;
319 340 }
320 341
  342 +- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
  343 +{
  344 + if ([[notification informativeText] isEqualToString:@"A newer version is available"]) {
  345 + [self openHomeUrl:nil];
  346 + }
  347 +}
  348 +
  349 +#pragma mark - NSMenuDelegate methods
  350 +
321 351 - (void)menuWillOpen:(NSMenu *)menu
322 352 {
323 353 // Stop checking if newer version is available
17 Battery Time Remaining/Battery Time Remaining-Info.plist
@@ -17,11 +17,24 @@
17 17 <key>CFBundlePackageType</key>
18 18 <string>APPL</string>
19 19 <key>CFBundleShortVersionString</key>
20   - <string>1.3</string>
  20 + <string>1.4</string>
21 21 <key>CFBundleSignature</key>
22 22 <string>????</string>
  23 + <key>CFBundleURLTypes</key>
  24 + <array>
  25 + <dict>
  26 + <key>CFBundleTypeRole</key>
  27 + <string>Viewer</string>
  28 + <key>CFBundleURLName</key>
  29 + <string>com.codler.${PRODUCT_NAME:rfc1034identifier}</string>
  30 + <key>CFBundleURLSchemes</key>
  31 + <array>
  32 + <string>com.codler.Battery-Time-Remaining</string>
  33 + </array>
  34 + </dict>
  35 + </array>
23 36 <key>CFBundleVersion</key>
24   - <string>6</string>
  37 + <string>7</string>
25 38 <key>LSApplicationCategoryType</key>
26 39 <string>public.app-category.utilities</string>
27 40 <key>LSMinimumSystemVersion</key>
18 LaunchAtLoginHelper/LLManager.h
... ... @@ -0,0 +1,18 @@
  1 +//
  2 +// LLManager.h
  3 +// LaunchAtLogin
  4 +//
  5 +// Created by David Keegan on 4/20/12.
  6 +// Copyright (c) 2012 David Keegan. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +
  11 +@interface LLManager : NSObject
  12 +
  13 ++ (BOOL)launchAtLogin;
  14 ++ (void)setLaunchAtLogin:(BOOL)value;
  15 +
  16 +@property (assign) BOOL launchAtLogin;
  17 +
  18 +@end
53 LaunchAtLoginHelper/LLManager.m
... ... @@ -0,0 +1,53 @@
  1 +//
  2 +// LLManager.m
  3 +// LaunchAtLogin
  4 +//
  5 +// Created by David Keegan on 4/20/12.
  6 +// Copyright (c) 2012 David Keegan. All rights reserved.
  7 +//
  8 +
  9 +#import "LLManager.h"
  10 +#import "LLStrings.h"
  11 +#import <ServiceManagement/ServiceManagement.h>
  12 +
  13 +@implementation LLManager
  14 +
  15 ++ (BOOL)launchAtLogin{
  16 + BOOL launch = NO;
  17 + CFArrayRef cfJobs = SMCopyAllJobDictionaries(kSMDomainUserLaunchd);
  18 +#if __has_feature(objc_arc)
  19 + NSArray *jobs = [NSArray arrayWithArray:(__bridge NSArray *)cfJobs];
  20 +#else
  21 + NSArray *jobs = [NSArray arrayWithArray:(NSArray *)cfJobs];
  22 +#endif
  23 + CFRelease(cfJobs);
  24 + if([jobs count]){
  25 + for(NSDictionary *job in jobs){
  26 + if([job[@"Label"] isEqualToString:LLHelperBundleIdentifier]){
  27 + launch = [job[@"OnDemand"] boolValue];
  28 + break;
  29 + }
  30 + }
  31 + }
  32 + return launch;
  33 +}
  34 +
  35 ++ (void)setLaunchAtLogin:(BOOL)value{
  36 + if(!SMLoginItemSetEnabled((CFStringRef)LLHelperBundleIdentifier, value)){
  37 + NSLog(@"SMLoginItemSetEnabled failed!");
  38 + }
  39 +}
  40 +
  41 +#pragma mark - Bindings support
  42 +
  43 +- (BOOL)launchAtLogin {
  44 + return [[self class] launchAtLogin];
  45 +}
  46 +
  47 +- (void)setLaunchAtLogin:(BOOL)launchAtLogin {
  48 + [self willChangeValueForKey:@"launchAtLogin"];
  49 + [[self class] setLaunchAtLogin:launchAtLogin];
  50 + [self didChangeValueForKey:@"launchAtLogin"];
  51 +}
  52 +
  53 +@end
5 LaunchAtLoginHelper/LLStrings.h
... ... @@ -0,0 +1,5 @@
  1 +// strings used by LLManager and LaunchAtLoginHelper
  2 +//
  3 +
  4 +#define LLURLScheme @"com.codler.Battery-Time-Remaining"
  5 +#define LLHelperBundleIdentifier @"com.codler.Battery-Time-Remaining-Helper"
243 LaunchAtLoginHelper/LaunchAtLoginHelper.xcodeproj/project.pbxproj
... ... @@ -0,0 +1,243 @@
  1 +// !$*UTF8*$!
  2 +{
  3 + archiveVersion = 1;
  4 + classes = {
  5 + };
  6 + objectVersion = 46;
  7 + objects = {
  8 +
  9 +/* Begin PBXBuildFile section */
  10 + 734C379915414CE200994189 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 734C379815414CE200994189 /* Cocoa.framework */; };
  11 + 73C920E915414E7800C2A75A /* LLHAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 73C920E615414E7800C2A75A /* LLHAppDelegate.m */; };
  12 + 73C920EA15414E7800C2A75A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 73C920E715414E7800C2A75A /* main.m */; };
  13 + 73C920EB15414E7800C2A75A /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73C920E815414E7800C2A75A /* MainMenu.xib */; };
  14 +/* End PBXBuildFile section */
  15 +
  16 +/* Begin PBXFileReference section */
  17 + 734C379415414CE200994189 /* LaunchAtLoginHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LaunchAtLoginHelper.app; sourceTree = BUILT_PRODUCTS_DIR; };
  18 + 734C379815414CE200994189 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
  19 + 734C379B15414CE200994189 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
  20 + 734C379D15414CE200994189 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
  21 + 73C920E515414E7800C2A75A /* LLHAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLHAppDelegate.h; path = LaunchAtLoginHelper/LLHAppDelegate.h; sourceTree = "<group>"; };
  22 + 73C920E615414E7800C2A75A /* LLHAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LLHAppDelegate.m; path = LaunchAtLoginHelper/LLHAppDelegate.m; sourceTree = "<group>"; };
  23 + 73C920E715414E7800C2A75A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = LaunchAtLoginHelper/main.m; sourceTree = "<group>"; };
  24 + 73C920E815414E7800C2A75A /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = MainMenu.xib; path = LaunchAtLoginHelper/MainMenu.xib; sourceTree = "<group>"; };
  25 + 73C920FA15414F7000C2A75A /* LLStrings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LLStrings.h; sourceTree = SOURCE_ROOT; };
  26 + 73C920FB15414FC900C2A75A /* LaunchAtLoginHelper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = LaunchAtLoginHelper.entitlements; path = LaunchAtLoginHelper/LaunchAtLoginHelper.entitlements; sourceTree = "<group>"; };
  27 +/* End PBXFileReference section */
  28 +
  29 +/* Begin PBXFrameworksBuildPhase section */
  30 + 734C379115414CE200994189 /* Frameworks */ = {
  31 + isa = PBXFrameworksBuildPhase;
  32 + buildActionMask = 2147483647;
  33 + files = (
  34 + 734C379915414CE200994189 /* Cocoa.framework in Frameworks */,
  35 + );
  36 + runOnlyForDeploymentPostprocessing = 0;
  37 + };
  38 +/* End PBXFrameworksBuildPhase section */
  39 +
  40 +/* Begin PBXGroup section */
  41 + 734C378915414CE200994189 = {
  42 + isa = PBXGroup;
  43 + children = (
  44 + 73C920E715414E7800C2A75A /* main.m */,
  45 + 73C920FA15414F7000C2A75A /* LLStrings.h */,
  46 + 73C920E515414E7800C2A75A /* LLHAppDelegate.h */,
  47 + 73C920E615414E7800C2A75A /* LLHAppDelegate.m */,
  48 + 73C920E815414E7800C2A75A /* MainMenu.xib */,
  49 + 73C920FB15414FC900C2A75A /* LaunchAtLoginHelper.entitlements */,
  50 + 734C379715414CE200994189 /* Frameworks */,
  51 + 734C379515414CE200994189 /* Products */,
  52 + );
  53 + sourceTree = "<group>";
  54 + };
  55 + 734C379515414CE200994189 /* Products */ = {
  56 + isa = PBXGroup;
  57 + children = (
  58 + 734C379415414CE200994189 /* LaunchAtLoginHelper.app */,
  59 + );
  60 + name = Products;
  61 + sourceTree = "<group>";
  62 + };
  63 + 734C379715414CE200994189 /* Frameworks */ = {
  64 + isa = PBXGroup;
  65 + children = (
  66 + 734C379B15414CE200994189 /* AppKit.framework */,
  67 + 734C379D15414CE200994189 /* Foundation.framework */,
  68 + 734C379815414CE200994189 /* Cocoa.framework */,
  69 + );
  70 + name = Frameworks;
  71 + sourceTree = "<group>";
  72 + };
  73 +/* End PBXGroup section */
  74 +
  75 +/* Begin PBXNativeTarget section */
  76 + 734C379315414CE200994189 /* LaunchAtLoginHelper */ = {
  77 + isa = PBXNativeTarget;
  78 + buildConfigurationList = 734C37B215414CE200994189 /* Build configuration list for PBXNativeTarget "LaunchAtLoginHelper" */;
  79 + buildPhases = (
  80 + 734C379015414CE200994189 /* Sources */,
  81 + 734C379115414CE200994189 /* Frameworks */,
  82 + 734C379215414CE200994189 /* Resources */,
  83 + );
  84 + buildRules = (
  85 + );
  86 + dependencies = (
  87 + );
  88 + name = LaunchAtLoginHelper;
  89 + productName = LaunchAtLoginHelper;
  90 + productReference = 734C379415414CE200994189 /* LaunchAtLoginHelper.app */;
  91 + productType = "com.apple.product-type.application";
  92 + };
  93 +/* End PBXNativeTarget section */
  94 +
  95 +/* Begin PBXProject section */
  96 + 734C378B15414CE200994189 /* Project object */ = {
  97 + isa = PBXProject;
  98 + attributes = {
  99 + CLASSPREFIX = LLH;
  100 + LastUpgradeCheck = 0450;
  101 + ORGANIZATIONNAME = "David Keegan";
  102 + };
  103 + buildConfigurationList = 734C378E15414CE200994189 /* Build configuration list for PBXProject "LaunchAtLoginHelper" */;
  104 + compatibilityVersion = "Xcode 3.2";
  105 + developmentRegion = English;
  106 + hasScannedForEncodings = 0;
  107 + knownRegions = (
  108 + en,
  109 + );
  110 + mainGroup = 734C378915414CE200994189;
  111 + productRefGroup = 734C379515414CE200994189 /* Products */;
  112 + projectDirPath = "";
  113 + projectRoot = "";
  114 + targets = (
  115 + 734C379315414CE200994189 /* LaunchAtLoginHelper */,
  116 + );
  117 + };
  118 +/* End PBXProject section */
  119 +
  120 +/* Begin PBXResourcesBuildPhase section */
  121 + 734C379215414CE200994189 /* Resources */ = {
  122 + isa = PBXResourcesBuildPhase;
  123 + buildActionMask = 2147483647;
  124 + files = (
  125 + 73C920EB15414E7800C2A75A /* MainMenu.xib in Resources */,
  126 + );
  127 + runOnlyForDeploymentPostprocessing = 0;
  128 + };
  129 +/* End PBXResourcesBuildPhase section */
  130 +
  131 +/* Begin PBXSourcesBuildPhase section */
  132 + 734C379015414CE200994189 /* Sources */ = {
  133 + isa = PBXSourcesBuildPhase;
  134 + buildActionMask = 2147483647;
  135 + files = (
  136 + 73C920E915414E7800C2A75A /* LLHAppDelegate.m in Sources */,
  137 + 73C920EA15414E7800C2A75A /* main.m in Sources */,
  138 + );
  139 + runOnlyForDeploymentPostprocessing = 0;
  140 + };
  141 +/* End PBXSourcesBuildPhase section */
  142 +
  143 +/* Begin XCBuildConfiguration section */
  144 + 734C37B015414CE200994189 /* Debug */ = {
  145 + isa = XCBuildConfiguration;
  146 + buildSettings = {
  147 + ALWAYS_SEARCH_USER_PATHS = NO;
  148 + ARCHS = "$(ARCHS_STANDARD_64_BIT)";
  149 + COMBINE_HIDPI_IMAGES = YES;
  150 + COPY_PHASE_STRIP = NO;
  151 + GCC_C_LANGUAGE_STANDARD = gnu99;
  152 + GCC_DYNAMIC_NO_PIC = NO;
  153 + GCC_ENABLE_OBJC_EXCEPTIONS = YES;
  154 + GCC_OPTIMIZATION_LEVEL = 0;
  155 + GCC_PREPROCESSOR_DEFINITIONS = (
  156 + "DEBUG=1",
  157 + "$(inherited)",
  158 + );
  159 + GCC_SYMBOLS_PRIVATE_EXTERN = NO;
  160 + GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
  161 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
  162 + GCC_WARN_ABOUT_RETURN_TYPE = YES;
  163 + GCC_WARN_UNINITIALIZED_AUTOS = YES;
  164 + GCC_WARN_UNUSED_VARIABLE = YES;
  165 + MACOSX_DEPLOYMENT_TARGET = 10.6;
  166 + ONLY_ACTIVE_ARCH = YES;
  167 + SDKROOT = macosx;
  168 + SKIP_INSTALL = YES;
  169 + };
  170 + name = Debug;
  171 + };
  172 + 734C37B115414CE200994189 /* Release */ = {
  173 + isa = XCBuildConfiguration;
  174 + buildSettings = {
  175 + ALWAYS_SEARCH_USER_PATHS = NO;
  176 + ARCHS = "$(ARCHS_STANDARD_64_BIT)";
  177 + COMBINE_HIDPI_IMAGES = YES;
  178 + COPY_PHASE_STRIP = YES;
  179 + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
  180 + GCC_C_LANGUAGE_STANDARD = gnu99;
  181 + GCC_ENABLE_OBJC_EXCEPTIONS = YES;
  182 + GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
  183 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
  184 + GCC_WARN_ABOUT_RETURN_TYPE = YES;
  185 + GCC_WARN_UNINITIALIZED_AUTOS = YES;
  186 + GCC_WARN_UNUSED_VARIABLE = YES;
  187 + MACOSX_DEPLOYMENT_TARGET = 10.6;
  188 + SDKROOT = macosx;
  189 + SKIP_INSTALL = YES;
  190 + };
  191 + name = Release;
  192 + };
  193 + 734C37B315414CE200994189 /* Debug */ = {
  194 + isa = XCBuildConfiguration;
  195 + buildSettings = {
  196 + CODE_SIGN_ENTITLEMENTS = LaunchAtLoginHelper/LaunchAtLoginHelper.entitlements;
  197 + CODE_SIGN_IDENTITY = "Mac Developer";
  198 + INFOPLIST_FILE = "LaunchAtLoginHelper/LaunchAtLoginHelper-Info.plist";
  199 + MACOSX_DEPLOYMENT_TARGET = 10.6.8;
  200 + PRODUCT_NAME = "$(TARGET_NAME)";
  201 + PROVISIONING_PROFILE = "";
  202 + WRAPPER_EXTENSION = app;
  203 + };
  204 + name = Debug;
  205 + };
  206 + 734C37B415414CE200994189 /* Release */ = {
  207 + isa = XCBuildConfiguration;
  208 + buildSettings = {
  209 + CODE_SIGN_ENTITLEMENTS = LaunchAtLoginHelper/LaunchAtLoginHelper.entitlements;
  210 + CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application";
  211 + INFOPLIST_FILE = "LaunchAtLoginHelper/LaunchAtLoginHelper-Info.plist";
  212 + MACOSX_DEPLOYMENT_TARGET = 10.6.8;
  213 + PRODUCT_NAME = "$(TARGET_NAME)";
  214 + PROVISIONING_PROFILE = "";
  215 + WRAPPER_EXTENSION = app;
  216 + };
  217 + name = Release;
  218 + };
  219 +/* End XCBuildConfiguration section */
  220 +
  221 +/* Begin XCConfigurationList section */
  222 + 734C378E15414CE200994189 /* Build configuration list for PBXProject "LaunchAtLoginHelper" */ = {
  223 + isa = XCConfigurationList;
  224 + buildConfigurations = (
  225 + 734C37B015414CE200994189 /* Debug */,
  226 + 734C37B115414CE200994189 /* Release */,
  227 + );
  228 + defaultConfigurationIsVisible = 0;
  229 + defaultConfigurationName = Release;
  230 + };
  231 + 734C37B215414CE200994189 /* Build configuration list for PBXNativeTarget "LaunchAtLoginHelper" */ = {
  232 + isa = XCConfigurationList;
  233 + buildConfigurations = (
  234 + 734C37B315414CE200994189 /* Debug */,
  235 + 734C37B415414CE200994189 /* Release */,
  236 + );
  237 + defaultConfigurationIsVisible = 0;
  238 + defaultConfigurationName = Release;
  239 + };
  240 +/* End XCConfigurationList section */
  241 + };
  242 + rootObject = 734C378B15414CE200994189 /* Project object */;
  243 +}
13 LaunchAtLoginHelper/LaunchAtLoginHelper/LLHAppDelegate.h
... ... @@ -0,0 +1,13 @@
  1 +//
  2 +// LLHAppDelegate.h
  3 +// LaunchAtLoginHelper
  4 +//
  5 +// Created by David Keegan on 4/20/12.
  6 +// Copyright (c) 2012 David Keegan. All rights reserved.
  7 +//
  8 +
  9 +#import <Cocoa/Cocoa.h>
  10 +
  11 +@interface LLHAppDelegate : NSObject <NSApplicationDelegate>
  12 +
  13 +@end
26 LaunchAtLoginHelper/LaunchAtLoginHelper/LLHAppDelegate.m
... ... @@ -0,0 +1,26 @@
  1 +//
  2 +// LLHAppDelegate.m
  3 +// LaunchAtLoginHelper
  4 +//
  5 +// Created by David Keegan on 4/20/12.
  6 +// Copyright (c) 2012 David Keegan. All rights reserved.
  7 +//
  8 +
  9 +#import "LLHAppDelegate.h"
  10 +#import "LLStrings.h"
  11 +
  12 +@implementation LLHAppDelegate
  13 +
  14 +- (void)applicationDidFinishLaunching:(NSNotification *)notification{
  15 + // Call the scheme to launch the app
  16 + NSString *scheme = [NSString stringWithFormat:@"%@://", LLURLScheme];
  17 + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:scheme]];
  18 +
  19 + // Call the app again this time with `launchedAtLogin` so it knows how it was launched
  20 + NSString *schemeLaunchedAtLogin =
  21 + [NSString stringWithFormat:@"%@://launchedAtLogin", LLURLScheme];
  22 + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:schemeLaunchedAtLogin]];
  23 + [NSApp terminate:self];
  24 +}
  25 +
  26 +@end
36 LaunchAtLoginHelper/LaunchAtLoginHelper/LaunchAtLoginHelper-Info.plist
... ... @@ -0,0 +1,36 @@
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>CFBundleDevelopmentRegion</key>
  6 + <string>en</string>
  7 + <key>CFBundleExecutable</key>
  8 + <string>${EXECUTABLE_NAME}</string>
  9 + <key>CFBundleIconFile</key>
  10 + <string></string>
  11 + <key>CFBundleIdentifier</key>
  12 + <string>com.codler.Battery-Time-Remaining-Helper</string>
  13 + <key>CFBundleInfoDictionaryVersion</key>
  14 + <string>6.0</string>
  15 + <key>CFBundleName</key>
  16 + <string>${PRODUCT_NAME}</string>
  17 + <key>CFBundlePackageType</key>
  18 + <string>APPL</string>
  19 + <key>CFBundleShortVersionString</key>
  20 + <string>1.0</string>
  21 + <key>CFBundleSignature</key>
  22 + <string>????</string>
  23 + <key>CFBundleVersion</key>
  24 + <string>1</string>
  25 + <key>LSMinimumSystemVersion</key>
  26 + <string>${MACOSX_DEPLOYMENT_TARGET}</string>
  27 + <key>LSUIElement</key>
  28 + <true/>
  29 + <key>NSHumanReadableCopyright</key>
  30 + <string>Copyright © 2012 David Keegan. All rights reserved.</string>
  31 + <key>NSMainNibFile</key>
  32 + <string>MainMenu</string>
  33 + <key>NSPrincipalClass</key>
  34 + <string>NSApplication</string>
  35 +</dict>
  36 +</plist>
36 LaunchAtLoginHelper/LaunchAtLoginHelper/LaunchAtLoginHelper-InfoBase.plist
... ... @@ -0,0 +1,36 @@
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>CFBundleDevelopmentRegion</key>
  6 + <string>en</string>
  7 + <key>CFBundleExecutable</key>
  8 + <string>${EXECUTABLE_NAME}</string>
  9 + <key>CFBundleIconFile</key>
  10 + <string></string>
  11 + <key>CFBundleIdentifier</key>
  12 + <string>com.InScopeApps.ShellTo.${PRODUCT_NAME:rfc1034identifier}</string>
  13 + <key>CFBundleInfoDictionaryVersion</key>
  14 + <string>6.0</string>
  15 + <key>CFBundleName</key>
  16 + <string>${PRODUCT_NAME}</string>
  17 + <key>CFBundlePackageType</key>
  18 + <string>APPL</string>
  19 + <key>CFBundleShortVersionString</key>
  20 + <string>1.0</string>
  21 + <key>CFBundleSignature</key>
  22 + <string>????</string>
  23 + <key>CFBundleVersion</key>
  24 + <string>1</string>
  25 + <key>LSMinimumSystemVersion</key>
  26 + <string>${MACOSX_DEPLOYMENT_TARGET}</string>
  27 + <key>LSUIElement</key>
  28 + <true/>
  29 + <key>NSHumanReadableCopyright</key>
  30 + <string>Copyright © 2012 David Keegan. All rights reserved.</string>
  31 + <key>NSMainNibFile</key>
  32 + <string>MainMenu</string>
  33 + <key>NSPrincipalClass</key>
  34 + <string>NSApplication</string>
  35 +</dict>
  36 +</plist>
8 LaunchAtLoginHelper/LaunchAtLoginHelper/LaunchAtLoginHelper.entitlements
... ... @@ -0,0 +1,8 @@
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>com.apple.security.app-sandbox</key>
  6 + <true/>
  7 +</dict>
  8 +</plist>
104 LaunchAtLoginHelper/LaunchAtLoginHelper/MainMenu.xib
... ... @@ -0,0 +1,104 @@
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00">
  3 + <data>
  4 + <int key="IBDocument.SystemTarget">1070</int>
  5 + <string key="IBDocument.SystemVersion">11D50</string>
  6 + <string key="IBDocument.InterfaceBuilderVersion">2182</string>
  7 + <string key="IBDocument.AppKitVersion">1138.32</string>
  8 + <string key="IBDocument.HIToolboxVersion">568.00</string>
  9 + <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
  10 + <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
  11 + <string key="NS.object.0">2182</string>
  12 + </object>
  13 + <array key="IBDocument.IntegratedClassDependencies">
  14 + <string>NSCustomObject</string>
  15 + </array>
  16 + <array key="IBDocument.PluginDependencies">
  17 + <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
  18 + </array>
  19 + <object class="NSMutableDictionary" key="IBDocument.Metadata">
  20 + <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
  21 + <integer value="1" key="NS.object.0"/>
  22 + </object>
  23 + <array class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
  24 + <object class="NSCustomObject" id="1021">
  25 + <string key="NSClassName">NSApplication</string>
  26 + </object>
  27 + <object class="NSCustomObject" id="1014">
  28 + <string key="NSClassName">FirstResponder</string>
  29 + </object>
  30 + <object class="NSCustomObject" id="1050">
  31 + <string key="NSClassName">NSApplication</string>
  32 + </object>
  33 + <object class="NSCustomObject" id="976324537">
  34 + <string key="NSClassName">LLHAppDelegate</string>
  35 + </object>
  36 + </array>
  37 + <object class="IBObjectContainer" key="IBDocument.Objects">
  38 + <array class="NSMutableArray" key="connectionRecords">
  39 + <object class="IBConnectionRecord">
  40 + <object class="IBOutletConnection" key="connection">
  41 + <string key="label">delegate</string>
  42 + <reference key="source" ref="1021"/>
  43 + <reference key="destination" ref="976324537"/>
  44 + </object>
  45 + <int key="connectionID">495</int>
  46 + </object>
  47 + </array>
  48 + <object class="IBMutableOrderedSet" key="objectRecords">
  49 + <array key="orderedObjects">
  50 + <object class="IBObjectRecord">
  51 + <int key="objectID">0</int>
  52 + <array key="object" id="0"/>
  53 + <reference key="children" ref="1048"/>
  54 + <nil key="parent"/>
  55 + </object>
  56 + <object class="IBObjectRecord">
  57 + <int key="objectID">-2</int>
  58 + <reference key="object" ref="1021"/>
  59 + <reference key="parent" ref="0"/>
  60 + <string key="objectName">File's Owner</string>
  61 + </object>
  62 + <object class="IBObjectRecord">
  63 + <int key="objectID">-1</int>
  64 + <reference key="object" ref="1014"/>
  65 + <reference key="parent" ref="0"/>
  66 + <string key="objectName">First Responder</string>
  67 + </object>
  68 + <object class="IBObjectRecord">
  69 + <int key="objectID">-3</int>
  70 + <reference key="object" ref="1050"/>
  71 + <reference key="parent" ref="0"/>
  72 + <string key="objectName">Application</string>
  73 + </object>
  74 + <object class="IBObjectRecord">
  75 + <int key="objectID">494</int>
  76 + <reference key="object" ref="976324537"/>
  77 + <reference key="parent" ref="0"/>
  78 + </object>
  79 + </array>
  80 + </object>
  81 + <dictionary class="NSMutableDictionary" key="flattenedProperties">
  82 + <string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
  83 + <string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
  84 + <string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
  85 + <string key="494.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
  86 + </dictionary>
  87 + <dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
  88 + <nil key="activeLocalization"/>
  89 + <dictionary class="NSMutableDictionary" key="localizations"/>
  90 + <nil key="sourceID"/>
  91 + <int key="maxID">535</int>
  92 + </object>
  93 + <object class="IBClassDescriber" key="IBDocument.Classes"/>
  94 + <int key="IBDocument.localizationMode">0</int>
  95 + <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
  96 + <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
  97 + <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
  98 + <integer value="1070" key="NS.object.0"/>
  99 + </object>
  100 + <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
  101 + <int key="IBDocument.defaultPropertyAccessControl">3</int>
  102 + <bool key="IBDocument.UseAutolayout">YES</bool>
  103 + </data>
  104 +</archive>
13 LaunchAtLoginHelper/LaunchAtLoginHelper/main.m
... ... @@ -0,0 +1,13 @@
  1 +//
  2 +// main.m
  3 +// LaunchAtLoginHelper
  4 +//
  5 +// Created by David Keegan on 4/20/12.
  6 +// Copyright (c) 2012 David Keegan. All rights reserved.
  7 +//
  8 +
  9 +#import <Cocoa/Cocoa.h>
  10 +
  11 +int main(int argc, char *argv[]){
  12 + return NSApplicationMain(argc, (const char **)argv);
  13 +}
56 LaunchAtLoginHelper/readme.md
Source Rendered
... ... @@ -0,0 +1,56 @@
  1 +When creating a sandboxed app `LSSharedFileListInsertItemURL` can no longer be used to launch the app at startup. Instead `SMLoginItemSetEnabled` should be used with a helper app inside the main app's bundle that launches the main app. **LaunchAtLoginHelper** is that helper app, it is designed to be as easy as possible to integrate into the main app to allow it to launch at login when sandboxed.
  2 +
  3 +A lot of research was put into this helper app. For example [Apple's docs](http://developer.apple.com/library/mac/#documentation/Security/Conceptual/AppSandboxDesignGuide/DesigningYourSandbox/DesigningYourSandbox.html#//apple_ref/doc/uid/TP40011183-CH4-SW3) state that `LSRegisterURL` should be used to register the helper app, however this never seemed to work and after further digging it turns out this is a [typo in the docs](https://devforums.apple.com/message/647212#647212). Many examples I found online used `NSWorkspace launchApplication:` to launch the main app, however this was blocked by sandboxing so a url scheme is used instead.
  4 +
  5 +**LaunchAtLoginHelper** calls the main app's scheme twice, once to launchg the app and then again with `launchedAtLogin` so the main app can know if it has been launched at login. For example [Play by Play](http://playbyplayapp.com) uses this to hide the app if it was launched at login.
  6 +
  7 +This project contains a [sample app](https://github.com/kgn/LaunchAtLoginHelper/tree/master/LaunchAtLoginSample) to demonstrate how the main app should be configured and how to setup a checkbox to enable and disable launching at login.
  8 +
  9 +# How to use
  10 +
  11 +First download or even better submodule **LaunchAtLoginHelper**. To clone the repository as a submodule use the following commands:
  12 +
  13 +```
  14 +$ cd <main_app_project>
  15 +$ git clone --recursive https://github.com/kgn/LaunchAtLoginHelper.git
  16 +```
  17 +
  18 +**LaunchAtLoginHelper** uses a url scheme to launch the main app, if the main app doesn't have a url scheme yet add one.
  19 +
  20 +![](http://kgn.github.com/content/launchatlogin/url_scheme.png)
  21 +
  22 +There are two files missing from this repo that are specific to your instance of the helper app. To generate these files run the `setup.py` python script and pass in the url scheme to launch the main app and the bundle identifier of the helper app, this is usually based of of the bundle identifier of the main app but with *Helper* added onto the end.
  23 +
  24 +```
  25 +$ cd LaunchAtLoginHelper
  26 +$ python setup.py <main_app_url_scheme> <helper_app_bundle_identifier>
  27 +```
  28 +
  29 +This will create `LLStrings.h` which is used in both the helper app and the main app and contains `#define`'s for the url scheme and the helper app's bundle identifier. `LaunchAtLoginHelper-Info.plist` is also created for the helper app with it's custom bundle identifier filled in.
  30 +
  31 +Once these two files are generated it's time to add **LaunchAtLoginHelper** to the main app. Drag `LaunchAtLoginHelper.xcodeproj`, `LLStrings.h`, `LLManager.h`, and `LLManager.m` to the main app's project.
  32 +
  33 +![](http://kgn.github.com/content/launchatlogin/drag_drop_file.png)
  34 +
  35 +Next go to the *Build Phases* for the main app and add **LaunchAtLoginHelper** as a *Target Dependency* and create a new *Copy Files Build Phase*. Set the *Destination* of this build phase to `Wrapper` and the *Subpath* to `Contents/Library/LoginItems`.
  36 +
  37 +![](http://kgn.github.com/content/launchatlogin/build_phases.png)
  38 +
  39 +Lastly add `ServiceManagement.framework` to the main app.
  40 +
  41 +Once this is done use `LLManager` to enable and disable launching at login! [**LaunchAtLoginSample**](https://github.com/kgn/LaunchAtLoginHelper/blob/master/LaunchAtLoginSample/LLAppDelegate.m) shows how to hook this up to a checkbox.
  42 +
  43 +``` obj-c
  44 +#import "LLManager.h"
  45 +
  46 +[LLManager launchAtLogin] // will the app launch at login?
  47 +[LLManager setLaunchAtLogin:YES] // set the app to launch at login
  48 +```
  49 +
  50 +# Bindings
  51 +
  52 +The `LLManager` class supports KVO and Cocoa Bindings. This allows for a completely code-free implementaion of this class. To get started, open the Interface Builder document in which you plan to create a login toggle. Drag a generic `NSObject` from the Utilities pane, and drop it onto your canvas. Select the newly created object, and open the Identity inspector tab in the Utilities pane. Change the class from `NSObject` to `LLManager`. Now, select to your login toggle (checkbox) and open the Bindings inspector in the Utilities pane. Expand `Value`, check the "Bind to", and select the name of the `LLManager` object you created earlier. Set the key path to `self.launchAtLogin`. You're done!
  53 +
  54 +---
  55 +
  56 +Special thanks to [Curtis Hard](http://www.geekygoodness.com) for offering some much needed advice on this project.
22 LaunchAtLoginHelper/setup.py
... ... @@ -0,0 +1,22 @@
  1 +import sys, os
  2 +import plistlib
  3 +
  4 +urlScheme = sys.argv[1]
  5 +bundleIdentifier = sys.argv[2]
  6 +
  7 +directory = os.path.dirname(os.path.abspath(__file__))
  8 +
  9 +stringsOutput = os.path.join(directory, 'LLStrings.h')
  10 +infoPlistOutput = os.path.join(directory, 'LaunchAtLoginHelper/LaunchAtLoginHelper-Info.plist')
  11 +infoPlist = plistlib.readPlist(os.path.join(directory, 'LaunchAtLoginHelper/LaunchAtLoginHelper-InfoBase.plist'))
  12 +
  13 +with open(stringsOutput, 'w') as strings:
  14 + strings.write("""// strings used by LLManager and LaunchAtLoginHelper
  15 +//
  16 +
  17 +#define LLURLScheme @"%(urlScheme)s"
  18 +#define LLHelperBundleIdentifier @"%(bundleIdentifier)s"
  19 +"""%locals())
  20 +
  21 +infoPlist['CFBundleIdentifier'] = bundleIdentifier
  22 +plistlib.writePlist(infoPlist, infoPlistOutput)
7 Readme.md
Source Rendered
@@ -37,6 +37,13 @@ Who did make this app?
37 37 Change log
38 38 ----------
39 39
  40 +2012-08-15 - **v1.4** - [diff](https://github.com/codler/Battery-Time-Remaining/compare/v1.3...v1.4)
  41 +
  42 +* App sandbox ([codler](https://github.com/codler))
  43 +* Rewrote start at login ([codler](https://github.com/codler) [#4](https://github.com/codler/Battery-Time-Remaining/issues/4))
  44 +* Improved battery icon ([codler](https://github.com/codler))
  45 +* Improved notification ([codler](https://github.com/codler))
  46 +
40 47 2012-08-12 - **v1.3** - [diff](https://github.com/codler/Battery-Time-Remaining/compare/v1.2.1...v1.3)
41 48
42 49 * Added check for updates ([codler](https://github.com/codler))
2  build_version
... ... @@ -1 +1 @@
1   -6
  1 +7

No commit comments for this range

Something went wrong with that request. Please try again.