// Created by Sam McCall on 4/05/09.
//
+#import <Sparkle/Sparkle.h>
+
#import "EnjoyableApplicationDelegate.h"
#import "NJMapping.h"
#import "NJMappingsController.h"
-#import "NJDeviceController.h"
-#import "NJOutputController.h"
#import "NJEvents.h"
@implementation EnjoyableApplicationDelegate {
object:nil];
[NSNotificationCenter.defaultCenter
addObserver:self
- selector:@selector(mappingListDidChange:)
- name:NJEventMappingListChanged
- object:nil];
- [NSNotificationCenter.defaultCenter
- addObserver:self
- selector:@selector(eventTranslationActivated:)
- name:NJEventTranslationActivated
+ selector:@selector(eventSimulationStarted:)
+ name:NJEventSimulationStarted
object:nil];
[NSNotificationCenter.defaultCenter
addObserver:self
- selector:@selector(eventTranslationDeactivated:)
- name:NJEventTranslationDeactivated
+ selector:@selector(eventSimulationStopped:)
+ name:NJEventSimulationStopped
object:nil];
[self.mappingsController load];
}
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
- [window makeKeyAndOrderFront:nil];
+ if ([NSUserDefaults.standardUserDefaults boolForKey:@"hidden in status item"]
+ && NSRunningApplication.currentApplication.wasLaunchedAsLoginItemOrResume)
+ [self transformIntoElement:nil];
+ 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 {
+ 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 {
return NO;
}
-- (void)eventTranslationActivated:(NSNotification *)note {
- [dockMenu itemAtIndex:0].state = NSOnState;
- [statusItemMenu itemAtIndex:0].state = NSOnState;
+- (void)eventSimulationStarted:(NSNotification *)note {
statusItem.image = [NSImage imageNamed:@"Status Menu Icon"];
[NSWorkspace.sharedWorkspace.notificationCenter
addObserver:self
object:nil];
}
-- (void)eventTranslationDeactivated:(NSNotification *)note {
- [dockMenu itemAtIndex:0].state = NSOffState;
- [statusItemMenu itemAtIndex:0].state = NSOffState;
+- (void)eventSimulationStopped:(NSNotification *)note {
statusItem.image = [NSImage imageNamed:@"Status Menu Icon Disabled"];
[NSWorkspace.sharedWorkspace.notificationCenter
removeObserver:self
object:nil];
}
-- (void)restoreWindowAndShowMappings:(id)sender {
- [self restoreToForeground:sender];
- [self.mappingsController mappingPressed:sender];
-}
-
-- (void)addMappings:(NSArray *)mappings
- toMenu:(NSMenu *)menu
- withKeys:(BOOL)withKeys
- atIndex:(NSInteger)index {
- static const NSUInteger MAXIMUM_ITEMS = 15;
- int added = 0;
- for (NJMapping *mapping in mappings) {
- NSString *keyEquiv = (++added < 10 && withKeys) ? @(added).stringValue : @"";
- NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:mapping.name
- action:@selector(chooseMapping:)
- keyEquivalent:keyEquiv];
- item.representedObject = mapping;
- item.state = mapping == self.mappingsController.currentMapping;
- [menu insertItem:item atIndex:index++];
- if (added == MAXIMUM_ITEMS && self.mappingsController.mappings.count > MAXIMUM_ITEMS + 1) {
- NSString *msg = [NSString stringWithFormat:@"(and %lu moreā¦)",
- self.mappingsController.mappings.count - MAXIMUM_ITEMS];
- NSMenuItem *end = [[NSMenuItem alloc] initWithTitle:msg
- action:@selector(restoreWindowAndShowMappings:)
- keyEquivalent:@""];
- // There must be a represented object here so the item gets
- // removed correctly when the menus are regenerated.
- end.representedObject = mappings;
- end.target = self;
- [menu insertItem:end atIndex:index++];
- break;
- }
- }
-}
-
-- (void)mappingListDidChange:(NSNotification *)note {
- NSArray *mappings = note.userInfo[@"mappings"];
- while (mappingsMenu.lastItem.representedObject)
- [mappingsMenu removeLastItem];
- [self addMappings:mappings
- toMenu:mappingsMenu
- withKeys:YES
- atIndex:mappingsMenu.numberOfItems];
- while ([statusItemMenu itemAtIndex:2].representedObject)
- [statusItemMenu removeItemAtIndex:2];
- [self addMappings:mappings toMenu:statusItemMenu withKeys:NO atIndex:2];
-}
-
- (void)mappingDidChange:(NSNotification *)note {
- NJMapping *current = note.userInfo[@"mapping"];
- for (NSMenuItem *item in mappingsMenu.itemArray)
- if (item.representedObject)
- item.state = item.representedObject == current;
- for (NSMenuItem *item in statusItemMenu.itemArray)
- if (item.representedObject)
- item.state = item.representedObject == current;
-
if (!window.isVisible)
for (int i = 0; i < 4; ++i)
[self performSelector:@selector(flashStatusItem)
afterDelay:0.2 * i];
}
-- (void)chooseMapping:(NSMenuItem *)sender {
- NJMapping *chosen = sender.representedObject;
- [self.mappingsController activateMapping:chosen];
-}
-
- (NSMenu *)applicationDockMenu:(NSApplication *)sender {
- while (dockMenu.lastItem.representedObject)
- [dockMenu removeLastItem];
- [self addMappings:self.mappingsController.mappings
- toMenu:dockMenu
- withKeys:NO
- atIndex:dockMenu.numberOfItems];
return dockMenu;
}
return YES;
}
+- (void)mappingWasChosen:(NJMapping *)mapping {
+ [self.mappingsController activateMapping:mapping];
+}
+
+- (void)mappingListShouldOpen {
+ [self restoreToForeground:self];
+ [self.mappingsController mappingPressed:self];
+}
+
+- (void)loginItemPromptDidEnd:(NSWindow *)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void *)contextInfo {
+ if (returnCode == NSAlertDefaultReturn) {
+ [NSRunningApplication.currentApplication addToLoginItems];
+ // If we're going to automatically start, don't bug the user
+ // about automatic updates next boot - they probably want it,
+ // and if they don't they probably want a prompt for it less.
+ SUUpdater.sharedUpdater.automaticallyChecksForUpdates = YES;
+ }
+}
+
+- (void)loginItemPromptDidDismiss:(NSWindow *)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void *)contextInfo {
+ [NSUserDefaults.standardUserDefaults setBool:YES forKey:@"explained login items"];
+ [window performClose:sheet];
+}
+
+- (BOOL)windowShouldClose:(NSWindow *)sender {
+ if (sender != window
+ || NSRunningApplication.currentApplication.isLoginItem
+ || [NSUserDefaults.standardUserDefaults boolForKey:@"explained login items"])
+ return YES;
+ NSBeginAlertSheet(
+ NSLocalizedString(@"login items prompt", @"alert prompt for adding to login items"),
+ NSLocalizedString(@"login items add button", @"button to add to login items"),
+ NSLocalizedString(@"login items don't add button", @"button to not add to login items"),
+ nil, window, self,
+ @selector(loginItemPromptDidEnd:returnCode:contextInfo:),
+ @selector(loginItemPromptDidDismiss:returnCode:contextInfo:),
+ NULL,
+ NSLocalizedString(@"login items explanation", @"a brief explanation of login items")
+ );
+ for (int i = 0; i < 10; ++i)
+ [self performSelector:@selector(flashStatusItem)
+ withObject:self
+ afterDelay:0.5 * i];
+ return NO;
+}
+
@end