Support relaunching in the background as part of resume/launch items.
authorJoe Wreschnig <joe.wreschnig@gmail.com>
Wed, 13 Mar 2013 17:34:41 +0000 (18:34 +0100)
committerJoe Wreschnig <joe.wreschnig@gmail.com>
Wed, 13 Mar 2013 17:34:41 +0000 (18:34 +0100)
Categories/NSRunningApplication+LoginItem.h [new file with mode: 0644]
Categories/NSRunningApplication+LoginItem.m [new file with mode: 0644]
Classes/EnjoyableApplicationDelegate.m
Enjoyable.xcodeproj/project.pbxproj
Info.plist
Other Sources/Enjoyable_Prefix.pch
Resources/English.lproj/MainMenu.xib
Website/index.html

diff --git a/Categories/NSRunningApplication+LoginItem.h b/Categories/NSRunningApplication+LoginItem.h
new file mode 100644 (file)
index 0000000..da5dd19
--- /dev/null
@@ -0,0 +1,19 @@
+//
+//  NSRunningApplication+LoginItem.h
+//  Enjoyable
+//
+//  Created by Joe Wreschnig on 3/13/13.
+//
+//
+
+#import <Cocoa/Cocoa.h>
+
+@interface NSRunningApplication (LoginItem)
+    // Don't be a jerk. Ask the user before doing this.
+
+- (BOOL)isLoginItem;
+- (void)addToLoginItems;
+- (void)removeFromLoginItems;
+- (BOOL)wasLaunchedAsLoginItemOrResume;
+
+@end
diff --git a/Categories/NSRunningApplication+LoginItem.m b/Categories/NSRunningApplication+LoginItem.m
new file mode 100644 (file)
index 0000000..53a9521
--- /dev/null
@@ -0,0 +1,89 @@
+//
+//  NSApplication+LoginItem.m
+//  Enjoyable
+//
+//  Created by Joe Wreschnig on 3/13/13.
+//
+//
+
+#import "NSRunningApplication+LoginItem.h"
+
+#import <CoreServices/CoreServices.h>
+
+static const UInt32 RESOLVE_FLAGS = kLSSharedFileListNoUserInteraction
+                                  | kLSSharedFileListDoNotMountVolumes;
+
+@implementation NSRunningApplication (LoginItem)
+
+- (BOOL)isLoginItem {
+    LSSharedFileListRef loginItems = LSSharedFileListCreate(
+        NULL, kLSSharedFileListSessionLoginItems, NULL);
+    NSURL *myURL = self.bundleURL;
+       BOOL found = NO;
+    UInt32 seed = 0;
+    NSArray *currentLoginItems = CFBridgingRelease(
+        LSSharedFileListCopySnapshot(loginItems, &seed));
+    for (id obj in currentLoginItems) {
+        LSSharedFileListItemRef item = (__bridge LSSharedFileListItemRef)obj;
+        CFURLRef itemURL = NULL;
+        if (!LSSharedFileListItemResolve(item, RESOLVE_FLAGS, &itemURL, NULL)) {
+            found = CFEqual(itemURL, (__bridge CFURLRef)myURL);
+            CFRelease(itemURL);
+        }
+        if (found)
+            break;
+    }
+    CFRelease(loginItems);
+       return found;
+}
+
+- (void)addToLoginItems {
+    if (!self.isLoginItem) {
+        NSURL *myURL = self.bundleURL;
+        LSSharedFileListRef loginItems = LSSharedFileListCreate(
+            NULL, kLSSharedFileListSessionLoginItems, NULL);
+        LSSharedFileListInsertItemURL(
+            loginItems, kLSSharedFileListItemBeforeFirst,
+            NULL, NULL, (__bridge CFURLRef)myURL, NULL, NULL);
+        CFRelease(loginItems);
+    }
+}
+
+- (void)removeFromLoginItems {
+    LSSharedFileListRef loginItems = LSSharedFileListCreate(
+        NULL, kLSSharedFileListSessionLoginItems, NULL);
+    NSURL *myURL = self.bundleURL;
+    UInt32 seed = 0;
+    NSArray *currentLoginItems = CFBridgingRelease(
+        LSSharedFileListCopySnapshot(loginItems, &seed));
+    for (id obj in currentLoginItems) {
+        LSSharedFileListItemRef item = (__bridge LSSharedFileListItemRef)obj;
+        CFURLRef itemURL = NULL;
+        if (!LSSharedFileListItemResolve(item, RESOLVE_FLAGS, &itemURL, NULL)) {
+            if (CFEqual(itemURL, (__bridge CFURLRef)myURL))
+                LSSharedFileListItemRemove(loginItems, item);
+            CFRelease(itemURL);
+        }
+    }
+    CFRelease(loginItems);
+}
+
+- (BOOL)wasLaunchedAsLoginItemOrResume {
+    ProcessSerialNumber psn = { 0, kCurrentProcess };
+    NSDictionary *processInfo = CFBridgingRelease(
+        ProcessInformationCopyDictionary(
+            &psn, kProcessDictionaryIncludeAllInformationMask));
+    long long parent = [processInfo[@"ParentPSN"] longLongValue];
+    ProcessSerialNumber parentPsn = {
+        (parent >> 32) & 0x00000000FFFFFFFFLL,
+        parent & 0x00000000FFFFFFFFLL
+    };
+    
+    NSDictionary *parentInfo = CFBridgingRelease(
+        ProcessInformationCopyDictionary(
+            &parentPsn, kProcessDictionaryIncludeAllInformationMask));
+    return [parentInfo[@"FileCreator"] isEqualToString:@"lgnw"];
+}
+
+
+@end
index f151399..f02ec90 100644 (file)
 }
 
 - (void)applicationDidFinishLaunching:(NSNotification *)notification {
-    [window makeKeyAndOrderFront:nil];
+    if (NSRunningApplication.currentApplication.wasLaunchedAsLoginItemOrResume
+        && [NSUserDefaults.standardUserDefaults boolForKey:@"hidden in status item"]) {
+        [self transformIntoElement:self];
+        NSApplication *app = notification.object;
+        [app deactivate];
+    } else {
+        [window makeKeyAndOrderFront:nil];
+    }
 }
 
 - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication
     [NSObject cancelPreviousPerformRequestsWithTarget:self
                                              selector:@selector(transformIntoElement:)
                                                object:self];
