AppDelegate.swift 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. //
  2. // AppDelegate.swift
  3. // ZeroTier One
  4. //
  5. // Created by Grant Limberg on 5/14/16.
  6. // Copyright © 2016 ZeroTier, Inc. All rights reserved.
  7. //
  8. import Cocoa
  9. @NSApplicationMain
  10. class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
  11. @IBOutlet weak var window: NSWindow!
  12. let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(-2.0)
  13. let networkListPopover = NSPopover()
  14. let joinNetworkPopover = NSPopover()
  15. let preferencesPopover = NSPopover()
  16. let aboutPopover = NSPopover()
  17. var transientMonitor: AnyObject? = nil
  18. let monitor = NetworkMonitor()
  19. var networks = [Network]()
  20. var status: NodeStatus? = nil
  21. var pasteboard = NSPasteboard.generalPasteboard()
  22. func applicationDidFinishLaunching(aNotification: NSNotification) {
  23. pasteboard.declareTypes([NSPasteboardTypeString], owner: nil)
  24. let defaults = NSUserDefaults.standardUserDefaults()
  25. let defaultsDict = ["firstRun": true]
  26. defaults.registerDefaults(defaultsDict)
  27. let firstRun = defaults.boolForKey("firstRun")
  28. if firstRun {
  29. defaults.setBool(false, forKey: "firstRun")
  30. defaults.synchronize()
  31. let loginController = LaunchAtLoginController()
  32. let bundle = NSBundle.mainBundle()
  33. let bundleURL = bundle.bundleURL
  34. loginController.setLaunchAtLogin(true, forURL: bundleURL)
  35. }
  36. let nc = NSNotificationCenter.defaultCenter()
  37. nc.addObserver(self, selector: #selector(onNetworkListUpdated(_:)), name: networkUpdateKey, object: nil)
  38. nc.addObserver(self, selector: #selector(onNodeStatusUpdated(_:)), name: statusUpdateKey, object: nil)
  39. statusItem.image = NSImage(named: "MenuBarIconMac")
  40. buildMenu()
  41. joinNetworkPopover.contentViewController = JoinNetworkViewController(
  42. nibName: "JoinNetworkViewController", bundle: nil)
  43. joinNetworkPopover.behavior = .Transient
  44. let showNetworksView = ShowNetworksViewController(
  45. nibName: "ShowNetworksViewController", bundle: nil)
  46. showNetworksView?.netMonitor = monitor
  47. networkListPopover.contentViewController = showNetworksView
  48. networkListPopover.behavior = .Transient
  49. preferencesPopover.contentViewController = PreferencesViewController(
  50. nibName: "PreferencesViewController", bundle: nil)
  51. preferencesPopover.behavior = .Transient
  52. aboutPopover.contentViewController = AboutViewController(
  53. nibName: "AboutViewController", bundle: nil)
  54. aboutPopover.behavior = .Transient
  55. if firstRun {
  56. NSOperationQueue.mainQueue().addOperationWithBlock() {
  57. self.showAbout()
  58. }
  59. }
  60. monitor.updateNetworkInfo()
  61. monitor.start()
  62. }
  63. func applicationWillTerminate(aNotification: NSNotification) {
  64. // Insert code here to tear down your application
  65. let nc = NSNotificationCenter.defaultCenter()
  66. nc.removeObserver(self)
  67. }
  68. func showNetworks() {
  69. if let button = statusItem.button {
  70. networkListPopover.showRelativeToRect(button.bounds, ofView: button, preferredEdge: .MinY)
  71. if transientMonitor == nil {
  72. transientMonitor = NSEvent.addGlobalMonitorForEventsMatchingMask(
  73. [.LeftMouseDownMask, .RightMouseDownMask, .OtherMouseDownMask]) { (event: NSEvent) -> Void in
  74. NSEvent.removeMonitor(self.transientMonitor!)
  75. self.transientMonitor = nil
  76. self.networkListPopover.close()
  77. }
  78. }
  79. }
  80. }
  81. func joinNetwork() {
  82. if let button = statusItem.button {
  83. joinNetworkPopover.showRelativeToRect(button.bounds, ofView: button, preferredEdge: .MinY)
  84. if transientMonitor == nil {
  85. transientMonitor = NSEvent.addGlobalMonitorForEventsMatchingMask(
  86. [.LeftMouseDownMask, .RightMouseDownMask, .OtherMouseDownMask]) { (event: NSEvent) -> Void in
  87. NSEvent.removeMonitor(self.transientMonitor!)
  88. self.transientMonitor = nil
  89. self.joinNetworkPopover.close()
  90. }
  91. }
  92. }
  93. }
  94. func showPreferences() {
  95. if let button = statusItem.button {
  96. preferencesPopover.showRelativeToRect(button.bounds, ofView: button, preferredEdge: .MinY)
  97. if transientMonitor == nil {
  98. transientMonitor = NSEvent.addGlobalMonitorForEventsMatchingMask(
  99. [.LeftMouseDownMask, .RightMouseDownMask, .OtherMouseDownMask]) { (event: NSEvent) -> Void in
  100. NSEvent.removeMonitor(self.transientMonitor!)
  101. self.transientMonitor = nil
  102. self.preferencesPopover.close()
  103. }
  104. }
  105. }
  106. }
  107. func showAbout() {
  108. if let button = statusItem.button {
  109. aboutPopover.showRelativeToRect(button.bounds, ofView: button, preferredEdge: .MinY)
  110. if transientMonitor == nil {
  111. transientMonitor = NSEvent.addGlobalMonitorForEventsMatchingMask(
  112. [.LeftMouseDownMask, .RightMouseDownMask, .OtherMouseDownMask]) { (event: NSEvent) -> Void in
  113. NSEvent.removeMonitor(self.transientMonitor!)
  114. self.transientMonitor = nil
  115. self.aboutPopover.close()
  116. }
  117. }
  118. }
  119. }
  120. func quit() {
  121. NSApp.performSelector(#selector(NSApp.terminate(_:)), withObject: nil, afterDelay: 0.0)
  122. }
  123. func onNetworkListUpdated(note: NSNotification) {
  124. let netList = note.userInfo!["networks"] as! [Network]
  125. (networkListPopover.contentViewController as! ShowNetworksViewController).setNetworks(netList)
  126. self.networks = netList
  127. buildMenu()
  128. }
  129. func onNodeStatusUpdated(note: NSNotification) {
  130. let status = note.userInfo!["status"] as! NodeStatus
  131. self.status = status
  132. buildMenu()
  133. }
  134. func buildMenu() {
  135. let menu = NSMenu()
  136. menu.delegate = self
  137. if let s = self.status {
  138. menu.addItem(NSMenuItem(title: "Node ID: \(s.address)", action: #selector(AppDelegate.copyNodeID), keyEquivalent: ""))
  139. menu.addItem(NSMenuItem.separatorItem())
  140. }
  141. menu.addItem(NSMenuItem(title: "Network Details...", action: #selector(AppDelegate.showNetworks), keyEquivalent: "n"))
  142. menu.addItem(NSMenuItem(title: "Join Network...", action: #selector(AppDelegate.joinNetwork), keyEquivalent: "j"))
  143. menu.addItem(NSMenuItem.separatorItem())
  144. if networks.count > 0 {
  145. for net in networks {
  146. let id = String(net.nwid, radix: 16)
  147. var networkName = ""
  148. if net.name.isEmpty {
  149. networkName = "\(id)"
  150. }
  151. else {
  152. networkName = "\(id) (\(net.name))"
  153. }
  154. if net.allowDefault && net.connected {
  155. networkName += " [default]"
  156. }
  157. let item = NSMenuItem(title: networkName, action: #selector(AppDelegate.toggleNetwork(_:)), keyEquivalent: "")
  158. if net.connected {
  159. item.state = NSOnState
  160. }
  161. else {
  162. item.state = NSOffState
  163. }
  164. item.representedObject = net
  165. menu.addItem(item)
  166. }
  167. menu.addItem(NSMenuItem.separatorItem())
  168. }
  169. menu.addItem(NSMenuItem(title: "About ZeroTier One...", action: #selector(AppDelegate.showAbout), keyEquivalent: ""))
  170. menu.addItem(NSMenuItem(title: "Preferences...", action: #selector(AppDelegate.showPreferences), keyEquivalent: ","))
  171. menu.addItem(NSMenuItem.separatorItem())
  172. menu.addItem(NSMenuItem(title: "Quit ZeroTier One", action: #selector(AppDelegate.quit), keyEquivalent: "q"))
  173. statusItem.menu = menu
  174. }
  175. func toggleNetwork(sender: NSMenuItem) {
  176. NSLog("\(sender.title)")
  177. let network = sender.representedObject as! Network
  178. let id = String(network.nwid, radix: 16)
  179. if network.connected {
  180. ServiceCom.sharedInstance().leaveNetwork(id)
  181. }
  182. else {
  183. ServiceCom.sharedInstance().joinNetwork(id, allowManaged: true, allowGlobal: false, allowDefault: false)
  184. }
  185. }
  186. func copyNodeID() {
  187. if let s = self.status {
  188. pasteboard.setString(s.address, forType: NSPasteboardTypeString)
  189. }
  190. }
  191. func menuWillOpen(menu: NSMenu) {
  192. //monitor.updateNetworkInfo()
  193. }
  194. func menuDidClose(menu: NSMenu) {
  195. }
  196. }