Skip to content

feat(runtime): let a secondary window paint chrome, and add fullscreen - #455

Closed
phall1 wants to merge 1 commit into
vercel-labs:mainfrom
phall1:upstream/secondary-window-chrome
Closed

phall1 wants to merge 1 commit into
vercel-labs:mainfrom
phall1:upstream/secondary-window-chrome

Conversation

@phall1

@phall1 phall1 commented Sep 19, 2026

Copy link
Copy Markdown

Secondary windows could not paint their own chrome, and there was no fullscreen verb. Both are needed for a multi-window app that is not just a webview.

…creen verb

Two things a multi-window terminal app cannot do without.

=== A SECONDARY WINDOW CAN PAINT ITS TERMINALS ===

`rebuild` runs the app's `chrome.build` through `installChromeDisplayList`
— the path that produces every terminal cell. `rebuildWindowSlot`, the
secondary-window path, instead published the widget layout and emitted
with `WithChrome(.{})`: a chrome prefix of ZERO. So a second window
opened, laid out correctly, drew its tab strip, its split divider and
its widget bounds, and painted no cells at all. `ChromeOptions.build`
also took no window label, so even reaching it could not have helped —
it could not know which window it was painting.

- `ChromeOptions.build_window` is the per-window builder, taking a
  `ChromeContext` (canvas label, window id, that window's size, tokens,
  is_main). A struct rather than more parameters so the next thing a
  window needs to know does not break every caller again.
- `installChromeDisplayList` is parameterized by window — label, size,
  and the tree-currency flag — instead of reading the main canvas's.
- `rebuildWindowSlot` takes that branch, and so do per-window terminal
  sizing (`applyTerminalLayout`) and web panes, which were also
  main-canvas-only.
- `handleWindowSlotFrame` calls `on_frame` with the slot's own
  `gpuSurfaceFrame`, so each window has a viewport/PTY pump.

ADDITIVE: `build` is untouched and still works. The slot path is gated
on `build_window` being set, not merely on `chrome` — a builder that
cannot name a window would paint the MAIN window's content into a
secondary one, which is a different wrong answer, not a fix. An app that
does not migrate sees no change. Migration is one line:

    .build = view.buildChrome,
    // becomes
    .build_window = myBuildWindowChrome,   // (model, builder, context)

Verified by running it: a scratch `windows_fn`/`window_view` spike in the
consuming app, built against this commit, opened a second window and
BOTH windows painted live zsh prompts simultaneously — read from the two
automation screenshots. The spike was reverted.

Also fixed on the way: the install path re-emitted with a zero chrome
prefix right after `rebuildWindowSlot`, which would have erased the
chrome it had just installed.

=== THE FULLSCREEN VERB ===

`PlatformServices` had focus/close/minimize/show and no way to enter or
leave fullscreen, so an app could be told it was fullscreen and never ask
to be. Worse, `WindowState.fullscreen` existed but nothing ever filled
it — even the window-state store persisted a constant false.

- `set_window_fullscreen_fn` on `PlatformServices`, `Runtime.setWindowFullscreen`,
  `Effects.setWindowFullscreen(label, bool)` and `toggleFullscreenWindow`.
  SET rather than toggle so the call is idempotent and an app can restore
  a remembered layout without computing parity; macOS compares the style
  mask and only calls `toggleFullScreen:` when it differs.
- The READ half now exists: `WindowInfo.fullscreen`, filled from the
  window's style mask on every macOS frame emit, so a transition the USER
  started from the green button reports exactly like one the app asked
  for. `WindowInfo.state()` finally carries it into `WindowState`.

Chose (a) over (b), deliberately. (b) — appending the stock Enter Full
Screen item when an app supplies custom menus — is a real bug, but the
fix changes "you supplied a menu bar" from "you own it" to "you own it
plus items we inject", which is the wrong default for a framework whose
doctrine is explicitness, and it leaves an app still unable to drive
fullscreen from anything but a menu item it does not control. With (a)
in place a custom-menu app binds its own item in one line, and the
capability also serves shortcuts, buttons, and launch-state restore. (b)
remains worth doing as an opt-outable documented policy; it is not this
commit.

Suite: 2979 pass / 14 skip / 2993 total.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 19, 2026

Copy link
Copy Markdown

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

A member of the Team first needs to authorize it.

@phall1

phall1 commented Sep 20, 2026

Copy link
Copy Markdown
Author

This is larger than a focused patch. Closing; will reopen once it's smaller or split.

@phall1 phall1 closed this Sep 20, 2026
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