/// Copyright 2015 Google Inc. All rights reserved. /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. #import "SNTAppDelegate.h" #import "SNTAboutWindowController.h" #import "SNTConfigurator.h" #import "SNTFileWatcher.h" #import "SNTNotificationManager.h" #import "SNTXPCConnection.h" @interface SNTAppDelegate () @property SNTAboutWindowController *aboutWindowController; @property SNTFileWatcher *configFileWatcher; @property SNTNotificationManager *notificationManager; @property SNTXPCConnection *listener; @end @implementation SNTAppDelegate #pragma mark App Delegate methods - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { [self setupMenu]; self.configFileWatcher = [[SNTFileWatcher alloc] initWithFilePath:kDefaultConfigFilePath handler:^{ [[SNTConfigurator configurator] reloadConfigData]; }]; self.notificationManager = [[SNTNotificationManager alloc] init]; NSNotificationCenter *workspaceNotifications = [[NSWorkspace sharedWorkspace] notificationCenter]; [workspaceNotifications addObserver:self selector:@selector(killConnection) name:NSWorkspaceSessionDidResignActiveNotification object:nil]; [workspaceNotifications addObserver:self selector:@selector(createConnection) name:NSWorkspaceSessionDidBecomeActiveNotification object:nil]; [self createConnection]; } - (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag { self.aboutWindowController = [[SNTAboutWindowController alloc] init]; [self.aboutWindowController showWindow:self]; return NO; } #pragma mark Connection handling - (void)createConnection { __weak __typeof(self) weakSelf = self; self.listener = [[SNTXPCConnection alloc] initClientWithName:[SNTXPCNotifierInterface serviceId] options:NSXPCConnectionPrivileged]; self.listener.exportedInterface = [SNTXPCNotifierInterface notifierInterface]; self.listener.exportedObject = self.notificationManager; self.listener.rejectedHandler = ^{ [weakSelf attemptReconnection]; }; self.listener.invalidationHandler = self.listener.rejectedHandler; [self.listener resume]; } - (void)killConnection { self.listener.invalidationHandler = nil; [self.listener invalidate]; self.listener = nil; } - (void)attemptReconnection { // TODO(rah): Make this smarter. sleep(10); [self performSelectorOnMainThread:@selector(createConnection) withObject:nil waitUntilDone:NO]; } #pragma mark Menu Management - (void)setupMenu { // Whilst the user will never see the menu, having one with the Copy and Select All options // allows the shortcuts for these items to work, which is useful for being able to copy // information from notifications. The mainMenu must have a nested menu for this to work properly. NSMenu *mainMenu = [[NSMenu alloc] init]; NSMenu *editMenu = [[NSMenu alloc] init]; [editMenu addItemWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]; [editMenu addItemWithTitle:@"Select All" action:@selector(selectAll:) keyEquivalent:@"a"]; NSMenuItem *editMenuItem = [[NSMenuItem alloc] init]; [editMenuItem setSubmenu:editMenu]; [mainMenu addItem:editMenuItem]; [NSApp setMainMenu:mainMenu]; } @end