Skip to content

Report the content size in the macOS window frame event - #286

Open
sepehr-safari wants to merge 1 commit into
vercel-labs:mainfrom
sepehr-safari:window-frame-reports-content-size
Open

Report the content size in the macOS window frame event#286
sepehr-safari wants to merge 1 commit into
vercel-labs:mainfrom
sepehr-safari:window-frame-reports-content-size

Conversation

@sepehr-safari

Copy link
Copy Markdown
Contributor

The bug

The runtime lays its shell views out into the width and height of the window
frame it is told about:

// src/runtime/window_storage.zig
pub fn shellBoundsForWindow(self: *const Runtime, window_id: platform.WindowId) geometry.RectF {
    const frame_value = self.windows[index].info.frame;
    const bounds = geometry.RectF.init(0, 0, frame_value.width, frame_value.height);

Windows are also created and restored through initWithContentRect:, so on every
other path those two numbers are a content size. The AppKit host reported
window.frame, which includes the chrome.

With a standard titlebar that is 32 points of disagreement.

What it looks like from an app

An app whose manifest asks for 760x760 gets a 760x760 content view, and is then
told its shell is 760x792. It lays out 32 points taller than the view it lives
in, so anything on the bottom edge is placed below the window.

Measured on a real app with a status bar on the floor of its canvas, five
launches out of five:

canvas the app is told status bar
before 760x792 y 761 to 792, entirely outside the 760pt content view
after 760x760 y 729 to 760, on the floor of it

CGWindowListCopyWindowInfo reports the window frame as 760x792 in both, so the
window itself was always the right size. Only the number the app was handed
changed.

It reads as intermittent, which is what made it confusing. The bar is absent from
every launch and then appears permanently the first time the window is resized,
because emitResizeForWindowId already sends contentView.bounds and is
correct. Whether anyone sees the bug depends only on whether they happened to
drag the window.

The fix

emitWindowFrameForWindowId reports contentRectForFrameRect: for the size. The
origin stays the frame's, which is what positions the window on screen and what
the restore path already round-trips.

What I tried first, and why it is not this

Making shellBoundsForWindow use self.surface.size instead. The surface does
carry the correct content size, but it is not populated until the host sends its
first resize, so at startup it is still the 640x360 default. That fails

test "runtime lays out startup shell windows with native configured bounds"
  expected 1200, found 640

which is the suite catching it exactly. The host is the right place: it is the
only layer that knows the chrome height, and every other window path there
already speaks in content rects.

Checks

zig build test on macOS produces the same result with this patch as without it.

The runtime lays its shell views out into the width and height of the
window frame it is told about (`shellBoundsForWindow`), and it creates
and restores windows through `initWithContentRect:`, so those two numbers
are a content size on every other path. The AppKit host reported
`window.frame`, which includes the chrome.

On a standard titlebar that is 32 points of disagreement. An app whose
manifest asks for 760x760 is created with a 760x760 content view, and
then told its shell is 760x792, so it lays out 32 points taller than the
view it lives in and anything on its bottom edge lands below the window.
A status bar disappears completely and comes back the first time the
window is resized, because the resize event carries `contentView.bounds`
and is correct.

The origin stays the frame's, which is what positions the window on
screen and what the restore path already round-trips.
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

@sepehr-safari is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

sepehr-safari added a commit to zig-nostr/plaza that referenced this pull request Aug 5, 2026
The toolkit reported the window's FRAME where the runtime wanted its
CONTENT size, so the canvas was 32 points taller than the view it lived
in and the status bar was laid out below the bottom edge. It was
invisible on every fresh launch and came back the first time anyone
dragged the window, which is why it read as intermittent rather than as
always broken.

Measured five launches each way. Before: canvas 760x792, status bar at y
761 to 792, entirely outside a 760pt content view. After: canvas 760x760,
status bar at y 729 to 760, on the floor of it. The window frame is
760x792 in both, so the window was always the right size; only the number
the app was handed changed.

The fix is one line in the toolkit's AppKit host and is reported upstream
as vercel-labs/native#286. Until that lands the dependency points at a
fork carrying exactly that commit on top of the same base this already
pinned, so the diff against upstream is one commit and moving back is a
one-line change.

The acceptance suite now measures it. No unit test can: the layout is
correct at whatever size it is handed, and the defect is which size that
is, so it only exists in a real window.

Closes #100.
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