+    [NSUserDefaults.standardUserDefaults setBool:NO forKey:@"hidden in status item"];
 }
 
 - (void)applicationWillBecomeActive:(NSNotification *)notification {
-    [self restoreToForeground:notification];
+    if (window.isVisible)
+        [self restoreToForeground:notification];
 }
 
 - (void)transformIntoElement:(id)sender {
     ProcessSerialNumber psn = { 0, kCurrentProcess };
     TransformProcessType(&psn, kProcessTransformToUIElementApplication);
+    [NSUserDefaults.standardUserDefaults setBool:YES forKey:@"hidden in status item"];
 }
 
 - (void)flashStatusItem {
index eee41a1..d428220 100644 (file)
@@ -15,6 +15,7 @@
                EE3D897F16EA817E00596D1F /* Status Menu Icon Disabled.png in Resources */ = {isa = PBXBuildFile; fileRef = EE3D897D16EA817E00596D1F /* Status Menu Icon Disabled.png */; };
                EE3D898016EA817E00596D1F /* Status Menu Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = EE3D897E16EA817E00596D1F /* Status Menu Icon.png */; };
                EE6A122E16E8F46300EDBD32 /* Icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = EE6A122D16E8F46300EDBD32 /* Icon.icns */; };
+               EE8455DD16F0E46B00F32A01 /* NSRunningApplication+LoginItem.m in Sources */ = {isa = PBXBuildFile; fileRef = EE8455DC16F0E46B00F32A01 /* NSRunningApplication+LoginItem.m */; };
                EED4CE6E16ED692400C65AA8 /* NJMappingMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = EED4CE6D16ED692400C65AA8 /* NJMappingMenuController.m */; };
                EED4CE7716EE195100C65AA8 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EED4CE7616EE195100C65AA8 /* Sparkle.framework */; };
                EED4CE7816EE195B00C65AA8 /* Sparkle.framework in Copy Sparkle Framework */ = {isa = PBXBuildFile; fileRef = EED4CE7616EE195100C65AA8 /* Sparkle.framework */; };
