| | |
| | | private var statusItem: NSStatusItem? |
| | | private var overlayWindow: NSWindow? |
| | | private var overlayKeyMonitor: Any? |
| | | private var quickSearchLocalMouseMonitor: Any? |
| | | private var quickSearchExternalMouseMonitor: Any? |
| | | private var settingsWindow: NSWindow? // Track Settings window to keep it above overlay |
| | | private var mainHotkeyRef: EventHotKeyRef? |
| | |
| | | |
| | | /// Settings must always appear centered over the current overlay view and float above it. |
| | | private func prepareSettingsWindow(_ window: NSWindow) { |
| | | dismissQuickSearchIfNeeded() |
| | | let settingsSize = NSSize(width: 880, height: 460) |
| | | window.identifier = NSUserInterfaceItemIdentifier("TagLauncherPreferencesWindow") |
| | | window.minSize = settingsSize |
| | |
| | | } |
| | | |
| | | private func installQuickSearchExternalMouseMonitor() { |
| | | installQuickSearchLocalMouseMonitor() |
| | | guard quickSearchExternalMouseMonitor == nil else { return } |
| | | quickSearchExternalMouseMonitor = NSEvent.addGlobalMonitorForEvents( |
| | | matching: [.leftMouseDown, .rightMouseDown, .otherMouseDown] |
| | |
| | | } |
| | | } |
| | | |
| | | private func installQuickSearchLocalMouseMonitor() { |
| | | guard quickSearchLocalMouseMonitor == nil else { return } |
| | | quickSearchLocalMouseMonitor = NSEvent.addLocalMonitorForEvents( |
| | | matching: [.leftMouseDown, .rightMouseDown, .otherMouseDown] |
| | | ) { [weak self] event in |
| | | guard let self, self.isQuickSearchOpen else { return event } |
| | | if event.window === self.overlayWindow { |
| | | NotificationCenter.default.post(name: .tagLauncherQuickSearchDismissRequested, object: nil) |
| | | return nil |
| | | } |
| | | return event |
| | | } |
| | | } |
| | | |
| | | private func removeQuickSearchExternalMouseMonitor() { |
| | | if let quickSearchLocalMouseMonitor { |
| | | NSEvent.removeMonitor(quickSearchLocalMouseMonitor) |
| | | self.quickSearchLocalMouseMonitor = nil |
| | | } |
| | | if let quickSearchExternalMouseMonitor { |
| | | NSEvent.removeMonitor(quickSearchExternalMouseMonitor) |
| | | self.quickSearchExternalMouseMonitor = nil |
| | |
| | | } |
| | | |
| | | @objc private func openPreferences(_ sender: Any? = nil) { |
| | | dismissQuickSearchIfNeeded() |
| | | TagDatabase.flushPendingCategorySchemeBackupBatch() |
| | | if overlayAvoidsSpaceSwitch { |
| | | refreshLauncherChromeState(activate: false, avoidSpaceSwitch: true) |
| | |
| | | prepareSettingsWindow(window) |
| | | } |
| | | |
| | | private func dismissQuickSearchIfNeeded() { |
| | | guard isQuickSearchOpen else { return } |
| | | isQuickSearchOpen = false |
| | | removeQuickSearchExternalMouseMonitor() |
| | | updateOverlayLevelForTextInput() |
| | | NotificationCenter.default.post(name: .tagLauncherQuickSearchDismissRequested, object: nil) |
| | | } |
| | | |
| | | @objc private func switchLanguage(_ sender: NSMenuItem) { |
| | | guard let code = sender.representedObject as? String else { return } |
| | | L10n.switchTo(code) |