From 9f18811cfe5f8eebd6f373b7bf6f8f4178960390 Mon Sep 17 00:00:00 2001 From: David Albert Date: Sun, 6 Dec 2020 17:09:43 -0500 Subject: [PATCH] Close popover when preference window is clicked --- PiHoleStats/Controllers/MenuController.swift | 38 ++++++++++++++------ PiHoleStats/Util/EventMonitor.swift | 21 +++++++++-- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/PiHoleStats/Controllers/MenuController.swift b/PiHoleStats/Controllers/MenuController.swift index 971c5ac..1f3539e 100644 --- a/PiHoleStats/Controllers/MenuController.swift +++ b/PiHoleStats/Controllers/MenuController.swift @@ -17,7 +17,8 @@ class MenuController: NSObject { private lazy var navigationController = NavigationController(preferences: preferences, piholeDataProvider: dataProvider) private lazy var dataProvider = PiholeDataProvider(piholes: Pihole.restoreAll()) private lazy var summaryViewController = SummaryViewController(preferences: preferences, piHoleDataProvider: dataProvider, navigationController: navigationController) - private var eventMonitor: EventMonitor? + private var globalEventMonitor: EventMonitor? + private var localEventMonitor: EventMonitor? private var eventCancellable: AnyCancellable? private var statusPreferenceCancellable: AnyCancellable? private var statusCancellable: AnyCancellable? @@ -36,7 +37,7 @@ class MenuController: NSObject { public func setup() { updateButton() popover.contentViewController = summaryViewController - setupEventMonitor() + setupEventMonitors() dataProvider.startPolling() dataProvider.updatePollingMode(.background) updateButtonStatus() @@ -46,9 +47,11 @@ class MenuController: NSObject { private func setupCancellables() { eventCancellable = preferences.$keepPopoverPanelOpen.receive(on: DispatchQueue.main).sink { [weak self] keepPopoverOpen in if keepPopoverOpen { - self?.eventMonitor?.stop() + self?.globalEventMonitor?.stop() + self?.localEventMonitor?.stop() } else { - self?.eventMonitor?.start() + self?.globalEventMonitor?.start() + self?.localEventMonitor?.start() } } statusPreferenceCancellable = preferences.$displayStatusColorWhenPiholeIsOffline.receive(on: DispatchQueue.main).sink { [weak self] _ in @@ -60,17 +63,30 @@ class MenuController: NSObject { } } - private func setupEventMonitor() { - eventMonitor = EventMonitor(mask: [.leftMouseDown, .rightMouseDown]) { [weak self] event in + private func setupEventMonitors() { + globalEventMonitor = EventMonitor(mask: [.leftMouseDown, .rightMouseDown], scope: .global) { [weak self] event in if let strongSelf = self, strongSelf.popover.isShown { strongSelf.closePopover(sender: event) } } + + localEventMonitor = EventMonitor(mask: [.leftMouseDown, .rightMouseDown], scope: .local) { [weak self] event in + guard let self = self else { return } + + let popoverWindow = self.popover.contentViewController?.view.window + + if event?.window != popoverWindow && self.popover.isShown { + self.closePopover(sender: event) + } + } } private func destroyEventMonitor() { - eventMonitor?.stop() - eventMonitor = nil + globalEventMonitor?.stop() + globalEventMonitor = nil + + localEventMonitor?.stop() + localEventMonitor = nil } private func updateButtonStatus() { @@ -113,7 +129,8 @@ class MenuController: NSObject { private func showPopover(sender: Any?) { guard let button = statusItem.button else { return } if !preferences.keepPopoverPanelOpen { - eventMonitor?.start() + globalEventMonitor?.start() + localEventMonitor?.start() } popover.show( @@ -126,7 +143,8 @@ class MenuController: NSObject { private func closePopover(sender: Any?) { popover.performClose(sender) - eventMonitor?.stop() + globalEventMonitor?.stop() + localEventMonitor?.stop() dataProvider.updatePollingMode(.background) } diff --git a/PiHoleStats/Util/EventMonitor.swift b/PiHoleStats/Util/EventMonitor.swift index e8576dc..2f36674 100644 --- a/PiHoleStats/Util/EventMonitor.swift +++ b/PiHoleStats/Util/EventMonitor.swift @@ -34,13 +34,20 @@ import Cocoa import os.log public class EventMonitor { + public enum EventScope { + case global + case local + } + private let log = Logger().osLog(describing: EventMonitor.self) private var monitor: Any? private let mask: NSEvent.EventTypeMask + private let scope: EventScope private let handler: (NSEvent?) -> Void - public init(mask: NSEvent.EventTypeMask, handler: @escaping (NSEvent?) -> Void) { + public init(mask: NSEvent.EventTypeMask, scope: EventScope, handler: @escaping (NSEvent?) -> Void) { self.mask = mask + self.scope = scope self.handler = handler os_log("Event monitor init", log: self.log, type: .debug) } @@ -55,7 +62,17 @@ public class EventMonitor { return } os_log("Event monitor start", log: self.log, type: .debug) - monitor = NSEvent.addGlobalMonitorForEvents(matching: mask, handler: handler) + + switch scope { + case .global: + monitor = NSEvent.addGlobalMonitorForEvents(matching: mask, handler: handler) + case .local: + monitor = NSEvent.addLocalMonitorForEvents(matching: mask) { event in + self.handler(event) + + return event + } + } } public func stop() {