From 554dce57269e2ae24f5de9c39972cacbc0a350dc Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Tue, 19 May 2026 03:03:21 +0800
Subject: [PATCH] Fix stale app hover bubbles
---
Apptag/ApptagApp.swift | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 50 insertions(+), 8 deletions(-)
diff --git a/Apptag/ApptagApp.swift b/Apptag/ApptagApp.swift
index daf5d45..72a1665 100644
--- a/Apptag/ApptagApp.swift
+++ b/Apptag/ApptagApp.swift
@@ -29,6 +29,9 @@
final class AppDelegate: NSObject, NSApplicationDelegate {
private static let showDockIconKey = "showDockIcon"
+ private static let statusItemAutosaveName = "com.apptag.launcher.statusItem"
+ private static let statusItemButtonIdentifier = NSUserInterfaceItemIdentifier("TagLauncherStatusItemButton")
+ private static let statusItemAccessibilityLabel = "TagLauncher"
private static let showAppListMenuItemIdentifier = NSUserInterfaceItemIdentifier("TagLauncherShowAppListMenuItem")
private static let showAppListShortcutGlyphs = "⌥⇧␣"
private static let overlayDefaultLevel = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.maximumWindow)))
@@ -192,12 +195,19 @@
// MARK: - Menu Bar
private func setupMenuBar() {
- removeMenuBarItem()
- statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
+ if statusItem == nil {
+ statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
+ } else {
+ statusItem?.length = NSStatusItem.squareLength
+ }
guard let statusItem else { return }
+ statusItem.autosaveName = Self.statusItemAutosaveName
statusItem.isVisible = true
if let button = statusItem.button {
+ button.identifier = Self.statusItemButtonIdentifier
+ button.setAccessibilityIdentifier(Self.statusItemAutosaveName)
+ button.setAccessibilityLabel(Self.statusItemAccessibilityLabel)
button.image = makeMenuBarIcon()
button.imageScaling = .scaleProportionallyDown
button.imagePosition = .imageOnly
@@ -499,15 +509,22 @@
NSMouseInRect(mousePoint, $0.frame, false)
}) ?? NSScreen.main ?? NSScreen.screens.first else { return }
- overlayWindow?.orderOut(nil)
- overlayWindow = makeOverlayWindow(on: screen)
- overlayWindow?.setFrame(screen.frame, display: true)
- overlayWindow?.level = isEditingAppNote ? Self.overlayTextInputLevel : Self.overlayDefaultLevel
+ let window: NSWindow
+ if let existingWindow = overlayWindow {
+ window = existingWindow
+ } else {
+ window = makeOverlayWindow(on: screen)
+ overlayWindow = window
+ }
+
+ window.setFrame(screen.frame, display: true)
+ window.level = isEditingAppNote ? Self.overlayTextInputLevel : Self.overlayDefaultLevel
installOverlayKeyMonitor()
- overlayWindow?.makeKeyAndOrderFront(nil)
- overlayWindow?.orderFrontRegardless()
+ window.makeKeyAndOrderFront(nil)
+ window.orderFrontRegardless()
+ NotificationCenter.default.post(name: .tagLauncherOverlayDidShow, object: nil)
}
private func installOverlayKeyMonitor() {
@@ -569,6 +586,7 @@
}
overlayWindow?.orderOut(nil)
removeOverlayKeyMonitor()
+ NotificationCenter.default.post(name: .tagLauncherOverlayDidHide, object: nil)
if force {
overlayWindow = nil
}
@@ -819,15 +837,25 @@
final class DismissibleHostingView<Content: View>: NSHostingView<Content> {
private let onBackdropTap: () -> Void
+ private var suppressBackdropDismiss = false
+ private var modalInteractionObserver: NSObjectProtocol?
@MainActor required init(rootView: Content) {
self.onBackdropTap = {}
super.init(rootView: rootView)
+ observeModalInteractionChanges()
}
init(rootView: Content, onBackdropTap: @escaping () -> Void) {
self.onBackdropTap = onBackdropTap
super.init(rootView: rootView)
+ observeModalInteractionChanges()
+ }
+
+ deinit {
+ if let modalInteractionObserver {
+ NotificationCenter.default.removeObserver(modalInteractionObserver)
+ }
}
@available(*, unavailable)
@@ -840,6 +868,10 @@
return
}
if hit == self {
+ if suppressBackdropDismiss {
+ super.mouseDown(with: event)
+ return
+ }
onBackdropTap()
return
}
@@ -862,6 +894,16 @@
super.mouseDown(with: event)
}
+ private func observeModalInteractionChanges() {
+ modalInteractionObserver = NotificationCenter.default.addObserver(
+ forName: .tagLauncherModalInteractionChanged,
+ object: nil,
+ queue: .main
+ ) { [weak self] notification in
+ self?.suppressBackdropDismiss = (notification.userInfo?["active"] as? Bool) ?? false
+ }
+ }
+
private func findTextFieldContainer(in view: NSView) -> TextFieldContainer? {
if let container = view as? TextFieldContainer { return container }
for sub in view.subviews {
--
Gitblit v1.9.3