Skip to content

fix: close the popover when another menu bar popup opens - #154

Merged
chattymin merged 2 commits into
chattymin:mainfrom
jjamming:fix/close-popover-on-other-menu-bar-popup
Aug 15, 2026
Merged

chattymin merged 2 commits into
chattymin:mainfrom
jjamming:fix/close-popover-on-other-menu-bar-popup

Conversation

@jjamming

@jjamming jjamming commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Update — reworked after review

Review testing was correct: opening another menu bar popup does not postdidResignActiveNotification (the app stays active), so the original observer never ran — the patch was a no-op for this exact case. Switched to the suggested global monitor:

  • Register NSEvent.addGlobalMonitorForEvents([.leftMouseDown, .rightMouseDown]) when the popover opens, remove it in popoverDidClose (zero idle cost), keep the returned token, and keep the isShown guard.
  • Removed the didResignActive observer entirely.

Verified in a signed .app on macOS 26 with real clicks: opening Control Center / Wi-Fi now dismisses the popover; desktop / other-app clicks and in-popover buttons still behave; no input-monitoring permission prompt appears.

Video

poketoken_tobe.mp4

Checklist

  • swift build passes locally; verified live in a signed .app (manual click test); full suite runs in CI
  • PR title and description are written in English
  • No UI changes (menu bar dismissal behavior only)
  • No copyrighted assets, secrets, or private tooling references committed
  • No unit test — NSEvent global monitor is AppKit runtime behavior not exercisable without a running app; verified by manual click test instead
Original description (superseded by the rework above)

Summary — the popover uses .transient, which only dismisses on outside clicks the app itself receives. Opening another menu bar popup merely deactivates PokeTokenBar, so no outside click reaches us and the popover lingers.

Fix — observe NSApplication.didResignActiveNotification and close the popover when the app resigns active; the isShown guard + performClose idempotency make it a no-op for paths .transient already handled.

A .transient NSPopover only dismisses on outside clicks the app itself
receives. Opening another menu bar popup (a system menu or another app's
status item) deactivates PokeTokenBar without delivering that outside
click, so the popover stayed open. Close it on didResignActive.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@chattymin

Copy link
Copy Markdown
Owner

@jjamming Thanks for tracking this down — the popover really does linger when a menu bar popup opens, and pinpointing .transient's dismissal path was a useful lead.

Before merging I A/B tested it here (macOS 26.5, scratch app reproducing togglePopover()'s exact sequence, real CGEvent click on the Control Center Wi-Fi item), and the chosen signal doesn't fire for this case:

  1. Opening a menu bar popup does not post didResignActiveNotification — the app stays active, so the observer never runs. The popover stays open with and without this patch.
  2. Where the notification does fire (another app activating), the .transient popover already closes on its own 0.34–0.55s later.

Two signals that do fire, both verified in a signed .app with AXIsProcessTrusted=false:

  • NSEvent.addGlobalMonitorForEvents(matching: [.leftMouseDown, .rightMouseDown]) — fires ~20ms after the click; closing from it works.
  • DistributedNotificationCenter + com.apple.HIToolbox.beginMenuTrackingNotification — narrower, only on menu tracking.

With either, register when the popover opens and remove it in popoverDidClose (idle cost matters here), keep the returned token, and keep the isShown guard.

If you did see it close at runtime on your machine, let me know your macOS version — that would mean my repro diverges from the real app and I'd re-check before we settle on a mechanism.

Opening another menu bar popup does not deactivate the app, so
didResignActiveNotification never fires and the popover lingered.
Register an NSEvent global mouse monitor while the popover is open and
remove it in popoverDidClose (zero idle cost); keep the isShown guard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jjamming

Copy link
Copy Markdown
Contributor Author

@chattymin Thanks for the review. My last commit went out with only the code change and no local testing — and when I actually ran it, it failed exactly the way you described.

I've reworked it along the lines you suggested and confirmed it works locally (video attached).

Thanks again for taking a second look.

@jjamming
jjamming force-pushed the fix/close-popover-on-other-menu-bar-popup branch from df92dc3 to b447c8c Compare August 13, 2026 02:47
@chattymin
chattymin merged commit 2577c7a into chattymin:main Aug 15, 2026
2 checks passed
@chattymin

Copy link
Copy Markdown
Owner

Thank you for your contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants