Skip to content

Skip chromium restart on headful display resize#262

Open
hiroTamada wants to merge 4 commits into
mainfrom
hypeship/headful-resize-no-restart
Open

Skip chromium restart on headful display resize#262
hiroTamada wants to merge 4 commits into
mainfrom
hypeship/headful-resize-no-restart

Conversation

@hiroTamada
Copy link
Copy Markdown
Contributor

@hiroTamada hiroTamada commented May 29, 2026

Summary

Headful PATCH /display previously restarted chromium after the
xrandr/Neko screen resize so chromium could re-apply --start-maximized
against the new X root. The restart costs ~9s and wipes browser-side
state (Emulation.* overrides, devtools sessions).

The restart turns out not to be load-bearing. Mutter reflows a window in
windowState=maximized (or fullscreen) onto the new root whenever the
X root resizes via xrandr/Neko. The server just has to make sure the
window is in that state.

This PR replaces the restart on the Xorg branch with a single
Browser.setWindowBounds{windowState:"maximized"} call via CDP. The
restart_chromium request field stays in the API schema for
compatibility but is now a no-op on the Xorg path. Existing callers
that hardcode restart_chromium=true (kraft.go, chromium_configure.go
in kernel/kernel) silently get the faster path.

The trap we avoid

The explicit-bounds form of setWindowBoundswindowState:"normal"
with {left, top, width, height} — is intentionally not used. Once
a window is in normal state, mutter stops auto-tracking RANDR events,
which silently breaks subsequent resizes. The new e2e test
headful_force_maximized_no_restart exercises this indirectly by going
normal → maximized via the helper and confirming reflow still works on
both up- and down-resize.

Changes

  • server/lib/cdpclient/cdpclient.goSetWindowBoundsMaximized(ctx).
    Idempotent: early-returns on maximized or fullscreen so kiosk
    windows aren't demoted.
  • server/cmd/api/api/display.go — Xorg branch: always call
    setWindowMaximizedViaCDP after a successful resize. The legacy
    restart branch is gone. restartChrome is no longer threaded into
    setResolutionXorgViaXrandr.
  • server/cmd/api/api/chromium_configure.go — drop the now-unused
    fifth argument from the setResolutionXorgViaXrandr call.
  • server/e2e/e2e_display_resize_window_test.go — new test exercising
    five scenarios: headless fast path, headful --start-maximized +
    neko, headful kiosk, kiosk with explicit restart_chromium=false,
    and force-maximized-via-CDP starting from normal state. Each
    subtest asserts X root, renderer screen.* and outer{Width,Height}
    convergence, WindowState preservation, and a stable windowId
    (proving no chromium restart).

The Xvfb-with-recordings branch in display.go is orthogonal (headless
chromium has no OS window) and still honours restart_chromium=true.

Numbers

subtest wall-clock before after windowId stable
headful_start_maximized ~35s 17s yes
headful_kiosk ~34s 17s yes
headful_kiosk_no_restart n/a 17s yes
headful_force_maximized_no_restart n/a 17s yes

Two resizes per scenario; ~17s saved per PATCH /display call against
the kernel/kernel callers that all hardcode restart_chromium=true
today.

Test plan

  • cd server && go vet ./...
  • cd server && go test ./lib/cdpclient/... ./cmd/api/... — unit
    tests for cdpclient and the api package
  • New TestDisplayResizeChromiumWindow — 5 subtests, all pass
    against an overlay image carrying this branch's kernel-images-api
  • Existing TestDisplayResolutionChange still passes against the
    modified server
  • Manual smoke against a metro VM to confirm the same behaviour on
    the unikernel runtime as in the docker e2e

🤖 Generated with Claude Code


Note

Medium Risk
Changes production headful display resize semantics and makes CDP failures block success; mitigated by xrandr correctness fix and extensive e2e tests, but behavior differs from the prior restart-based path.

Overview
Headful PATCH /display no longer restarts Chromium after an Xorg screen resize (Neko or xrandr). The Xorg path now re-asserts windowState=maximized via CDP (Browser.setWindowBounds), relying on Mutter to reflow maximized/fullscreen windows to the new X root. restart_chromium remains in the API but is ignored on this branch; CDP re-assert failure returns 500 so callers are not left with a resized root and a stuck window.

setResolutionXorgViaXrandr is fixed to target DUMMY0 (or KERNEL_IMAGES_XRANDR_OUTPUT) with --output / --size instead of commands that could exit 0 without changing resolution.

cdpclient.SetWindowBoundsMaximized is added (idempotent; does not demote fullscreen). New e2e TestDisplayResizeChromiumWindow checks X root, renderer size, stable windowId, and preserved window state across resizes for headless and headful scenarios.

Reviewed by Cursor Bugbot for commit 9f62371. Bugbot is set up for automated code reviews on this repo. Configure here.

hiroTamada and others added 2 commits May 29, 2026 19:19
Headful PATCH /display previously restarted chromium to re-apply
--start-maximized against the new X root. The restart costs ~9s and
also wipes browser-side state (Emulation.* overrides, devtools
sessions). It turns out the restart isn't load-bearing: mutter reflows
a window in windowState=maximized (or fullscreen) onto the new root
whenever the X root resizes via xrandr/Neko. The server just has to
make sure the window is in that state.

This replaces the restart on the Xorg branch of PatchDisplay with a
single Browser.setWindowBounds{windowState:"maximized"} call. The
helper is idempotent: it early-returns when the window is already
maximized or fullscreen, so kiosk windows stay in fullscreen. Callers
that still want the legacy restart can pass restart_chromium=true.

The explicit-bounds form of setWindowBounds (windowState:"normal" with
{left,top,width,height}) is intentionally NOT used: once a window is
in normal state mutter stops auto-tracking RANDR events, which would
silently break subsequent resizes.

