Skip to content

fix(macos): emit the content rect for WINDOW_FRAME events#133

Open
iAmCorey wants to merge 1 commit into
vercel-labs:mainfrom
iAmCorey:fix/macos-window-frame-content-rect
Open

fix(macos): emit the content rect for WINDOW_FRAME events#133
iAmCorey wants to merge 1 commit into
vercel-labs:mainfrom
iAmCorey:fix/macos-window-frame-content-rect

Conversation

@iAmCorey

Copy link
Copy Markdown

Symptom

On a multi-display setup (built-in Retina + external monitor), dragging a window to the other display and back leaves the bottom of the canvas clipped — a UiApp's bottom status-bar disappears. Clicking another app and back (key-window change), or manually resizing, heals it. Single-display apps can also hit it intermittently.

Root cause

The macOS host's WINDOW_FRAME event carried window.frame — the outer frame, one titlebar (~32pt) taller than the content area. Everything else in the pipeline speaks content-rect:

  • windows are created with initWithContentRect:
  • the runtime's shellBoundsForWindow uses the event's size as the shell-view layout viewport (window_frame_changedrelayoutShellViews)
  • the window state store round-trips the saved frame back into initWithContentRect:

So every window_frame_changed relayouts shell views to the outer-frame height (the fill gpu_surface gets frame={{0,-32},{560,592}} inside a 560-tall contentView — bottom 32pt clipped), and every RESIZE event snaps them back to the content height. The two events fight continuously; whichever lands last wins. Instrumented log of an idle app:

updateDrawableSize changed scale=2.0 bounds={560, 560} frame={{0, 0}, {560, 560}}
updateDrawableSize changed scale=2.0 bounds={560, 592} frame={{0, -32}, {560, 592}}
updateDrawableSize changed scale=2.0 bounds={560, 560} frame={{0, 0}, {560, 560}}
... (oscillates every frame)

Dragging across displays reliably parks the war on the clipped side; a key-window change parks it on the correct side — which made the bug masquerade as a multi-display issue.

Separately, restore_state windows grow by one titlebar height per launch (outer frame saved, restored as a content rect).

Fix

  • emitWindowFrameForWindowId: now emits [window contentRectForFrameRect:window.frame], matching the content-rect semantics of window creation, shell layout, and state restore.
  • Add the missing windowDidChangeScreen: / windowDidChangeBackingProperties: delegate re-emits (mirroring windowDidBecomeKey:) so crossing displays refreshes geometry immediately instead of at the next key-window change.

Verification

Dual-display MacBook (built-in Retina @2x + external monitor): before, dragging across displays clipped the bottom 32pt of a zig-core UiApp's canvas; after, layout is stable across display moves, focus changes, and resizes, and the per-frame relayout oscillation is gone.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown

@iAmCorey is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

On macOS the WINDOW_FRAME event carried window.frame — the OUTER frame,
one titlebar taller than the content area. Everything else in the
pipeline speaks content-rect: windows are created with
initWithContentRect:, the runtime's shellBoundsForWindow uses the
event's size as the shell-view layout viewport, and the window state
store round-trips the saved frame back into initWithContentRect:.

Consequences of the mismatch:

- Shell views (e.g. a UiApp's fill gpu_surface) relayout to the outer
  frame's height on every window_frame_changed, then snap back to the
  content height on the next RESIZE event — the two events fight every
  frame, and whichever lands last wins. When WINDOW_FRAME wins, the
  canvas is laid out one titlebar taller than the content area and the
  bottom of the UI (status bars) renders clipped. Dragging the window
  to another display reliably parks the war on the clipped side;
  clicking another app and back parks it on the correct side, which
  made the bug look like a multi-display issue.
- restore_state windows grow by one titlebar height per launch (outer
  frame saved, restored as a content rect).

Emit [window contentRectForFrameRect:window.frame] instead, and add the
missing windowDidChangeScreen:/windowDidChangeBackingProperties:
delegate re-emits so crossing displays refreshes geometry immediately
rather than at the next key-window change.

Verified on a dual-display setup (built-in Retina + external monitor):
before, dragging across displays clipped the bottom 32pt of the canvas;
after, layout is stable across display moves, focus changes, and
resizes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@iAmCorey iAmCorey force-pushed the fix/macos-window-frame-content-rect branch from 2726790 to 03f8436 Compare July 15, 2026 07:02
// frame makes shell views a titlebar taller than the content area
// (clipping the bottom) and makes restored windows grow by one
// titlebar per launch.
NSRect frame = [window contentRectForFrameRect:window.frame];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On macOS, emitWindowFrameForWindowId: reports contentRectForFrameRect: (frame minus titlebar) which under-reports the height of NSWindowStyleMaskFullSizeContentView windows (titlebarStyle 1/2), so WINDOW_FRAME disagrees with the RESIZE event's contentView.bounds and reintroduces the shell-layout oscillation/bottom-clipping for hidden-inset windows.

Fix on Vercel

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