Skip to content

A menu bar icon macOS will not draw no longer quits the app - #124

Merged
PathGao merged 1 commit into
mainfrom
fix/a-blocked-menu-bar-icon-stops-quitting-the-app
Aug 31, 2026
Merged

A menu bar icon macOS will not draw no longer quits the app#124
PathGao merged 1 commit into
mainfrom
fix/a-blocked-menu-bar-icon-stops-quitting-the-app

Conversation

@PathGao

@PathGao PathGao commented Aug 31, 2026

Copy link
Copy Markdown
Owner

What this is

Double-clicking Nifro did nothing, and the menu bar icon was missing. Both are one thing: the app quit itself about 180ms into launch, cleanly, with no crash report and no message.

The app now stays running when macOS will not draw its icon.

Mechanism

statusItem.behavior was [.removalAllowed, .terminationOnRemoval]. That reads as "dragging the icon out of the menu bar quits the app", and it is also how macOS refusing to place the icon is delivered — AppKit gives both the same removal, with nothing to tell them apart.

macOS 26 does not grant menu bar permission per app. It grants it per responsible process, and records it in trackedApplications in group.com.apple.controlcenter:

host = com.openai.codex          isAllowed = false
  ├─ com.openai.codex
  ├─ com.openai.sky.CUAService
  ├─ com.cmuxterm.app
  └─ com.pathgao.nifro           ← a build launched once by that app

host = com.pathgao.nifro         isAllowed = true      ← what System Settings shows

A bundle id listed under any denied host is blocked no matter who launches it afterwards, and the app's own allowed entry does not override it. So System Settings said the icon was set to show while ControlCenter refused it on every launch:

appStatusItems  Host properties initialized; (bid:com.pathgao.nifro-Item-0)
                State(applicationItem: true, clientRequestsVisibility: true)
appStatusItems  Moving host to blocked list; (bid:com.pathgao.nifro-Item-0)
appStatusItems  Requesting blocked host to not be visible
AppKit          Received action(s): NSStatusItemChangeVisibilityAction
AppKit          terminate:

The permission is a system record, not app state: it survives reinstalling, rebuilding, resigning and changing the bundle's path, and it is cleared only from group.com.apple.controlcenter. Nothing in the app can see it, and there is no API that separates "the user dragged the icon away" from "the system will not place it".

Scope

behavior is now [] rather than dropping only .terminationOnRemoval. Keeping .removalAllowed alone would leave an icon the user can drag away from an app that no longer quits — an app with no interface and no way back, which is worse than either half. Quit is in the panel footer, and Hide menu bar icon is the setting for an icon somebody does not want, so nothing the removal gesture offered is lost.

Considered and not done: quitting only when the removal arrives after launch, on the theory that an early one is the system and a late one is the user. AppKit reports the same action either way, so the rule would be a timer standing in for a signal that does not exist, and it would still quit the app when the system revokes the permission while it runs.

Also not done: telling the user why the icon is missing. Reaching them needs a window, and the case that produces this is rare enough that a window on launch is the wrong trade. Worth reconsidering if it turns up again.

The system-side record is not the app's to write, and this change does not try to.

Verification

swift test: 221 tests in 49 suites, all passing.

By hand, macOS 26.6.2 (25G83) on a Mac17,3, two displays, signed via Tools/build-local.sh:

  • With the permission still denied, the built app launches and stays running instead of quitting. The icon is still absent — that is the system record, not this change — and Settings and the Shortcuts intents stay reachable, which is the whole of what the fix buys.
  • With the permission cleared, the icon appears and the app behaves as before: panel opens on click, appearsDisabled and the loading pulse both still track the scenes.
  • Confirmed the cause is not this repo: a build from before A toggle that could not work is gone #105 fails identically, and the same binary resigned with a different bundle identifier is never blocked.

`statusItem.behavior` was `[.removalAllowed, .terminationOnRemoval]`, which
reads as "dragging the icon out quits the app" and is also how macOS refusing
to place the icon arrives. AppKit delivers both as the same removal, so a
refusal quit the app about 180ms into launch, before any window, with no crash
and nothing said. Double-clicking the app then did nothing at all.

The refusal has nothing to do with the user. macOS 26 files a menu bar item
under the process that launched it, so a build started once by another app
inherits that app's menu bar permission for good, and a denied one leaves
Nifro unlaunchable with no way to find out why.

`.removalAllowed` goes with it: an icon the user can drag away from an app
that no longer quits is an app with no interface and no way back. Quit is in
the panel footer, and Hide menu bar icon is the setting for an icon somebody
does not want.
@PathGao
PathGao merged commit ad486fd into main Aug 31, 2026
0 of 5 checks passed
@PathGao
PathGao deleted the fix/a-blocked-menu-bar-icon-stops-quitting-the-app branch August 31, 2026 13:46
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.

1 participant