Skip to content

macOS 27 support: remaining gaps on top of #995 - #1001

Open
carlossantos74 wants to merge 179 commits into
jordanbaird:mainfrom
carlossantos74:macos-27-support
Open

carlossantos74 wants to merge 179 commits into
jordanbaird:mainfrom
carlossantos74:macos-27-support

Conversation

@carlossantos74

Copy link
Copy Markdown

This branch builds on #995 (by @RabenkoYevhenii), which itself targets macos-26. Against main, the diff therefore also carries the unmerged macos-26 work and every commit of #995: 129 commits in total. Only the last 10 are new here (5f68632…73731e4). If you would rather review just those, they apply cleanly on top of #995's head (6b6fca3).

New in this PR

  • Search panel: clicking a hidden item now goes through ItemClicker27, as the Ice Bar does. Before, it fell through to temporarilyShow, which drags the item and is ignored on 27. move() and temporarilyShow() now refuse to run on 27 instead of posting events that go nowhere.
  • Layout window: system items, and items without a bundle identifier, are disabled, with a tooltip. Dragging them used to do nothing, silently.
  • Settings: on 27, the divider style, hiding application menus and the temporary show interval are hidden. None of them has any effect there.
  • Missing MenuBarClientCore: the layout window now shows a warning. Before, the failure only went to the log.
  • System items: the assertion allows numbers 0–63 instead of 0–8, so items added by a later macOS are not hidden. Measured on 27.0: numbers with no item behind them are ignored.
  • Menu bar appearance:
    • The wallpaper window belongs to WindowManager on 27, not the Dock (measured), so it was never found.
    • The split shape now measures from the leftmost drawn item, and redraws when the items are read again.
  • Second display: hover and click on the inactive display now use the frames from MenuBarAgent's window there. Before, they used a left edge remembered from when that display was last active.
  • Notch stuck overflow: StuckOverflow27 (unit tested) recognises the state, and Ice only logs it. An automatic nudge was tried and removed: stale Accessibility frames can trigger false positives, and it was never shown to unfold anything.
  • The Ice Bar timing log is now at debug level.

Testing

  • swift test: 108 tests pass, 7 of them new for StuckOverflow27.
  • The app builds with Xcode 27.
  • Checked on macOS 27.0 (26A428) on a notched MacBook:
    • the wallpaper window owner;
    • the 0–63 system item range;
    • the 2 pt overlap between neighbouring items, which sets the stuck-overflow tolerance.
  • Not verified:
    • the second-display hit-testing (only one display was available);
    • whether the stuck-overflow check fires correctly in the real stuck state, which did not reproduce.

Known issue (not addressed)

With Ice's section-hiding assertion active, MenuBarAgent removes Ice's own control item on this machine, so there is no item to click to show the hidden sections again. Screenshots confirmed:

  • It happens with both Apple Development and (unnotarized) Developer ID signing.
  • Allowing com.jordanbaird.Ice from a separate process does not bring Ice's item back, while it does for other apps (for example com.zscaler.zscaler).
  • Allowing the item names Ice.ControlItem.* does not bring it back either.

Notarization is the remaining untested difference.

🤖 Generated with Claude Code

Misc additional changes and cleanup
`RunLoopLocalEventMonitor` seems to prevent certain buttons from receiving events in macOS 26 Developer Beta 1. This might be a bug in the beta, or `RunLoopLocalEventMonitor` itself. For now, let's just move to a better mouse check implementation that doesn't use continuous event monitoring.

Note the `FIXME` (line 1057). The previous implementation had this problem too, but it was never documented.
A big part of this is hopefully a temporary measure. We need an accurate identifier for every item, and the old way just isn't cutting it right now. Items are all owned by the Control Center in macOS 26, and try as I might, I couldn't find a great way to get the _actual_ host apps for the items.

Must dig deeper into the mines...

