123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- /*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #import "AppDelegate.h"
- #import "NetworkMonitor.h"
- #import "Network.h"
- #import "NodeStatus.h"
- #import "JoinNetworkViewController.h"
- #import "ShowNetworksViewController.h"
- #import "PreferencesViewController.h"
- #import "AboutViewController.h"
- #import "ServiceCom.h"
- @implementation AppDelegate
- - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
- self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:-2.0f];
- self.networkListPopover = [[NSPopover alloc] init];
- self.joinNetworkPopover = [[NSPopover alloc] init];
- self.preferencesPopover = [[NSPopover alloc] init];
- self.aboutPopover = [[NSPopover alloc] init];
- self.transientMonitor = nil;
- self.monitor = [[NetworkMonitor alloc] init];
- self.networks = [NSMutableArray<Network*> array];
- self.status = nil;
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- NSDictionary *defaultsDict = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:@"firstRun"];
- [defaults registerDefaults:defaultsDict];
- NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
- [nc addObserver:self
- selector:@selector(onNetworkListUpdated:)
- name:NetworkUpdateKey
- object:nil];
- [nc addObserver:self
- selector:@selector(onNodeStatusUpdated:)
- name:StatusUpdateKey
- object:nil];
- NSString *osxMode = [defaults stringForKey:@"AppleInterfaceStyle"];
- if(osxMode != nil && [osxMode isEqualToString:@"Dark"]) {
- self.statusItem.image = [NSImage imageNamed:@"MenuBarIconMacWhite"];
- }
- else {
- self.statusItem.image = [NSImage imageNamed:@"MenuBarIconMac"];
- }
- [[NSDistributedNotificationCenter defaultCenter] addObserver:self
- selector:@selector(darkModeChanged:)
- name:@"AppleInterfaceThemeChangedNotification"
- object:nil];
- [self buildMenu];
- JoinNetworkViewController *jnvc = [[JoinNetworkViewController alloc] initWithNibName:@"JoinNetworkViewController" bundle:nil];
- jnvc.appDelegate = self;
- self.joinNetworkPopover.contentViewController = jnvc;
- self.joinNetworkPopover.behavior = NSPopoverBehaviorTransient;
- ShowNetworksViewController *showNetworksView = [[ShowNetworksViewController alloc] initWithNibName:@"ShowNetworksViewController" bundle:nil];
- showNetworksView.netMonitor = self.monitor;
- self.networkListPopover.contentViewController = showNetworksView;
- self.networkListPopover.behavior = NSPopoverBehaviorTransient;
- PreferencesViewController *prefsView = [[PreferencesViewController alloc] initWithNibName:@"PreferencesViewController" bundle:nil];
- self.preferencesPopover.contentViewController = prefsView;
- self.preferencesPopover.behavior = NSPopoverBehaviorTransient;
- self.aboutPopover.contentViewController = [[AboutViewController alloc] initWithNibName:@"AboutViewController" bundle:nil];
- self.aboutPopover.behavior = NSPopoverBehaviorTransient;
- BOOL firstRun = [defaults boolForKey:@"firstRun"];
- if(firstRun) {
- [defaults setBool:NO forKey:@"firstRun"];
- [defaults synchronize];
- [prefsView setLaunchAtLoginEnabled:YES];
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- sleep(2);
- [[NSOperationQueue mainQueue] addOperationWithBlock:^{
- [self showAbout];
- }];
- });
- }
- [self.monitor updateNetworkInfo];
- [self.monitor start];
- }
- - (void)applicationWillTerminate:(NSNotification *)aNotification {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [[NSDistributedNotificationCenter defaultCenter] removeObserver:self
- name:@"AppleInterfaceThemeChangedNotification"
- object:nil];
- }
- - (void)showNetworks {
- NSButton *button = nil;
- NSRect frame;
- if ([self.statusItem respondsToSelector:@selector(button)]) {
- button = self.statusItem.button;
- frame = button.bounds;
- } else if ([self.statusItem respondsToSelector:@selector(_button)]) {
- button = [self.statusItem performSelector:@selector(_button)];
- frame = button.bounds;
- } else {
- NSLog(@"Can't get view. Uh oh.");
- return;
- }
-
- [self.networkListPopover showRelativeToRect:frame
- ofView:button
- preferredEdge:NSMinYEdge];
- if(self.transientMonitor == nil) {
- self.transientMonitor =
- [NSEvent addGlobalMonitorForEventsMatchingMask:(NSLeftMouseDown|NSRightMouseDown|NSOtherMouseDown)
- handler:^(NSEvent * _Nonnull e) {
- [NSEvent removeMonitor:self.transientMonitor];
- self.transientMonitor = nil;
- [self.networkListPopover close];
- }];
- }
- }
- - (void)joinNetwork {
- NSButton *button = nil;
- NSRect frame;
- if ([self.statusItem respondsToSelector:@selector(button)]) {
- button = self.statusItem.button;
- frame = button.bounds;
- } else if ([self.statusItem respondsToSelector:@selector(_button)]) {
- button = [self.statusItem performSelector:@selector(_button)];
- frame = button.bounds;
- } else {
- NSLog(@"Can't get view. Uh oh.");
- return;
- }
-
- [self.joinNetworkPopover showRelativeToRect:button.bounds
- ofView:button
- preferredEdge:NSMinYEdge];
- if(self.transientMonitor == nil) {
- self.transientMonitor =
- [NSEvent addGlobalMonitorForEventsMatchingMask:(NSLeftMouseDown|NSRightMouseDown|NSOtherMouseDown)
- handler:^(NSEvent * _Nonnull e) {
- [NSEvent removeMonitor:self.transientMonitor];
- self.transientMonitor = nil;
- [self.joinNetworkPopover close];
- }];
- }
- }
- - (void)showPreferences {
- NSButton *button = nil;
- NSRect frame;
- if ([self.statusItem respondsToSelector:@selector(button)]) {
- button = self.statusItem.button;
- frame = button.bounds;
- } else if ([self.statusItem respondsToSelector:@selector(_button)]) {
- button = [self.statusItem performSelector:@selector(_button)];
- frame = button.bounds;
- } else {
- NSLog(@"Can't get view. Uh oh.");
- return;
- }
- [self.preferencesPopover showRelativeToRect:button.bounds
- ofView:button
- preferredEdge:NSMinYEdge];
- if(self.transientMonitor == nil) {
- [NSEvent addGlobalMonitorForEventsMatchingMask:(NSLeftMouseDown|NSRightMouseDown|NSOtherMouseDown)
- handler:^(NSEvent * _Nonnull e) {
- [NSEvent removeMonitor:self.transientMonitor];
- self.transientMonitor = nil;
- [self.preferencesPopover close];
- }];
- }
- }
- - (void)showAbout {
- NSButton *button = nil;
- NSRect frame;
- if ([self.statusItem respondsToSelector:@selector(button)]) {
- button = self.statusItem.button;
- frame = button.bounds;
- } else if ([self.statusItem respondsToSelector:@selector(_button)]) {
- button = [self.statusItem performSelector:@selector(_button)];
- frame = button.bounds;
- } else {
- NSLog(@"Can't get view. Uh oh.");
- return;
- }
-
- [self.aboutPopover showRelativeToRect:button.bounds
- ofView:button
- preferredEdge:NSMinYEdge];
- if(self.transientMonitor == nil) {
- [NSEvent addGlobalMonitorForEventsMatchingMask:(NSLeftMouseDown|NSRightMouseDown|NSOtherMouseDown)
- handler:^(NSEvent * _Nonnull e) {
- [NSEvent removeMonitor:self.transientMonitor];
- self.transientMonitor = nil;
- [self.aboutPopover close];
- }];
- }
- }
- - (void)quit {
- [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0];
- }
- - (void)onNetworkListUpdated:(NSNotification*)note {
- NSArray<Network*> *netList = [note.userInfo objectForKey:@"networks"];
- [(ShowNetworksViewController*)self.networkListPopover.contentViewController setNetworks:netList];
- self.networks = [netList mutableCopy];
- [self buildMenu];
- }
- - (void)onNodeStatusUpdated:(NSNotification*)note {
- NodeStatus *status = [note.userInfo objectForKey:@"status"];
- self.status = status;
- [self buildMenu];
- }
- - (void)buildMenu {
- NSMenu *menu = [[NSMenu alloc] init];
- if(self.status != nil) {
- NSString *nodeId = @"Node ID: ";
- nodeId = [nodeId stringByAppendingString:self.status.address];
- [menu addItem:[[NSMenuItem alloc] initWithTitle:nodeId
- action:@selector(copyNodeID)
- keyEquivalent:@""]];
- [menu addItem:[NSMenuItem separatorItem]];
- }
- [menu addItem:[[NSMenuItem alloc] initWithTitle:@"Network Details..."
- action:@selector(showNetworks)
- keyEquivalent:@"n"]];
- [menu addItem:[[NSMenuItem alloc] initWithTitle:@"Join Network..."
- action:@selector(joinNetwork)
- keyEquivalent:@"j"]];
- [menu addItem:[NSMenuItem separatorItem]];
- if([self.networks count] > 0) {
- for(Network *net in self.networks) {
- NSString *nwid = [NSString stringWithFormat:@"%10llx", net.nwid];
- NSString *networkName = @"";
- if([net.name lengthOfBytesUsingEncoding:NSUTF8StringEncoding] == 0) {
- networkName = nwid;
- }
- else {
- networkName = [NSString stringWithFormat:@"%@ (%@)", nwid, net.name];
- }
- if(net.allowDefault && net.connected) {
- networkName = [networkName stringByAppendingString:@" [default]"];
- }
- NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:networkName
- action:@selector(toggleNetwork:)
- keyEquivalent:@""];
- if(net.connected) {
- item.state = NSOnState;
- }
- else {
- item.state = NSOffState;
- }
- item.representedObject = net;
- [menu addItem:item];
- }
- [menu addItem:[NSMenuItem separatorItem]];
- }
- [menu addItem:[[NSMenuItem alloc] initWithTitle:@"About ZeroTier One..."
- action:@selector(showAbout)
- keyEquivalent:@""]];
- [menu addItem:[[NSMenuItem alloc] initWithTitle:@"Preferences..."
- action:@selector(showPreferences)
- keyEquivalent:@""]];
- [menu addItem:[NSMenuItem separatorItem]];
- [menu addItem:[[NSMenuItem alloc] initWithTitle:@"Quit"
- action:@selector(quit)
- keyEquivalent:@"q"]];
- self.statusItem.menu = menu;
- }
- - (void)toggleNetwork:(NSMenuItem*)sender {
- Network *network = sender.representedObject;
- NSString *nwid = [NSString stringWithFormat:@"%10llx", network.nwid];
- if(network.connected) {
- NSError *error = nil;
- [[ServiceCom sharedInstance] leaveNetwork:nwid error:&error];
- if (error) {
- NSAlert *alert = [NSAlert alertWithError:error];
- alert.alertStyle = NSCriticalAlertStyle;
- [alert addButtonWithTitle:@"Ok"];
- [alert runModal];
- }
- }
- else {
- NSError *error = nil;
- [[ServiceCom sharedInstance] joinNetwork:nwid
- allowManaged:network.allowManaged
- allowGlobal:network.allowGlobal
- allowDefault:(network.allowDefault && ![Network defaultRouteExists:self.networks])
- error:&error];
- if (error) {
- NSAlert *alert = [NSAlert alertWithError:error];
- alert.alertStyle = NSCriticalAlertStyle;
- [alert addButtonWithTitle:@"Ok"];
- [alert runModal];
- }
- }
- }
- - (void)copyNodeID {
- if(self.status != nil) {
- NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
- [pasteboard declareTypes:[NSArray arrayWithObject:NSPasteboardTypeString] owner:nil];
- [pasteboard setString:self.status.address forType:NSPasteboardTypeString];
- }
- }
- - (void)darkModeChanged:(NSNotification*)note {
- NSString *osxMode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
- if(osxMode != nil && [osxMode isEqualToString:@"Dark"]) {
- self.statusItem.image = [NSImage imageNamed:@"MenuBarIconMacWhite"];
- }
- else {
- self.statusItem.image = [NSImage imageNamed:@"MenuBarIconMac"];
- }
- }
- - (void)closeJoinNetworkPopover {
- if (self.transientMonitor) {
- [NSEvent removeMonitor:self.transientMonitor];
- self.transientMonitor = nil;
- }
- [self.joinNetworkPopover close];
- }
- @end
|