From 62499d2a5428467bfb08f40dc8bea362da2c508f Mon Sep 17 00:00:00 2001 From: Lukas Romsicki Date: Sat, 7 Jan 2023 20:44:28 -0500 Subject: [PATCH] Fix dismiss when clicking a non-activating control --- Sources/FluidMenuBarExtra/EventMonitor.swift | 45 ++++++++++++++----- .../FluidMenuBarExtraStatusItem.swift | 17 +++++-- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/Sources/FluidMenuBarExtra/EventMonitor.swift b/Sources/FluidMenuBarExtra/EventMonitor.swift index 9d4a99b..9309813 100644 --- a/Sources/FluidMenuBarExtra/EventMonitor.swift +++ b/Sources/FluidMenuBarExtra/EventMonitor.swift @@ -8,17 +8,12 @@ import AppKit -final class EventMonitor { - typealias Handler = (NSEvent) -> NSEvent? - - private let mask: NSEvent.EventTypeMask - private let handler: Handler - - private var monitor: Any? +class EventMonitor { + fileprivate let mask: NSEvent.EventTypeMask + fileprivate var monitor: Any? - init(mask: NSEvent.EventTypeMask, handler: @escaping Handler) { + fileprivate init(mask: NSEvent.EventTypeMask) { self.mask = mask - self.handler = handler } deinit { @@ -26,7 +21,7 @@ final class EventMonitor { } func start() { - monitor = NSEvent.addLocalMonitorForEvents(matching: mask, handler: handler) + fatalError("start must be implemented by a subclass of EventMonitor") } func stop() { @@ -36,3 +31,33 @@ final class EventMonitor { } } } + +final class LocalEventMonitor: EventMonitor { + typealias Handler = (NSEvent) -> NSEvent? + + private let handler: Handler + + init(mask: NSEvent.EventTypeMask, handler: @escaping Handler) { + self.handler = handler + super.init(mask: mask) + } + + override func start() { + monitor = NSEvent.addLocalMonitorForEvents(matching: mask, handler: handler) + } +} + +final class GlobalEventMonitor: EventMonitor { + typealias Handler = (NSEvent) -> Void + + private let handler: Handler + + init(mask: NSEvent.EventTypeMask, handler: @escaping Handler) { + self.handler = handler + super.init(mask: mask) + } + + override func start() { + monitor = NSEvent.addGlobalMonitorForEvents(matching: mask, handler: handler) + } +} diff --git a/Sources/FluidMenuBarExtra/FluidMenuBarExtraStatusItem.swift b/Sources/FluidMenuBarExtra/FluidMenuBarExtraStatusItem.swift index 7a863ed..1e6ebab 100644 --- a/Sources/FluidMenuBarExtra/FluidMenuBarExtraStatusItem.swift +++ b/Sources/FluidMenuBarExtra/FluidMenuBarExtraStatusItem.swift @@ -15,7 +15,8 @@ final class FluidMenuBarExtraStatusItem: NSObject, NSWindowDelegate { private let window: NSWindow private let statusItem: NSStatusItem - private var eventMonitor: EventMonitor? + private var localEventMonitor: EventMonitor? + private var globalEventMonitor: EventMonitor? private init(window: NSWindow) { self.window = window @@ -25,7 +26,7 @@ final class FluidMenuBarExtraStatusItem: NSObject, NSWindowDelegate { super.init() - eventMonitor = EventMonitor(mask: [.leftMouseDown]) { [weak self] event in + localEventMonitor = LocalEventMonitor(mask: [.leftMouseDown]) { [weak self] event in if let button = self?.statusItem.button, event.window == button.window, !event.modifierFlags.contains(.command) { self?.didPressStatusBarButton(button) @@ -36,8 +37,16 @@ final class FluidMenuBarExtraStatusItem: NSObject, NSWindowDelegate { return event } + globalEventMonitor = GlobalEventMonitor(mask: [.leftMouseDown, .rightMouseDown]) { [weak self] event in + if let window = self?.window, window.isKeyWindow { + // Resign key window status if a external non-activating event is triggered, + // such as other system status bar menus. + window.resignKey() + } + } + window.delegate = self - eventMonitor?.start() + localEventMonitor?.start() } deinit { @@ -58,10 +67,12 @@ final class FluidMenuBarExtraStatusItem: NSObject, NSWindowDelegate { } func windowDidBecomeKey(_ notification: Notification) { + globalEventMonitor?.start() setButtonHighlighted(to: true) } func windowDidResignKey(_ notification: Notification) { + globalEventMonitor?.stop() dismissWindow() }