Oh yeah, there's also a bunch of random stuff here too that I don't really want to explain. Just know that it probably all fixed something.
This is what I get for trusting Xcode to update my build settings
- Refactor screen capture
- Rework menu bar item getters
- Update immovable/non-hideable info lists
- Remove OSLog wrapper
- Minor migration rework
- Remove old entitlements file
Should also fix a crash when accessing `ControlItem.windowNumber`.
- Rework app lifecycle
- Rework how windows are initialized
- Update documentation comments
- Refactoring and cleanup
This should fix some performance issues that occur during mouse tracking operations (e.g. highlighting a button on hover).
We also store the status item and layout constraint in a separate storage class. Not sure I like this, but the idea is to convey the tightly coupled relationship between the constraint and status item, and to ensure that they are initialized (and deinitialized) at the same time.
Relying on the default behavior seemed to work fine, but is now broken in the macOS 26 Developer Beta. Probably better to handle it explicitly, even if it is just a beta bug.
carlossantos74 and others added 19 commits September 26, 2026 17:32
The hover delay, temporary show interval, and rehide interval were saved
to user defaults on every step of their sliders. Debounce saving them,
while the settings themselves still change immediately.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Read the items after launches and quits (and again 5 s later, for apps
that add their item once started) with a 30 s safety-net sweep, and
cache the items cacheItemsIfNeeded just read instead of reading again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On macOS 27 each capture redrew, premultiplied and PNG-encoded every
tile on the main actor, then rewrote every file and the index. The
pixel work and encoding now run detached, glyphs whose pixels match
the stored ones are left alone, the index is written only when one
changed, the ScreenCaptureKit display is reused between captures, and
the periodic image update runs every 10 s instead of 3 s.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A capture that never returns held up every task queued behind it, and
each throttled tick added another. Ticks that arrive during an update
now coalesce into a single follow-up update.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The index now notes when each item was last on the bar, at most once a
day, and a capture drops the images, files and entries of items gone
for 30 days. They were only ever cleared on an appearance change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The cancellation handler of postEventWithBarrier and scrombleEvent sat
in an unstructured task that the timeout never cancelled, so the wait
never ended, the event taps stayed enabled and the timeout's task group
waited on it for good. The handler now wraps the continuation, which is
resumed once whichever of the taps or the cancellation comes first, and
the taps are disabled however the wait ends.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The loop read the item's bounds back to back, each through a detached
task of its own, spinning a core for the whole wait.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The wait resumed only when the app terminated, so an app that survived
the force quit left the spacing change waiting for good. It now gives
up with an error 5 s after the force quit, resuming exactly once and
without depending on the manager staying alive.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each update queued its apply behind the previous one, so a burst of
updates laid the bar out once per update, and each queued its own read
of every application's items afterwards. An apply, and the refresh
after it, now only runs if no later update came in; releases are never
skipped, so the order of applies and releases holds.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
sourceApplication creates an NSRunningApplication on every access, and
the saved-layout cache and the missing-photo pass asked it for every
item on the bar. They now look each process up once.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… cancellation

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RabenkoYevhenii added a commit to RabenkoYevhenii/Ice that referenced this pull request Oct 1, 2026
macOS folds what does not fit beside the notch on the built-in display. Ice
then conceals the hidden applications, the room comes back, and the fold is
never reconsidered: the "«" that reaches the folded items disappears with the
items still behind it, and they are gone until something lays the bar out
again.

Seen twice here, on 2026-09-29 and 2026-10-01, both times after Ice started
with the bar already crowded. Measured against the live state: neither
`Scripts/macos27/reflow-probe.swift` in either mode nor restarting Ice unfolds
anything, while relaunching the application whose item is missing restores it
within seconds. An item created by an application without a Developer ID is
not drawn at all while an assertion is live, so Ice cannot nudge the layout
with one of its own.

The Menu Bar Layout pane now says so, and says what cures it, rather than
leaving the user to wonder where their items went. Ice does not relaunch
anything by itself: Accessibility keeps reporting the frames of items it no
longer draws, so which application is missing cannot be read off them, and
quitting the wrong one is not a mistake worth making.

