Reveal tray icons only for the moment a menu is opened

Keeping every icon on the menu bar for as long as the panel was open
looked cluttered. Reveal them just long enough to open the clicked
item's menu, then hide again, so the panel stays clean.

💘 Generated with Crush

Assisted-by: Crush:deepseek-v4.1-flash
This commit is contained in:
2026-09-27 02:47:20 +08:00
parent 61d2689cbc
commit 9c5416d27e
3 changed files with 32 additions and 26 deletions
+1 -16
View File
@@ -17,7 +17,7 @@ struct SimpleTopBarApp: App {
/// full menu bar, a brand new item lands under the notch and is invisible;
/// writing `NSStatusItem Preferred Position <name>` into defaults puts it in a
/// visible slot, and the autosave name lets the user's own drag persist.
final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
final class AppDelegate: NSObject, NSApplicationDelegate {
private var statusItem: NSStatusItem?
private var popover: NSPopover?
@@ -103,7 +103,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
let popover = NSPopover()
popover.behavior = .transient
popover.animates = false
popover.delegate = self
popover.contentViewController = NSHostingController(
rootView: TopBarView(
model: AppListModel.shared,
@@ -114,20 +113,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
self.popover = popover
}
// Reveal the hidden menu bar items while the panel is open so pressing a
// tray icon opens that app's menu at its real, on-screen position.
func popoverWillShow(_ notification: Notification) {
MenuBarHider.shared.suspend()
}
func popoverDidClose(_ notification: Notification) {
// Small delay so a menu just opened from a tray tile is fully on screen
// before the bar contracts again.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) {
MenuBarHider.shared.resume()
}
}
@objc private func togglePopover() {
guard let popover, let button = statusItem?.button else { return }
if popover.isShown {
+24 -4
View File
@@ -103,10 +103,30 @@ final class MenuBarItemManager: ObservableObject {
}
}
/// Opens the real menu bar item by pressing its accessibility element, so
/// its menu/popover appears at its true screen location.
@discardableResult
func press(_ item: MenuBarItem) -> Bool {
/// Opens the real menu bar item, so its menu/popover appears.
///
/// A hidden item sits off-screen, and its menu would open off-screen too.
/// So briefly reveal the items, let the layout settle, press the item, then
/// hide again shortly after. The reveal is momentary rather than lasting the
/// whole time the panel is open.
func press(_ item: MenuBarItem) {
let hider = MenuBarHider.shared
let needsReveal = hider.isHiding
guard needsReveal else {
_ = performPress(item)
return
}
hider.suspend()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.18) {
_ = self.performPress(item)
// Let the menu finish appearing before the bar contracts again.
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
hider.resume()
}
}
}
private func performPress(_ item: MenuBarItem) -> Bool {
if AXUIElementPerformAction(item.element, kAXPressAction as CFString) == .success {
return true
}