Skip to content

Fix "Unable to display menu bar items" on macOS 26.4#922

Open
heyalchang wants to merge 1 commit into
jordanbaird:macos-26from
heyalchang:fix/displayID-fallback-26.4
Open

Fix "Unable to display menu bar items" on macOS 26.4#922
heyalchang wants to merge 1 commit into
jordanbaird:macos-26from
heyalchang:fix/displayID-fallback-26.4

Conversation

@heyalchang
Copy link
Copy Markdown

Fixes the empty Menu Bar Layout pane on macOS 26.4 / 26.4.1. Likely fixes #913 and #916, possibly #891 and #921.

On macOS 26.4.1 (build 25E253), CGSCopyActiveMenuBarDisplayIdentifier returns nil. That cascades:

  1. Bridging.getActiveMenuBarDisplayID() returns nil
  2. MenuBarItemManager.ItemCache.displayID stays nil after cacheItemsRegardless
  3. MenuBarItemImageCache.updateCacheWithoutChecks bails on its guard let displayID check (silently, no log)
  4. cacheFailed(for:) returns true for every section because items were cached but no images
  5. The Layout pane renders "Unable to display menu bar items"

Items themselves enumerate fine (20 items in my case) and cacheItemsRegardless reaches Updated menu bar item cache -- only the displayID is nil.

This PR adds a CGMainDisplayID() fallback in getActiveMenuBarDisplayID. Verified on a single-display setup running 26.4.1; the layout pane populates correctly. Multi-display configurations with the menu bar on a non-main display may need a richer fallback (for example, the NSScreen whose frame intersects the menu-bar window's frame), but CGMainDisplayID() is strictly better than nil in every case.

Test plan

  • Build macos-26 clean on macOS 26.4.1, observe the empty Layout pane
  • Apply the patch, rebuild, observe the populated Layout pane
  • Multi-display config -- not tested

macOS 26.4.1 (Tahoe, build 25E253) appears to have changed the
behavior of the private SkyLight function
CGSCopyActiveMenuBarDisplayIdentifier so that it now returns nil.
This cascades through the cache pipeline:

  Bridging.getActiveMenuBarDisplayID() returns nil
  MenuBarItemManager.ItemCache.displayID stays nil
  MenuBarItemImageCache.updateCacheWithoutChecks bails on its
    `guard let displayID` check (silently, no log)
  cacheFailed(for:) returns true (items are cached but no images)
  Layout pane renders "Unable to display menu bar items"

Same source builds and works on macOS 26.3.1, where the SkyLight
call still returns a valid identifier.

Fix: when the SkyLight call returns nil (or the UUID-to-displayID
lookup fails), fall back to CGMainDisplayID(). Correct for
single-display setups, which is the common case. Multi-display
configurations with an active menu bar on a non-main display may
need a richer fallback (for example, the NSScreen whose frame
intersects the menu-bar window's frame).
emindeniz99 pushed a commit to emindeniz99/Ice that referenced this pull request Apr 18, 2026
Ice's macos-26 branch left several critical issues that prevent the app
from working correctly on Tahoe, especially 26.3+ / 26.4+. This change
folds in the fixes from the three community PRs that address them (jordanbaird#903,
jordanbaird#911, jordanbaird#922) and the cache-thrash guard from jordanbaird#874.

Changes:

* `Bridging.getActiveMenuBarDisplayID()` falls back to `CGMainDisplayID()`
  when `CGSCopyActiveMenuBarDisplayIdentifier` returns nil, which is now
  the case on macOS 26.4.1. Without the fallback, the item cache's
  `displayID` stayed `nil` and the layout preview rendered as "Unable to
  display menu bar items" even though items existed.

* `MenuBarItemTag.Namespace` on macOS 26 recognizes Ice's own control
  items by window title ("Ice.ControlItem.*") and falls back to the
  owning application's identifiers when the owner isn't Control Center.
  This stops the UUID-namespace feedback loop that left the layout stuck
  on "Loading menu bar items..." after Control Center re-parented Ice's
  status items.

* `SourcePIDCache` caches failed AX lookups for 30 seconds, and the item
  manager no longer invalidates the window-ID cache when `sourcePID` is
  nil. Those two together stopped the thrash where each failed lookup
  triggered another full scan, racing with `IceBarPanel.show()` and
  causing clicks to drop roughly half the time on notched Macs.

* `AXHelpers.menuBarElement(nearDisplayOrigin:)` probes several inset
  points along the leftmost menu bar region instead of hit-testing the
  exact display corner. Single-point probing fails on notched displays
  (outside the rounded-corner mask), next to menu bar accessories such
  as NotchNook, and on Tahoe's translucent menu bar.
  `getApplicationMenuFrame()` and `hasValidMenuBar(in:for:)` both use
  the new helper.

* `MenuBarItemImageCache.compositeCapture` falls back to `item.bounds`
  when `CGSGetScreenRectForWindow` fails and tolerates a one-pixel
  discrepancy in the composite width. This keeps items that Control
  Center has re-parented from being dropped entirely.

* XPC `.isFromSameTeam()` requirement is only applied when the current
  process actually has a team identifier. Ad-hoc signed builds (the
  default when no signing team is configured) do not, and the old
  requirement refused every peer, leaving the `MenuBarItemService`
  unusable. A new `CodeSignInfo` helper inspects the process's code
  signature.

* The settings detail pane is keyed by the current navigation
  identifier on macOS 26 so that `NavigationSplitView` reliably updates
  on the first sidebar click.
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