`StuckOverflow27` and its tests are taken as they are from @carlossantos74's
jordanbaird#1001, which recognises the same state.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
RabenkoYevhenii added a commit to RabenkoYevhenii/Ice that referenced this pull request Oct 1, 2026
Both branches widened the allowlist past the numbers macOS 27.0 draws, one to
31 and the other to 63. Nothing answers to either, so the difference is only a
difference; matching @carlossantos74's range keeps the two from colliding when
they meet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
RabenkoYevhenii added a commit to RabenkoYevhenii/Ice that referenced this pull request Oct 1, 2026
Names the new build, its commit and its checksum. Adds the step that keeps it
installed: Ice updates itself through Sparkle, and the newest official release
is the one that does not work on macOS 27, so it would quietly replace this
build with a broken one (pointed out by @Theralley on jordanbaird#1006).

Also corrects what the hiding spares: a Developer ID signature is not enough on
its own. @carlossantos74 measured on jordanbaird#1001 that an unnotarized
Developer ID build loses its own item exactly as this one does.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@RabenkoYevhenii

Copy link
Copy Markdown

The stuck notched bar turned up live on this machine twice this week — 2026-09-29 and 2026-10-01 — so here is what it does, against the "did not reproduce" note.

Both times the built-in bar was missing three Stats modules and the input menu, with no "«" anywhere, while the external bar drew all of them. Measured on that state:

  • Scripts/macos27/reflow-probe.swift in both modes (add-remove, resize) changed nothing.
  • Quitting Ice did not unfold them either. With Ice down the bar showed "«" again and kept the same items behind it, and concealing freed the room once more without a reflow.
  • Relaunching the application whose items were missing restored them within seconds, on both displays at once (killall TextInputMenuAgent for the input menu — launchd brings it straight back).

So dropping the automatic nudge looks right, and for one more reason than the one you gave: an item created by anything not signed with a Developer ID is not drawn at all while an assertion is live, so a status item added as a nudge is never laid out. The probe could not have worked from an unsigned helper in the first place, whatever the state of the bar. Whether a notarized build can nudge it is still untested here.

I took StuckOverflow27 and its tests as they are, and show the state in the Menu Bar Layout pane with what cures it. Ice does not relaunch anything itself: the frames macOS keeps for items it no longer draws do not say which application is missing, and quitting the wrong one is not a mistake worth making.

I also matched your 0–63 system item range. I had arrived at 0–31 independently, with the same measurement behind it: holding an assertion with one number at a time, every number from 0 to 127 is accepted and only four draw anything — 0 battery, 2 clock, 6 Wi-Fi, 8 Control Centre.

One finding from that measurement that is worth knowing before someone files it as a bug: Control Centre's capture indicator — AudioVideoModule, the green camera button, orange for the microphone, indigo for screen sharing — is not one of those numbered system items, and any live assertion removes it, whatever the allowlist holds: all 128 numbers, com.apple.controlcenter, the capturing application's own bundle identifier. It returns the moment the last assertion goes. The small green dot beside the clock is not an item and stays throughout.

@RabenkoYevhenii

Copy link
Copy Markdown

Follow-up on StuckOverflow27, now with the trigger in hand: plugging a display into a MacBook. With Ice quit, unplug the second display and plug it back in, and the built-in bar is left with the four system items and nothing else — so the state is macOS's, not ours, and it reproduces on demand.

Two things that matter for the check:

  • Geometry cannot see this one. The items are not folded behind a "«" that has gone; they are not drawn anywhere, so nothing sits under the notch or on top of a neighbour.
  • The applications' frames cannot either. A missing item keeps the frame it last had and still reads as drawn — all five reported frames on the built-in display while that bar drew one.

What does show it is MenuBarAgent's own window for each display. It lists every item that belongs to that bar: with a frame on the display where the item is drawn, and as an entry with no geometry at all on the other one. An item folded away is listed by neither, so "a notched bar lists fewer items than another display does" catches it, and the count follows each repair.

I kept your StuckOverflow27 file and its tests and added the counting there; the wiring is in Concealer27 on #995 (63036af), along with a check on display changes and a Relaunch button per application in the layout pane — Ice does not relaunch anything by itself, since the bar does not say whose item is missing.

holzcloud pushed a commit to holzcloud/holzBar that referenced this pull request Oct 2, 2026
- SystemItems27 (Core) holds the drawn numbers, the highest measured number
  (127) and the allowlist derived from them, 0 through 127
- MenuBarAssessmentAssertion27 builds its configuration from
  SystemItems27.allowed; its comment now says what the code does and how
  jordanbaird/Ice#1001's 0 to 63 relates, instead of claiming they match (BUG-08)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BSzFQk1ZzGXFVBDZMYq8eu
holzcloud pushed a commit to holzcloud/holzBar that referenced this pull request Oct 3, 2026
…t from under the notch

- MenuBarItemProvider27 keeps every frame MenuBarAgent draws on displays whose
  bar is not active; ItemHitTest27 counts them (tested), so hover, click and
  the context menu leave items on the second display alone (Thaw #1159,
  #1138, #1137; jordanbaird/Ice#1001)
- NotchCover27 (tested): while holzBar's icon lies under the notch, the
  nearest visible app right of it is concealed for the moment, one per read,
  never in the saved layout; cleared on display changes and app launches
- When the bar moves to a roomier display with items folded, concealment is
  released and applied again once (Thaw #1106)
- A click on the overflow button is bridged like the clock (Thaw #1195)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BSzFQk1ZzGXFVBDZMYq8eu
holzcloud pushed a commit to holzcloud/holzBar that referenced this pull request Oct 3, 2026
…ock click, unsquashed launching apps

- DesktopPicture reads the desktop picture from its file (ImageIO thumbnail
  off the main thread, laid out like the desktop) for the wallpaper beside a
  menu bar shape; no capture and no Screen Recording. Only a moving wallpaper
  before macOS 27 falls back to the capture (and its 30 s refresh); on
  macOS 27 the shape stands on the flat colour
- WallpaperChangeMonitor (adapted from Thaw, credited in NOTICE) notices a new
  wallpaper from the wallpaper store's index instead of a timer
- The search uses the flat colour on macOS 27; the wallpaper window is found
  under WindowManager too (jordanbaird/Ice#1001)
- ClockCover27 covers the concealed part of the bar while a clock click lifts
  concealment, so hidden items no longer flash (Thaw #1181)
- LaunchGrace27 (tested): an app launching into a concealed section is shown
  until its item exists (at most 10 s), then concealed, so its item is not
  squashed to 3 points (jordanbaird/Ice#1007)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BSzFQk1ZzGXFVBDZMYq8eu
holzcloud pushed a commit to holzcloud/holzBar that referenced this pull request Oct 3, 2026
- A hidden item opened from the search goes through ItemClicker27, as in the
  Shelf
- Items without a bundle identifier are disabled in the Layout pane with a
  tooltip; system items that cannot be hidden say so
- Settings that do nothing on macOS 27 are not shown there; their values stay
- holzBar's icon is put back when MenuBarAgent dropped it while concealing
  (two reads in a row, once per concealment change)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BSzFQk1ZzGXFVBDZMYq8eu
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.

3 participants