-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
StatusItemController.swift
116 lines (96 loc) · 3.4 KB
/
StatusItemController.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//
// Created by Jesse Squires
// https://www.jessesquires.com
//
// Documentation
// https://hexedbits.github.io/StatusItemController
//
// GitHub
// https://github.com/hexedbits/StatusItemController
//
// Copyright © 2020-present Jesse Squires, Hexed Bits
// https://www.hexedbits.com
//
import AppKit
/// Controller for an `NSStatusItem`. Designed to be subclassed.
/// - Warning: You must subclass this controller.
@MainActor
open class StatusItemController: NSObject, NSMenuDelegate {
// MARK: Properties
/// The status item.
public let statusItem: NSStatusItem
// MARK: Init
/// Creates a new `StatusItemController`.
/// - Parameters:
/// - image: An image for the status item button.
/// - length: The length of the status item.
public init(image: NSImage, length: CGFloat = NSStatusItem.squareLength) {
self.statusItem = NSStatusBar.system.statusItem(withLength: length)
super.init()
self.statusItem.button?.toolTip = Bundle.main.infoDictionary?["CFBundleName"] as? String
self.statusItem.button?.image = image
(self.statusItem.button?.cell as? NSButtonCell)?.highlightsBy = [NSCell.StyleMask.init(rawValue: 0)]
self.statusItem.button?.target = self
self.statusItem.button?.action = #selector(_didClickStatusItem(_:))
self.statusItem.button?.sendAction(on: [.leftMouseDown, .rightMouseUp])
}
/// :nodoc:
deinit {
NSStatusBar.system.removeStatusItem(self.statusItem)
}
// MARK: Open methods
/// Constructs an `NSMenu` to display for the status item.
/// - Returns: A menu object.
/// - Warning: You must override this method.
open func buildMenu() -> NSMenu { NSMenu() }
/// The action to be executed on the `.leftMouseDown` event.
/// - Warning: You must override this method.
open func leftClickAction() { }
/// The action to be executed on `.rightMouseUp` event.
/// - Warning: You must override this method.
open func rightClickAction() { }
// MARK: Actions
/// Opens the status item menu.
/// You may wish to call this from `leftClickAction()` or `rightClickAction()`.
public func openMenu() {
// Yes, this is deprecated, however there seems to be a bug in AppKit.
// Without using this method, the menu does not popup immediately,
// and you have to right click a second time.
self.statusItem.popUpMenu(self._configureMenu(hidden: false)!)
}
/// Hides the status item menu.
public func hideMenu() {
self._configureMenu(hidden: true)
}
/// Quits the application.
/// You may wish to create an `NSMenuItem` that calls this method.
@objc
public func quit() {
NSApp.terminate(self)
}
// MARK: Private
@discardableResult
private func _configureMenu(hidden: Bool) -> NSMenu? {
if hidden {
self.statusItem.menu = nil
return nil
}
let menu = self.buildMenu()
menu.delegate = self
self.statusItem.menu = menu
return menu
}
@objc
private func _didClickStatusItem(_ sender: NSStatusItem) {
if NSApp.isCurrentEventRightClickUp {
self.rightClickAction()
} else {
self.leftClickAction()
}
}
// MARK: NSMenuDelegate
/// :nodoc:
public func menuDidClose(_ menu: NSMenu) {
self._configureMenu(hidden: true)
}
}