Ariver
2026-05-29 1797e722aa5453f646187ab61483f70f7e19fd1f
Apptag/ApptagApp.swift
@@ -54,6 +54,7 @@
    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?
@@ -949,8 +950,6 @@
        for startIndex in tallWindows.indices {
            var union = tallWindows[startIndex].frame
            var lastMaxX = union.maxX
            var distinctOwners = Swift.Set<String>()
            distinctOwners.insert(tallWindows[startIndex].owner)
            for window in tallWindows.dropFirst(startIndex + 1) {
                let gap = window.frame.minX - lastMaxX
@@ -959,13 +958,12 @@
                }
                union = union.union(window.frame)
                lastMaxX = max(lastMaxX, window.frame.maxX)
                distinctOwners.insert(window.owner)
                let touchesLeft = abs(union.minX - screenFrame.minX) <= 32
                let touchesRight = abs(union.maxX - screenFrame.maxX) <= 32
                let coversWidth = union.width >= screenFrame.width * 0.92
                let coversHeight = union.height >= screenFrame.height * 0.86
                if distinctOwners.count >= 2 && touchesLeft && touchesRight && coversWidth && coversHeight {
                if touchesLeft && touchesRight && coversWidth && coversHeight {
                    return true
                }
            }
@@ -1282,6 +1280,7 @@
    /// 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
@@ -1432,7 +1431,10 @@
            let preferredScreen = self.overlayWindow?.screen
            self.detachSettingsWindow(closingWindow)
            self.settingsWindow = nil
            self.refreshLauncherChromeState(activate: shouldRefocusOverlay)
            self.refreshLauncherChromeState(
                activate: shouldRefocusOverlay && !self.overlayAvoidsSpaceSwitch,
                avoidSpaceSwitch: self.overlayAvoidsSpaceSwitch
            )
            guard shouldRefocusOverlay else { return }
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.12) { [weak self] in
                self?.showOrFocusOverlay(preferredScreen: preferredScreen)
@@ -1518,6 +1520,7 @@
    }
    private func installQuickSearchExternalMouseMonitor() {
        installQuickSearchLocalMouseMonitor()
        guard quickSearchExternalMouseMonitor == nil else { return }
        quickSearchExternalMouseMonitor = NSEvent.addGlobalMonitorForEvents(
            matching: [.leftMouseDown, .rightMouseDown, .otherMouseDown]
@@ -1529,7 +1532,25 @@
        }
    }
    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
@@ -1571,6 +1592,7 @@
    }
    @objc private func openPreferences(_ sender: Any? = nil) {
        dismissQuickSearchIfNeeded()
        TagDatabase.flushPendingCategorySchemeBackupBatch()
        if overlayAvoidsSpaceSwitch {
            refreshLauncherChromeState(activate: false, avoidSpaceSwitch: true)
@@ -1602,6 +1624,14 @@
        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)