@@ -78,6 +79,8 @@
                EE3D897D16EA817E00596D1F /* Status Menu Icon Disabled.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Status Menu Icon Disabled.png"; path = "Resources/Status Menu Icon Disabled.png"; sourceTree = "<group>"; };
                EE3D897E16EA817E00596D1F /* Status Menu Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Status Menu Icon.png"; path = "Resources/Status Menu Icon.png"; sourceTree = "<group>"; };
                EE6A122D16E8F46300EDBD32 /* Icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Icon.icns; sourceTree = "<group>"; };
+               EE8455DB16F0E46B00F32A01 /* NSRunningApplication+LoginItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSRunningApplication+LoginItem.h"; path = "Categories/NSRunningApplication+LoginItem.h"; sourceTree = "<group>"; };
+               EE8455DC16F0E46B00F32A01 /* NSRunningApplication+LoginItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSRunningApplication+LoginItem.m"; path = "Categories/NSRunningApplication+LoginItem.m"; sourceTree = "<group>"; };
                EED4CE6C16ED692400C65AA8 /* NJMappingMenuController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NJMappingMenuController.h; path = Classes/NJMappingMenuController.h; sourceTree = "<group>"; };
                EED4CE6D16ED692400C65AA8 /* NJMappingMenuController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NJMappingMenuController.m; path = Classes/NJMappingMenuController.m; sourceTree = "<group>"; };
                EED4CE7616EE195100C65AA8 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Sparkle.framework; sourceTree = "<group>"; };
                EE1D5F8B16E403D600749C36 /* Categories */ = {
                        isa = PBXGroup;
                        children = (
+                               EE8455DB16F0E46B00F32A01 /* NSRunningApplication+LoginItem.h */,
+                               EE8455DC16F0E46B00F32A01 /* NSRunningApplication+LoginItem.m */,
                                EEF17D2716E8E2E100D7DC4D /* NSError+Description.h */,
                                EEF17D2816E8E2E100D7DC4D /* NSError+Description.m */,
                                EEF17D2916E8E2E100D7DC4D /* NSFileManager+UniqueNames.h */,
                                EED4CE6E16ED692400C65AA8 /* NJMappingMenuController.m in Sources */,
                                EEE703DC16F089FE002FDD69 /* NJHIDManager.m in Sources */,
                                EEE703DE16F0B3F6002FDD69 /* NJInputPathElement.m in Sources */,
+                               EE8455DD16F0E46B00F32A01 /* NSRunningApplication+LoginItem.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index f3cc683..6191eaa 100644 (file)
@@ -46,7 +46,7 @@
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>248</string>
+       <string>258</string>
        <key>LSApplicationCategoryType</key>
        <string>public.app-category.utilities</string>
        <key>NSHumanReadableCopyright</key>
index 61d6aee..b0d1f40 100644 (file)
@@ -15,3 +15,4 @@
 #import "NSFileManager+UniqueNames.h"
 #import "NSString+FixFilename.h"
 #import "NSRunningApplication+NJPossibleNames.h"
+#import "NSRunningApplication+LoginItem.h"
index c63659b..98b5cef 100644 (file)
@@ -567,7 +567,7 @@ aW5nLg</string>
                                                                                                        <string key="NSFrameSize">{232, 321}</string>
                                                                                                        <reference key="NSSuperview" ref="698362889"/>
                                                                                                        <reference key="NSWindow"/>
-                                                                                                       <reference key="NSNextKeyView" ref="1036252745"/>
+                                                                                                       <reference key="NSNextKeyView" ref="892486973"/>
                                                                                                        <bool key="NSEnabled">YES</bool>
                                                                                                        <bool key="NSAllowsLogicalLayoutDirection">NO</bool>
                                                                                                        <bool key="NSControlAllowsExpansionToolTips">YES</bool>
@@ -697,7 +697,7 @@ aW5nLg</string>
                                                                        <string key="NSFrameSize">{234, 323}</string>
                                                                        <reference key="NSSuperview" ref="734312853"/>
                                                                        <reference key="NSWindow"/>
-                                                                       <reference key="NSNextKeyView" ref="892486973"/>
+                                                                       <reference key="NSNextKeyView" ref="698362889"/>
                                                                        <int key="NSsFlags">150034</int>
                                                                        <reference key="NSVScroller" ref="1036252745"/>
                                                                        <reference key="NSHScroller" ref="892486973"/>
@@ -3026,7 +3026,7 @@ aW5nLg</string>
                                <boolean value="YES" key="450.IBNSWindowAutoPositionCentersVertical"/>
                                <string key="450.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
                                <string key="450.IBWindowTemplateEditedContentRect">{{114, 276}, {770, 487}}</string>
-                               <boolean value="YES" key="450.NSWindowTemplate.visibleAtLaunch"/>
+                               <boolean value="NO" key="450.NSWindowTemplate.visibleAtLaunch"/>
                                <string key="451.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
                                <string key="453.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
                                <string key="456.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
index 6525b71..03d3468 100644 (file)
@@ -51,6 +51,7 @@
       them.
     </p>
     <ul style="font-size: 0.9em;">
+      <li><a href="mappings/6180 the moon.enjoyable">6180 the moon</a></li>
       <li><a href="mappings/Anodyne.enjoyable">Anodyne</a></li>
       <li><a href="mappings/BasketBelle.enjoyable">BasketBelle</a></li>
       <li><a href="mappings/Canabalt.enjoyable">Canabalt</a></li>