2 // EnjoyableApplicationDelegate.m
5 // Created by Sam McCall on 4/05/09.
8 #import "EnjoyableApplicationDelegate.h"
11 #import "NJMappingsController.h"
14 @implementation EnjoyableApplicationDelegate {
15 NSStatusItem *statusItem;
18 - (void)didSwitchApplication:(NSNotification *)note {
19 NSRunningApplication *activeApp = note.userInfo[NSWorkspaceApplicationKey];
21 [self.mappingsController activateMappingForProcess:activeApp];
24 - (void)applicationWillFinishLaunching:(NSNotification *)notification {
25 [NSNotificationCenter.defaultCenter
27 selector:@selector(mappingDidChange:)
28 name:NJEventMappingChanged
30 [NSNotificationCenter.defaultCenter
32 selector:@selector(eventTranslationActivated:)
33 name:NJEventTranslationActivated
35 [NSNotificationCenter.defaultCenter
37 selector:@selector(eventTranslationDeactivated:)
38 name:NJEventTranslationDeactivated
41 [self.mappingsController load];
43 statusItem = [NSStatusBar.systemStatusBar statusItemWithLength:36];
44 statusItem.image = [NSImage imageNamed:@"Status Menu Icon Disabled"];
45 statusItem.highlightMode = YES;
46 statusItem.menu = statusItemMenu;
47 statusItem.target = self;
50 - (void)applicationDidFinishLaunching:(NSNotification *)notification {
51 if (NSRunningApplication.currentApplication.wasLaunchedAsLoginItemOrResume
52 && [NSUserDefaults.standardUserDefaults boolForKey:@"hidden in status item"]) {
53 [self transformIntoElement:self];
54 NSApplication *app = notification.object;
57 [window makeKeyAndOrderFront:nil];
61 - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication
62 hasVisibleWindows:(BOOL)flag {
63 [self restoreToForeground:theApplication];
67 - (void)restoreToForeground:(id)sender {
68 ProcessSerialNumber psn = { 0, kCurrentProcess };
69 TransformProcessType(&psn, kProcessTransformToForegroundApplication);
70 [NSApplication.sharedApplication activateIgnoringOtherApps:YES];
71 [window makeKeyAndOrderFront:sender];
72 [NSObject cancelPreviousPerformRequestsWithTarget:self
73 selector:@selector(transformIntoElement:)
75 [NSUserDefaults.standardUserDefaults setBool:NO forKey:@"hidden in status item"];
78 - (void)applicationWillBecomeActive:(NSNotification *)notification {
80 [self restoreToForeground:notification];
83 - (void)transformIntoElement:(id)sender {
84 ProcessSerialNumber psn = { 0, kCurrentProcess };
85 TransformProcessType(&psn, kProcessTransformToUIElementApplication);
86 [NSUserDefaults.standardUserDefaults setBool:YES forKey:@"hidden in status item"];
89 - (void)flashStatusItem {
90 if ([statusItem.image.name isEqualToString:@"Status Menu Icon"]) {
91 statusItem.image = [NSImage imageNamed:@"Status Menu Icon Disabled"];
93 statusItem.image = [NSImage imageNamed:@"Status Menu Icon"];
98 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication {
99 [theApplication hide:theApplication];
100 // If we turn into a UIElement right away, the application cancels
101 // the deactivation events. The dock icon disappears, but an
102 // unresponsive menu bar remains until the user clicks somewhere.
103 // So delay just long enough to be past the end handling that.
104 [self performSelector:@selector(transformIntoElement:) withObject:self afterDelay:0.001];
108 - (void)eventTranslationActivated:(NSNotification *)note {
109 statusItem.image = [NSImage imageNamed:@"Status Menu Icon"];
110 [NSWorkspace.sharedWorkspace.notificationCenter
112 selector:@selector(didSwitchApplication:)
113 name:NSWorkspaceDidActivateApplicationNotification
117 - (void)eventTranslationDeactivated:(NSNotification *)note {
118 statusItem.image = [NSImage imageNamed:@"Status Menu Icon Disabled"];
119 [NSWorkspace.sharedWorkspace.notificationCenter
121 name:NSWorkspaceDidActivateApplicationNotification
125 - (void)mappingDidChange:(NSNotification *)note {
126 if (!window.isVisible)
127 for (int i = 0; i < 4; ++i)
128 [self performSelector:@selector(flashStatusItem)
133 - (NSMenu *)applicationDockMenu:(NSApplication *)sender {
137 - (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
138 [self restoreToForeground:sender];
139 NSURL *url = [NSURL fileURLWithPath:filename];
140 [self.mappingsController addMappingWithContentsOfURL:url];
144 - (void)mappingWasChosen:(NJMapping *)mapping {
145 [self.mappingsController activateMapping:mapping];
148 - (void)mappingListShouldOpen {
149 [self restoreToForeground:self];
150 [self.mappingsController mappingPressed:self];