411067e74d351bb3d55ec96a5bd5161a375174b2
[enjoyable.git] / Classes / EnjoyableApplicationDelegate.m
1 //
2 // EnjoyableApplicationDelegate.m
3 // Enjoy
4 //
5 // Created by Sam McCall on 4/05/09.
6 //
7
8 #import "EnjoyableApplicationDelegate.h"
9
10 #import "NJMapping.h"
11 #import "NJMappingsController.h"
12 #import "NJEvents.h"
13
14 @implementation EnjoyableApplicationDelegate {
15 NSStatusItem *statusItem;
16 }
17
18 - (void)didSwitchApplication:(NSNotification *)note {
19 NSRunningApplication *activeApp = note.userInfo[NSWorkspaceApplicationKey];
20 if (activeApp)
21 [self.mappingsController activateMappingForProcess:activeApp];
22 }
23
24 - (void)applicationWillFinishLaunching:(NSNotification *)notification {
25 [NSNotificationCenter.defaultCenter
26 addObserver:self
27 selector:@selector(mappingDidChange:)
28 name:NJEventMappingChanged
29 object:nil];
30 [NSNotificationCenter.defaultCenter
31 addObserver:self
32 selector:@selector(eventTranslationActivated:)
33 name:NJEventTranslationActivated
34 object:nil];
35 [NSNotificationCenter.defaultCenter
36 addObserver:self
37 selector:@selector(eventTranslationDeactivated:)
38 name:NJEventTranslationDeactivated
39 object:nil];
40
41 [self.mappingsController load];
42
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;
48 }
49
50 - (void)applicationDidFinishLaunching:(NSNotification *)notification {
51 [window makeKeyAndOrderFront:nil];
52 }
53
54 - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication
55 hasVisibleWindows:(BOOL)flag {
56 [self restoreToForeground:theApplication];
57 return NO;
58 }
59
60 - (void)restoreToForeground:(id)sender {
61 ProcessSerialNumber psn = { 0, kCurrentProcess };
62 TransformProcessType(&psn, kProcessTransformToForegroundApplication);
63 [NSApplication.sharedApplication activateIgnoringOtherApps:YES];
64 [window makeKeyAndOrderFront:sender];
65 [NSObject cancelPreviousPerformRequestsWithTarget:self
66 selector:@selector(transformIntoElement:)
67 object:self];
68 [NSUserDefaults.standardUserDefaults setBool:NO forKey:@"hidden in status item"];
69 }
70
71 - (void)applicationWillBecomeActive:(NSNotification *)notification {
72 if (window.isVisible)
73 [self restoreToForeground:notification];
74 }
75
76 - (void)transformIntoElement:(id)sender {
77 ProcessSerialNumber psn = { 0, kCurrentProcess };
78 TransformProcessType(&psn, kProcessTransformToUIElementApplication);
79 [NSUserDefaults.standardUserDefaults setBool:YES forKey:@"hidden in status item"];
80 }
81
82 - (void)flashStatusItem {
83 if ([statusItem.image.name isEqualToString:@"Status Menu Icon"]) {
84 statusItem.image = [NSImage imageNamed:@"Status Menu Icon Disabled"];
85 } else {
86 statusItem.image = [NSImage imageNamed:@"Status Menu Icon"];
87 }
88
89 }
90
91 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication {
92 [theApplication hide:theApplication];
93 // If we turn into a UIElement right away, the application cancels
94 // the deactivation events. The dock icon disappears, but an
95 // unresponsive menu bar remains until the user clicks somewhere.
96 // So delay just long enough to be past the end handling that.
97 [self performSelector:@selector(transformIntoElement:) withObject:self afterDelay:0.001];
98 return NO;
99 }
100
101 - (void)eventTranslationActivated:(NSNotification *)note {
102 statusItem.image = [NSImage imageNamed:@"Status Menu Icon"];
103 [NSWorkspace.sharedWorkspace.notificationCenter
104 addObserver:self
105 selector:@selector(didSwitchApplication:)
106 name:NSWorkspaceDidActivateApplicationNotification
107 object:nil];
108 }
109
110 - (void)eventTranslationDeactivated:(NSNotification *)note {
111 statusItem.image = [NSImage imageNamed:@"Status Menu Icon Disabled"];
112 [NSWorkspace.sharedWorkspace.notificationCenter
113 removeObserver:self
114 name:NSWorkspaceDidActivateApplicationNotification
115 object:nil];
116 }
117
118 - (void)mappingDidChange:(NSNotification *)note {
119 if (!window.isVisible)
120 for (int i = 0; i < 4; ++i)
121 [self performSelector:@selector(flashStatusItem)
122 withObject:self
123 afterDelay:0.2 * i];
124 }
125
126 - (NSMenu *)applicationDockMenu:(NSApplication *)sender {
127 return dockMenu;
128 }
129
130 - (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
131 [self restoreToForeground:sender];
132 NSURL *url = [NSURL fileURLWithPath:filename];
133 [self.mappingsController addMappingWithContentsOfURL:url];
134 return YES;
135 }
136
137 - (void)mappingWasChosen:(NJMapping *)mapping {
138 [self.mappingsController activateMapping:mapping];
139 }
140
141 - (void)mappingListShouldOpen {
142 [self restoreToForeground:self];
143 [self.mappingsController mappingPressed:self];
144 }
145
146
147 @end