New e2e test e2e_display_resize_window_test.go covers headless fast
path, --start-maximized + neko, kiosk + fullscreen, and a
force-maximized-via-CDP scenario. Each subtest asserts:
- X root reaches the requested size (xrandr Screen 0: current WxH)
- renderer screen.* and outer{Width,Height} converge
- CDP windowState is preserved across the resize
- CDP windowId is stable (proves no chromium restart)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Follow-up to the prior commit: remove the restart_chromium=true escape
hatch from the Xorg branch entirely. The CDP re-assert-maximized path
is strictly better (faster, preserves browser state, stable windowId)
and the e2e tests exercise it exclusively. Existing callers in
kernel/kernel (kraft.go, chromium_configure.go) hardcode
restart_chromium=true today and now transparently get the faster
behaviour.

The restart_chromium field stays in the request schema for API
compatibility. On the Xorg branch it is now a no-op. The Xvfb-with-
recordings branch (orthogonal — headless chromium has no OS window)
still honours the flag.

Also drop the unused restartChrome parameter from
setResolutionXorgViaXrandr and its one caller in chromium_configure.go.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@hiroTamada hiroTamada marked this pull request as ready for review May 29, 2026 19:56
After the legacy restart_chromium path was removed, two of the five
TestDisplayResizeChromiumWindow scenarios became strictly redundant:

  - headful_kiosk_no_restart: passes restart_chromium=false explicitly,
    but the field is a no-op on the Xorg branch — functionally
    identical to headful_kiosk.
  - headful_force_maximized_no_restart: forces windowState=maximized
    via CDP at baseline, then resizes. Was useful while investigating
    whether mutter's "maximized window reflows on RANDR" invariant
    holds; headful_start_maximized now covers the same hot path with
    production-equivalent CHROMIUM_FLAGS.

Both also flaked in CI when running later in a heavy e2e suite —
neko/mutter occasionally fails to apply its 1920x1080 desktop.screen
startup mode under load, leaving the X root at the dummy DDX's
3840x2160 default and breaking the resize assertions. Running them
locally or earlier in the suite passes consistently, so it's an
environmental flake, not a code regression.

Also remove the now-unused helpers setChromiumWindowStateCDP,
waitForWindowState, baselineOrForcedState, and the
forceMaximizeAtBaseline / restartChromium fields on resizeScenario.

The remaining three subtests cover every production path: headless
CDP fast path, headful --start-maximized + neko, headful kiosk +
fullscreen.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Comment thread server/e2e/e2e_display_resize_window_test.go
@firetiger-agent
Copy link
Copy Markdown

Monitoring Plan: Display Resize Skips Chromium Restart, Uses CDP Instead

What this PR does: Headful browser display resizes are now ~9 seconds faster and no longer wipe browser-side state (Emulation.* overrides, open devtools sessions). Instead of restarting Chromium after an xrandr resize, the server re-asserts the window's maximized state via a single CDP call — Mutter then automatically reflows the window to fill the new screen.

Intended effect:

  • CDP maximize re-assert success log: baseline 0 (new log message); confirmed if "re-asserted maximized window state via CDP" INFO appears post-deploy on headful resize calls
  • Chromium restart errors on resize: baseline 0 occurrences/7d; confirmed if "failed to restart chromium after resolution change" ERROR remains at 0 post-deploy on the headful path

Risks:

  • CDP maximize WARN burst"CDP maximize re-assert failed after Xorg resolution change (non-fatal)" WARN log; alert if any occurrences post-deploy (baseline: 0 — this message didn't exist pre-deploy)
  • Window not filling screen — if Mutter's reflow invariant fails or the CDP call silently errors, users see a clipped viewport; surface via the CDP maximize WARN log or customer reports
  • Kiosk mode disruptionSetWindowBoundsMaximized guards against demoting a fullscreen window; alert if kiosk sessions transition from fullscreen to maximized post-resize

Status updates will be posted automatically on this PR as monitoring progresses.

View monitor

Three follow-ups addressing review feedback:

1. xrandr targets DUMMY0 (or KERNEL_IMAGES_XRANDR_OUTPUT env override),
   not "default". The headful Xorg dummy driver does not expose a
   "default" output, so `xrandr --output default --mode ...` exits 0
   without applying anything. This affects only the non-Neko Xorg path
   (production runs with Neko enabled, which doesn't touch xrandr), but
   left the path silently broken.

2. CDP maximize re-assert failure is now fatal. Previously logged a
   warning and returned 200; if the window happened to be in normal
   state and the CDP call failed, the server returned success with the
   browser window stuck at the old size. Now the resize fails closed
   with a 500 so the caller sees the mismatch.

3. TestDisplayResizeChromiumWindow now asserts windowID stability and
   windowState preservation across both resizes. Previously logged but
   never asserted; a silent chromium restart regression would have
   slipped through.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 9f62371. Configure here.

log.Info("using specific modeline", "output", output, "mode", modeName)
} else {
xrandrCmd = fmt.Sprintf("xrandr -s %dx%d", width, height)
xrandrCmd = fmt.Sprintf("xrandr --output %s --size %dx%d", output, width, height)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Invalid xrandr --size used as per-output option

High Severity

The else branch (when refreshRate <= 0) constructs xrandr --output DUMMY0 --size WxH, but --size is a legacy RandR 1.0/1.1 global screen option (long form of -s), not a per-output option. Per-output resolution changes require --mode, not --size. Combining --output with --size is invalid and will either silently no-op or error. The refreshRate > 0 branch correctly uses --mode. The test comment at line 460 of e2e_display_resize_window_test.go still references the old working form (xrandr -s WxH), confirming the intent was a global size set, but the code was incorrectly rewritten to use --output with --size.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9f62371. Configure here.

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