--- /dev/null
+//
+// 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
--- /dev/null
+//
+// 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
}
- (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 {
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 */; };
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;
};
<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>
#import "NSFileManager+UniqueNames.h"
#import "NSString+FixFilename.h"
#import "NSRunningApplication+NJPossibleNames.h"
+#import "NSRunningApplication+LoginItem.h"
<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>
<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"/>
<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>
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>