Skip to content

fix: NSSwitch and NSSlider bezels draw under the macOS 26 design, where displayRectIgnoringOpacity left them empty - #126

Merged
sidorares merged 1 commit into
mainfrom
fix/bezel-view-controls-macos26
Oct 21, 2026
Merged

sidorares merged 1 commit into
mainfrom
fix/bezel-view-controls-macos26

Conversation

@sidorares

Copy link
Copy Markdown
Contributor

Problem

A process linked against the macOS 26 SDK gets AppKit's new control design. Bun 1.4.3 is (SDK 26.5); Node 24 is not (SDK 15). Under the new design, NSSwitch and NSSlider draw through their layers, and displayRectIgnoringOpacity:inContext: into a foreign context draws nothing. react-x11's native <Switch> and <Slider> were invisible under Bun, though they still took clicks and drags. Cell-based kinds (push, checkbox, radio, popup) were unaffected because they draw with drawWithFrame:.

A standalone check built against each SDK, measuring ink pixels:

SDK 15 SDK 26.5
displayRectIgnoringOpacity (switch) 2938 0
cacheDisplayInRect:toBitmapImageRep: (switch) 2942 4760

Fix

Both draw paths (drawControlIntoSurface in backend.mm and the legacy drawControl in addon.mm) now capture a view control with cacheDisplayInRect: into a bitmap rep at the surface's pixel size, then draw that rep into the context.

Verified

  • test/control-bezels.js gains an "every kind draws ink" check, light and dark. Under Bun it fails for slider and switch before the fix and passes after.
  • Under Node (old design), slider and switch pixels are byte-identical to the 0.30.0 prebuild (max channel diff 0, light and dark).
  • test/threaded-verbs.js passes under Node and Bun.
  • react-x11's examples/fonts.jsx under Bun with this build shows its switches and sliders.

Not in this PR

Under Bun, control-bezels.js still fails its existing push-vs-flexiblePush checks ("one line is one push tall", then a buffer-bounds throw). The macOS 26 push bezel has different geometry, so those expectations assume the old design. That's a separate gap, and CI on an SDK-15 Node never sees it.

🤖 Generated with Claude Code

…re displayRectIgnoringOpacity left them empty

A process linked against the macOS 26 SDK (Bun 1.4 is) gets the new
control design, in which NSSwitch and NSSlider draw through their layers.
displayRectIgnoringOpacity:inContext: into a foreign context then draws
nothing, so react-x11's native <Switch> and <Slider> were invisible while
still taking clicks and drags. Both draw paths (drawControlIntoSurface and
the legacy drawControl) now capture the view with cacheDisplayInRect: into
a bitmap rep of the surface's size, which renders the layer tree; on the
older design the pixels are byte-identical to before.

control-bezels.js now checks every kind inks its frame in both appearances.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@sidorares
sidorares merged commit b5ef662 into main Oct 21, 2026
4 checks passed
@sidorares
sidorares deleted the fix/bezel-view-controls-macos26 branch October 21, 2026 03:31
sidorares added a commit to sidorares/react-x11 that referenced this pull request Oct 21, 2026
…gn, on @windowkit/appkit 0.30.1 (#979)

A process linked against the macOS 26 SDK — Bun 1.4 is, Node 24 is not —
gets AppKit's new control design, where NSSwitch and NSSlider draw through
their layers and the bridge's offscreen capture came out empty: the
controls laid out, took clicks and drags, and showed no pixels.
@windowkit/appkit 0.30.1 (windowkit/appkit#126) captures them with
cacheDisplayInRect:, byte-identical on the older design.

Co-authored-by: Claude Opus 5.5 <[email protected]>
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