1import AppKit2import SwiftUI34@MainActor5class MenuController: NSObject {6 static private(set) weak var shared: MenuController?78 let statusItem: NSStatusItem9 let popover = NSPopover()10 var eventMonitor: EventMonitor?1112 init(statusItem: NSStatusItem) {13 self.statusItem = statusItem14 super.init()1516 if let button = statusItem.button {17 button.action = #selector(togglePopover(_:))18 button.target = self19 }2021 22 popover.contentSize = NSSize(width: 450, height: 640)23 popover.behavior = .transient24 popover.contentViewController = NSHostingController(rootView: MainView())2526 eventMonitor = EventMonitor(mask: [.leftMouseDown, .rightMouseDown]) { [weak self] event in27 if let self = self, self.popover.isShown {28 self.closePopover(sender: event)29 }30 }3132 MenuController.shared = self33 }3435 36 37 38 func beginModalPresentation() {39 eventMonitor?.stop()40 popover.behavior = .applicationDefined41 }4243 func endModalPresentation() {44 popover.behavior = .transient45 if popover.isShown {46 eventMonitor?.start()47 }48 }49 50 @objc func togglePopover(_ sender: AnyObject?) {51 if popover.isShown {52 closePopover(sender: sender)53 } else {54 showPopover(sender: sender)55 }56 }57 58 func showPopover(sender: AnyObject?) {59 if let button = statusItem.button {60 popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)61 eventMonitor?.start()62 }63 }64 65 func closePopover(sender: AnyObject?) {66 popover.performClose(sender)67 eventMonitor?.stop()68 }69}7071class EventMonitor {72 private var monitor: Any?73 private let mask: NSEvent.EventTypeMask74 private let handler: (NSEvent?) -> Void75 76 init(mask: NSEvent.EventTypeMask, handler: @escaping (NSEvent?) -> Void) {77 self.mask = mask78 self.handler = handler79 }80 81 deinit {82 stop()83 }84 85 func start() {86 monitor = NSEvent.addGlobalMonitorForEvents(matching: mask, handler: handler)87 }88 89 func stop() {90 if let monitor = monitor {91 NSEvent.removeMonitor(monitor)92 self.monitor = nil93 }94 }95}