From 22efc1e5000d462091f3156ee5a8959be32cfb11 Mon Sep 17 00:00:00 2001 From: Joe Wreschnig Date: Sat, 9 Mar 2013 00:03:03 +0100 Subject: [PATCH] Add status item. Disable automatic termination, but still hide from the dock when closed by transforming the process type. Share mapping menu generation between the (now three) menus that need it. --- Classes/EnjoyableApplicationDelegate.h | 6 +- Classes/EnjoyableApplicationDelegate.m | 126 ++++++-- Enjoyable.xcodeproj/project.pbxproj | 16 ++ Resources/English.lproj/MainMenu.xib | 316 +++++++++++++++++---- Resources/Status Menu Icon Disabled.png | Bin 0 -> 569 bytes Resources/Status Menu Icon Disabled@2x.png | Bin 0 -> 1071 bytes Resources/Status Menu Icon.png | Bin 0 -> 562 bytes Resources/Status Menu Icon@2x.png | Bin 0 -> 1013 bytes 8 files changed, 374 insertions(+), 90 deletions(-) create mode 100644 Resources/Status Menu Icon Disabled.png create mode 100644 Resources/Status Menu Icon Disabled@2x.png create mode 100644 Resources/Status Menu Icon.png create mode 100644 Resources/Status Menu Icon@2x.png diff --git a/Classes/EnjoyableApplicationDelegate.h b/Classes/EnjoyableApplicationDelegate.h index dfb82fc..c4d8e3b 100644 --- a/Classes/EnjoyableApplicationDelegate.h +++ b/Classes/EnjoyableApplicationDelegate.h @@ -10,11 +10,15 @@ @class NJMappingsController; @interface EnjoyableApplicationDelegate : NSObject { - IBOutlet NSMenu *dockMenuBase; + IBOutlet NSMenu *dockMenu; + IBOutlet NSMenu *statusItemMenu; + IBOutlet NSMenu *mappingsMenu; IBOutlet NSWindow *window; } @property (nonatomic, strong) IBOutlet NJDeviceController *inputController; @property (nonatomic, strong) IBOutlet NJMappingsController *mappingsController; +- (IBAction)restoreToForeground:(id)sender; + @end diff --git a/Classes/EnjoyableApplicationDelegate.m b/Classes/EnjoyableApplicationDelegate.m index 78b930b..aaa9f00 100644 --- a/Classes/EnjoyableApplicationDelegate.m +++ b/Classes/EnjoyableApplicationDelegate.m @@ -13,7 +13,9 @@ #import "NJOutputController.h" #import "NJEvents.h" -@implementation EnjoyableApplicationDelegate +@implementation EnjoyableApplicationDelegate { + NSStatusItem *statusItem; +} - (void)didSwitchApplication:(NSNotification *)note { NSRunningApplication *activeApp = note.userInfo[NSWorkspaceApplicationKey]; @@ -21,7 +23,7 @@ [self.mappingsController activateMappingForProcess:activeApp]; } -- (void)applicationDidFinishLaunching:(NSNotification *)notification { +- (void)applicationWillFinishLaunching:(NSNotification *)notification { [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(mappingDidChange:) @@ -43,60 +45,131 @@ name:NJEventTranslationDeactivated object:nil]; - [self.inputController setup]; [self.mappingsController load]; + + statusItem = [NSStatusBar.systemStatusBar statusItemWithLength:36]; + statusItem.image = [NSImage imageNamed:@"Status Menu Icon Disabled"]; + statusItem.highlightMode = YES; + statusItem.menu = statusItemMenu; + statusItem.target = self; } -- (void)applicationDidBecomeActive:(NSNotification *)notification { +- (void)applicationDidFinishLaunching:(NSNotification *)notification { + [self.inputController setup]; [window makeKeyAndOrderFront:nil]; } - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag { - [window makeKeyAndOrderFront:nil]; + [self restoreToForeground:theApplication]; + return NO; +} + +- (void)restoreToForeground:(id)sender { + ProcessSerialNumber psn = { 0, kCurrentProcess }; + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + [NSApplication.sharedApplication activateIgnoringOtherApps:YES]; + [window makeKeyAndOrderFront:sender]; + [NSObject cancelPreviousPerformRequestsWithTarget:self + selector:@selector(transformIntoElement:) + object:self]; +} + +- (void)transformIntoElement:(id)sender { + ProcessSerialNumber psn = { 0, kCurrentProcess }; + TransformProcessType(&psn, kProcessTransformToUIElementApplication); +} + +- (void)flashStatusItem { + if ([statusItem.image.name isEqualToString:@"Status Menu Icon"]) { + statusItem.image = [NSImage imageNamed:@"Status Menu Icon Disabled"]; + } else { + statusItem.image = [NSImage imageNamed:@"Status Menu Icon"]; + } + +} + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication { + [theApplication hide:theApplication]; + // If we turn into a UIElement right away, the application cancels + // the deactivation events. The dock icon disappears, but an + // unresponsive menu bar remains until the user clicks somewhere. + // So delay just long enough to be past the end handling that. + [self performSelector:@selector(transformIntoElement:) withObject:self afterDelay:0.001]; return NO; } - (void)eventTranslationActivated:(NSNotification *)note { - [NSProcessInfo.processInfo disableAutomaticTermination:@"Input translation is active."]; + [dockMenu itemAtIndex:0].state = NSOnState; + [statusItemMenu itemAtIndex:0].state = NSOnState; + statusItem.image = [NSImage imageNamed:@"Status Menu Icon"]; [NSWorkspace.sharedWorkspace.notificationCenter addObserver:self selector:@selector(didSwitchApplication:) name:NSWorkspaceDidActivateApplicationNotification object:nil]; - NSLog(@"Listening for application changes."); } - (void)eventTranslationDeactivated:(NSNotification *)note { - [NSProcessInfo.processInfo enableAutomaticTermination:@"Input translation is active."]; + [dockMenu itemAtIndex:0].state = NSOffState; + [statusItemMenu itemAtIndex:0].state = NSOffState; + statusItem.image = [NSImage imageNamed:@"Status Menu Icon Disabled"]; [NSWorkspace.sharedWorkspace.notificationCenter removeObserver:self name:NSWorkspaceDidActivateApplicationNotification object:nil]; - NSLog(@"Ignoring application changes."); } -- (void)mappingListDidChange:(NSNotification *)note { - NSArray *mappings = note.object; - while (dockMenuBase.lastItem.representedObject) - [dockMenuBase removeLastItem]; +- (void)restoreWindowAndShowMappings:(id)sender { + [self restoreToForeground:sender]; + [self.mappingsController mappingPressed:sender]; +} + +- (void)addMappingsToMenu:(NSMenu *)menu withKeys:(BOOL)withKeys atIndex:(NSInteger)index { + static const NSUInteger MAXIMUM_ITEMS = 5; int added = 0; - for (NJMapping *mapping in mappings) { - NSString *keyEquiv = ++added < 10 ? @(added).stringValue : @""; + for (NJMapping *mapping in self.mappingsController) { + 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; - [dockMenuBase addItem:item]; - } + [menu insertItem:item atIndex:index++]; + if (added == MAXIMUM_ITEMS && self.mappingsController.mappings.count > MAXIMUM_ITEMS + 1) { + NSMenuItem *end = [[NSMenuItem alloc] initWithTitle:@"…" + action:@selector(restoreWindowAndShowMappings:) + keyEquivalent:@""]; + end.target = self; + [menu insertItem:end atIndex:index++]; + break; + } + } +} + +- (void)mappingListDidChange:(NSNotification *)note { + while (mappingsMenu.lastItem.representedObject) + [mappingsMenu removeLastItem]; + [self addMappingsToMenu:mappingsMenu withKeys:YES atIndex:mappingsMenu.numberOfItems]; + while ([statusItemMenu itemAtIndex:2].representedObject) + [statusItemMenu removeItemAtIndex:2]; + [self addMappingsToMenu:statusItemMenu withKeys:NO atIndex:2]; } - (void)mappingDidChange:(NSNotification *)note { NJMapping *current = note.object; - for (NSMenuItem *item in dockMenuBase.itemArray) + 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) + withObject:self + afterDelay:0.2 * i]; } - (void)chooseMapping:(NSMenuItem *)sender { @@ -105,21 +178,14 @@ } - (NSMenu *)applicationDockMenu:(NSApplication *)sender { - NSMenu *menu = [[NSMenu alloc] init]; - int added = 0; - for (NJMapping *mapping in self.mappingsController) { - NSString *keyEquiv = ++added < 10 ? @(added).stringValue : @""; - NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:mapping.name - action:@selector(chooseMapping:) - keyEquivalent:keyEquiv]; - item.representedObject = mapping; - item.state = mapping == self.mappingsController.currentMapping; - [menu addItem:item]; - } - return menu; + while (dockMenu.lastItem.representedObject) + [dockMenu removeLastItem]; + [self addMappingsToMenu:dockMenu withKeys:NO atIndex:dockMenu.numberOfItems]; + return dockMenu; } - (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename { + [self restoreToForeground:sender]; NSURL *url = [NSURL fileURLWithPath:filename]; [self.mappingsController addMappingWithContentsOfURL:url]; return YES; diff --git a/Enjoyable.xcodeproj/project.pbxproj b/Enjoyable.xcodeproj/project.pbxproj index bf9c0d9..bf04acf 100644 --- a/Enjoyable.xcodeproj/project.pbxproj +++ b/Enjoyable.xcodeproj/project.pbxproj @@ -9,6 +9,10 @@ /* Begin PBXBuildFile section */ 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; D594BF000FAE7397007A85F2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D594BEFF0FAE7397007A85F2 /* IOKit.framework */; }; + EE3D897A16EA7EFC00596D1F /* Status Menu Icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = EE3D897916EA7EFC00596D1F /* Status Menu Icon@2x.png */; }; + EE3D897C16EA806E00596D1F /* Status Menu Icon Disabled@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = EE3D897B16EA806E00596D1F /* Status Menu Icon Disabled@2x.png */; }; + 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 */; }; EEE73B1616EA42E5009D9D99 /* NSRunningApplication+NJPossibleNames.m in Sources */ = {isa = PBXBuildFile; fileRef = EEE73B1516EA42E5009D9D99 /* NSRunningApplication+NJPossibleNames.m */; }; EEF17D1916E8E21A00D7DC4D /* com.yukkurigames.Enjoyable.mapping.icns in Resources */ = {isa = PBXBuildFile; fileRef = EEF17D1716E8E21A00D7DC4D /* com.yukkurigames.Enjoyable.mapping.icns */; }; @@ -48,6 +52,10 @@ 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8D1107320486CEB800E47090 /* Enjoyable.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Enjoyable.app; sourceTree = BUILT_PRODUCTS_DIR; }; D594BEFF0FAE7397007A85F2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = ""; }; + EE3D897916EA7EFC00596D1F /* Status Menu Icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Status Menu Icon@2x.png"; path = "Resources/Status Menu Icon@2x.png"; sourceTree = ""; }; + EE3D897B16EA806E00596D1F /* Status Menu Icon Disabled@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Status Menu Icon Disabled@2x.png"; path = "Resources/Status Menu Icon Disabled@2x.png"; sourceTree = ""; }; + 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 = ""; }; + EE3D897E16EA817E00596D1F /* Status Menu Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Status Menu Icon.png"; path = "Resources/Status Menu Icon.png"; sourceTree = ""; }; EE6A122D16E8F46300EDBD32 /* Icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Icon.icns; sourceTree = ""; }; EEE73B1416EA42E5009D9D99 /* NSRunningApplication+NJPossibleNames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSRunningApplication+NJPossibleNames.h"; path = "Categories/NSRunningApplication+NJPossibleNames.h"; sourceTree = ""; }; EEE73B1516EA42E5009D9D99 /* NSRunningApplication+NJPossibleNames.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSRunningApplication+NJPossibleNames.m"; path = "Categories/NSRunningApplication+NJPossibleNames.m"; sourceTree = ""; }; @@ -215,6 +223,10 @@ 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( + EE3D897D16EA817E00596D1F /* Status Menu Icon Disabled.png */, + EE3D897E16EA817E00596D1F /* Status Menu Icon.png */, + EE3D897B16EA806E00596D1F /* Status Menu Icon Disabled@2x.png */, + EE3D897916EA7EFC00596D1F /* Status Menu Icon@2x.png */, EE6A122D16E8F46300EDBD32 /* Icon.icns */, EEF17D2116E8E24400D7DC4D /* Help */, EEF17D1B16E8E23A00D7DC4D /* InfoPlist.strings */, @@ -313,6 +325,10 @@ EEF17D2016E8E23A00D7DC4D /* MainMenu.xib in Resources */, EEF17D2216E8E24400D7DC4D /* Help in Resources */, EE6A122E16E8F46300EDBD32 /* Icon.icns in Resources */, + EE3D897A16EA7EFC00596D1F /* Status Menu Icon@2x.png in Resources */, + EE3D897C16EA806E00596D1F /* Status Menu Icon Disabled@2x.png in Resources */, + EE3D897F16EA817E00596D1F /* Status Menu Icon Disabled.png in Resources */, + EE3D898016EA817E00596D1F /* Status Menu Icon.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Resources/English.lproj/MainMenu.xib b/Resources/English.lproj/MainMenu.xib index 895e1d2..22b83f7 100644 --- a/Resources/English.lproj/MainMenu.xib +++ b/Resources/English.lproj/MainMenu.xib @@ -132,20 +132,20 @@ - + - Hide Others - h - 1572864 + Hide From Dock + w + 1048576 2147483647 - + - Show All - - 1048576 + Hide Others + h + 1572864 2147483647 @@ -287,15 +287,6 @@ - - - Bring All to Front - - 1048576 - 2147483647 - - - _NSWindowsMenu @@ -1110,7 +1101,7 @@ aW5nLg YES - + 256 @@ -1126,7 +1117,8 @@ aW5nLg 256 {198, 198} - + + YES NO YES @@ -1183,6 +1175,7 @@ aW5nLg {{1, 1}, {198, 198}} + @@ -1193,6 +1186,7 @@ aW5nLg -2147483392 {{306, 1}, {15, 403}} + NO @@ -1204,6 +1198,7 @@ aW5nLg -2147483392 {{-100, -100}, {366, 16}} + NO 1 @@ -1214,7 +1209,8 @@ aW5nLg {{0, 20}, {200, 200}} - + + 150034 @@ -1229,6 +1225,7 @@ aW5nLg 268 {{66, -1}, {68, 23}} + _NS:22 YES @@ -1257,6 +1254,7 @@ aW5nLg 292 {{0, -1}, {34, 23}} + YES @@ -1283,6 +1281,8 @@ aW5nLg 292 {{166, -1}, {34, 23}} + + YES 67108864 @@ -1304,6 +1304,7 @@ aW5nLg 292 {{133, -1}, {34, 23}} + YES @@ -1326,6 +1327,7 @@ aW5nLg 292 {{33, -1}, {34, 23}} + YES @@ -1349,6 +1351,8 @@ aW5nLg {200, 220} + + NSView @@ -1373,6 +1377,78 @@ aW5nLg 0.0 YES + + + + + + Enable + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Show Enjoyable + + 2147483647 + + + + + + Quit Enjoyable + + 2147483647 + + + + + + + + + + + Enable + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + @@ -1408,6 +1484,14 @@ aW5nLg 870 + + + terminate: + + + + 937 + orderFrontStandardAboutPanel: @@ -1424,14 +1508,6 @@ aW5nLg 37 - - - arrangeInFront: - - - - 39 - performZoom: @@ -1458,11 +1534,11 @@ aW5nLg - unhideAllApplications: - - + performClose: + + - 370 + 941 @@ -1536,14 +1612,6 @@ aW5nLg 915 - - - dockMenuBase - - - - 726 - inputController @@ -1568,6 +1636,38 @@ aW5nLg 865 + + + statusItemMenu + + + + 928 + + + + dockMenu + + + + 930 + + + + mappingsMenu + + + + 931 + + + + restoreToForeground: + + + + 939 + removePressed: @@ -1880,6 +1980,22 @@ aW5nLg 880 + + + performClick: + + + + 932 + + + + performClick: + + + + 933 + @@ -1962,13 +2078,13 @@ aW5nLg - + @@ -1982,16 +2098,11 @@ aW5nLg - - 150 - - - 136 - Quit Enjoy + Quit Enjoyable 144 @@ -2031,7 +2142,6 @@ aW5nLg - @@ -2042,11 +2152,6 @@ aW5nLg - - 5 - - - 239 @@ -2594,6 +2699,70 @@ aW5nLg + + 918 + + + + + + + + + + Status Item Menu + + + 919 + + + + + 922 + + + + + 923 + + + + + + + Dock Menu + + + 926 + + + + + 924 + + + + + 925 + + + + + 936 + + + Quit Enjoyable + + + 938 + + + + + 940 + + + @@ -2607,7 +2776,6 @@ aW5nLg com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -2630,7 +2798,6 @@ aW5nLg com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin ToolTip @@ -2769,28 +2936,51 @@ aW5nLg com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin - 917 + 941 EnjoyableApplicationDelegate NSObject + + restoreToForeground: + id + + + restoreToForeground: + + restoreToForeground: + id + + - NSMenu + NSMenu NJDeviceController NJMappingsController + NSMenu + NSMenu NSWindow - - dockMenuBase + + dockMenu NSMenu @@ -2801,6 +2991,14 @@ aW5nLg mappingsController NJMappingsController + + mappingsMenu + NSMenu + + + statusItemMenu + NSMenu + window NSWindow diff --git a/Resources/Status Menu Icon Disabled.png b/Resources/Status Menu Icon Disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..8523aaef6913c85008f055eaa2ad7a466f3632d1 GIT binary patch literal 569 zcmV-90>=G`P)WFU8GbZ8()Nlj2>E@cM*00EszL_t(Y$L-b4YZO5c z1@NEQjVA6!(IgNhX2FYyiU#zc2p;^Og9wVCpa}j41|>*Hzz^JLK2|sDbQ)$xD^L0Dc`Sn z7zcH1tRWFU8GbZ8()Nlj2>E@cM*00WarL_t(&-tC#&PZL2H z#eZE&p%hUB6pKQ+iW@W$e9q8un#1C&zdt_29@1F)d?Zb@;AD(C>8 zfJM==%$RB5OB6FUW}GhqITz{`fo=od$yyB8^|B>i2W_8#LZK7`qxTEVMwd*Ja z;y|lt+HMKSjF&=sb)pp*uAkxeotxy z9nEMg0#)2qQ01J>R(XEZFVAg?4p*V@^N3wXN)*qEYUwJ^pOrCK2@+VQ&eo|?>3J#@ zZ1<_ygFyoevox6prqt$r!)E1GuXdC(rY+l$q$hyu%H56t-|W*nc|WSyW7#La%ZgW0 zwIhxCpy4U!RsR+x)#U+wAz!!->`QTj&hmlUs45;qA*tk8s#V6JH2_7!Z|02O@*%%F z=%5xBHEwGDXGh1QnCiKNwjZqaWP@gCN9h`~?uWz%$1hE7kx2002ovPDHLkV1k@+)q4N{ literal 0 HcmV?d00001 diff --git a/Resources/Status Menu Icon.png b/Resources/Status Menu Icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2b26cf6d636b02631f938f545f54a91261660e3e GIT binary patch literal 562 zcmV-20?qx2P)WFU8GbZ8()Nlj2>E@cM*00EXsL_t(Y$L-ZUNLOJL z2JoMzLWUX@f+Z-JLF6VPPSMa15g}QNgnJ-utqm@&Ep6eDgD$N>4%JYQK}(1ZMFegd zqLiSa|CXa%F8AaAL7NY}+mBqZ?)x)Hwcsi);}>?( zg9|})A}^ak93&V&#d#c-NVgkVPo?&k^8!7uv!yGT!H10f(R7fmf}$@5C0iVhM_8_Ni!aWq-j4NkBr(g4Az2et+*Q*Cw(m>4Q3Mu zU(wsZujgKrq7v7Uw83@Uj=9w+dT>8yqWoX{1E{IITwSpO*Z=?k07*qoM6N<$g4Mp{ Aa{vGU literal 0 HcmV?d00001 diff --git a/Resources/Status Menu Icon@2x.png b/Resources/Status Menu Icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..850151dcd6535f5f252a48c77e7b1c7dffe2eb07 GIT binary patch literal 1013 zcmV2+IHf03B&m zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00UV`L_t(&-tCx6NL4`? z$A4C856fFwLJ{=9uxyb1Z)OU4aSRskHC1PjRAfGzmx`W z8(3{1qY=0YTnGBRxaBfn(8Cr4MtcG5mB+vaft7YQIl=+3{v_CffkXq#0%j!v*wRD_ z9|hDVSmkPg%Rr~r-v=y76tF67vE#rN;Dk${YBU$1kH3jxf#aegAgnCXtEq913&0L* z{?Ul%h}*#Gv;`Wp@h>g_djSOGR;r`$bO00G0<~NbybH({XRA^gkPDo$0VE8R15<$t z>H7n8E8|Cjx!N;0?G~{6iqH%b-uX6wJv8x;ceU{r>F=^~Yi8y?7bsEw119_d8wWN{ z`JM#Kh`~ES-d*IoEZ*C?rk&zvpdPrQ@zns2fHs@&>XyWuA^GnH?g8&a70&{DBrsOz zwTk*XqHNK5qYX71L?iJUkAJ{Ik(UlMnegv*3hYb_p*_GHIkm+u`LXxf`ZrAY8=Zg} z3;gsr(CwFWC}M;frT7w>ZVw(>A+*9za7{LERv*B zo%0gdCI{K(V9h>Yid9gn94s)PnePH+?4ageT9w?{|71fEC4QQbI!?{vw>%Eyv;&0VEdAg z_Pfz8n5kmPFfAi)j8%S15#JSWTF@_+@VkUaJz`wKa*%2A9y2Af&vK!@iPSYiYPuhx znGQkq0uLmuuLIsH2EuAEkRuUHF|f%(77;BO4iTluX;-(arTXh8WdM~9vhu2E0yo$U zfA%N%-Q;W5)vR5LCaA!MGv48mQOHpox>>7?CM3}AwSJ+^px;=IlFwJes9lO~fZ zl4Q>FO~BQg2}suh*g>VvurtZNY98>~U~er()oCODF;XIswc>Yz61lez0Y{uFnZi1$ jeFVj5bmEgwLzDgk=6cG{aCf0E00000NkvXXu0mjf^}@m5 literal 0 HcmV?d00001 -- 2.20.1