Repository navigation
Keep the headful window maximized while the session runs - #506
Draft
robertjamesprior wants to merge 2 commits into
Draft
robertjamesprior wants to merge 2 commits into
robertjamesprior wants to merge 2 commits into
Conversation
Replaces the five-second reconcile poll with a watch on the window's _NET_WM_STATE property, which the window manager rewrites the moment the window leaves or re-enters the maximized state. A correction happens as the demotion does rather than up to an interval later, and a session whose window never moves costs nothing: no timer, no devtools connection, no round trips. Caps corrections at three per browser start. One correction covers what this guard is for, a window that leaves maximized once and stays there. Repeated demotions are a client that wants a window that size, and past the budget it keeps it, rather than being fought for the life of the session by something it cannot see or turn off. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Keeps a headful window covering the display after the promotion that runs on browser start, by watching the window state rather than polling it, and bounds how long it will argue with a client that wants a smaller window.
Why
Promotion restores the maximized contract once per chromium start. It does not cover what happens next: a CDP
Browser.setWindowBoundsover the proxy, the same command inside the playwright executor, a window manager restore, or a geometry a saved profile carries into the restart and applies after the promotion has already run. None of those are distinguishable from the window state itself, so the guard acts on the state.How it watches
xprop -spyon the window's_NET_WM_STATE. Openbox rewrites that property the moment the window leaves or re-enters maximized, so a correction happens as the demotion does instead of up to an interval later, and a session whose window never moves costs nothing — no timer, no devtools connection, no round trips. The earlier revision of this PR polled the state every 5s on a held connection for the life of every headful session.The X atoms are the trigger; CDP is still what decides. A reported change dials the browser, reads the bounds, and acts only on a window that is neither maximized nor fullscreen, so kiosk sessions are untouched and a change that was already corrected costs nothing. A window manager that does not maintain the EWMH atoms simply never triggers the guard; promotion on start is what guarantees the window starts covered.
The budget
Three corrections per browser start. One covers the case this exists for: a window that leaves maximized once and stays there for the rest of the session. Repeated demotions are a client that wants a window that size, and past the budget it keeps it, with a log line saying so. The previous revision fought such a client for the life of the session, with no error, no event and no way to turn it off — which is the mirror image of the bug this fixes.
Logging
Unchanged: a line per correction, carrying the bounds it replaced, so one line means one demotion and its timestamp can be matched against the client's own call timeline — including for a command through the playwright executor, which the devtools proxy does not see.
Testing
go test -raceacross the non-e2e packages: passgo build ./...,go vet ./cmd/api/api/ ./lib/x11/: cleanreconcileWindowtests are unchanged_NET_ACTIVE_WINDOWand_NET_WM_STATE, including maximized-in-one-direction and the kiosk fullscreen casecovered=falsein the same second as a CDP demotion, twice, once for the state change and once for the explicit bounds that followedNot yet exercised in a deployed image: the guard itself needs a release to run for real.
Follow-up worth having, not in this PR
A correction should be a telemetry event, not only a VM log line. Adding an event type means a schema change here plus the matching type on the API side, so it belongs in its own change — but without it, a window geometry change leaves no trace a customer can see, which is exactly why the bug behind this PR took two days to pin down.