fix: remove unnecessary screen width rounding in ChangeScreenSize#11
fix: remove unnecessary screen width rounding in ChangeScreenSize#11hiroTamada merged 2 commits intomasterfrom
Conversation
Sayan-
left a comment
There was a problem hiding this comment.
generally lgtm! how'd you test these changes?
The Go-level `s.Width = s.Width - (s.Width % 8)` rounding was silently truncating requested widths (e.g. 390 → 384) before attempting to find or create a screen mode. This made it impossible to use resolutions like 392x844 for mobile viewports even when valid modelines existed. The rounding was originally added to match libxcvt's CVT convention of producing widths as multiples of 8, but this is a timing standard for physical monitors — not a constraint of the Xorg dummy driver used for virtual displays. Now ChangeScreenSize follows a 3-step fallback: 1. Try the exact requested dimensions (e.g. 390x844) 2. If no match, round width up to the nearest multiple of 8 and retry (e.g. 392x844 — matches predefined modelines in xorg.conf) 3. If still no match, dynamically create a new mode via libxcvt The C layer is also updated so XCreateScreenMode returns the actual dimensions that libxcvt produced (via in/out pointer parameters), and XCreateScreenModeInfo uses the actual libxcvt output dimensions for the mode name so it matches the real mode geometry. Co-authored-by: Cursor <cursoragent@cursor.com>
77b82c8 to
9fc8c79
Compare
The 3-step resolution flow (exact → round-up → libxcvt) had no practical benefit from the middle step. If an exact modeline exists in xorg.conf, step 1 finds it. If not, libxcvt creates one. The round-up retry only helped in the contrived case where a rounded modeline existed but the exact one didn't. Simplify to: try exact match, then create via libxcvt. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| // if no existing mode matches, dynamically create one via libxcvt | ||
| if status != C.RRSetConfigSuccess { | ||
| // create new screen configuration | ||
| C.XCreateScreenMode(c_width, c_height, c_rate) |
There was a problem hiding this comment.
Missing round-up-to-8 fallback step before mode creation
Medium Severity
The PR description documents a 3-step fallback (exact match → round-up to nearest multiple of 8 → dynamic creation), but ChangeScreenSize only implements steps 1 and 3. The round-up step is missing: after the exact XSetScreenConfiguration fails, the code jumps directly to XCreateScreenMode instead of first trying the width rounded up to the nearest multiple of 8. This means if a pre-configured mode like 392×844 already exists and 390×844 is requested, libxcvt will create a duplicate 392×844 mode instead of reusing the existing one, causing mode proliferation on every such request.
Updates the neko base image and Go module dependency to include the screen width rounding fix (kernel/neko#11). Co-authored-by: Cursor <cursoragent@cursor.com>
## Summary - Automatically enables Chromium `--app` mode when the requested display width < 500px or height < 200px, removing the tab/toolbar chrome that enforces a ~500px minimum window width - Adds `RemoveFlagsByPrefix` and `HasFlagWithPrefix` helpers to the `chromiumflags` package for dynamic flag management - Adds manually crafted modelines for exact 390x844 (iPhone 14/15) and 768x1024 (tablet) viewports at 60/30/25 Hz, bypassing CVT's multiple-of-8 width convention since the Xorg dummy driver doesn't require it ## Context Chromium enforces a minimum window size of approximately 500px wide due to the tab bar and toolbar chrome. Launching with `--app=<url>` removes this chrome, allowing the window to resize to mobile viewports like 390x844. The `PatchDisplay` endpoint now automatically toggles this flag based on the requested dimensions and restarts Chromium when needed. The modelines use exact pixel widths (e.g. 390 instead of 392) with manually calculated timing parameters that keep the pixel clock above the Xorg dummy driver's 11 MHz minimum. CVT's convention of rounding widths to multiples of 8 is a standard for real monitor compatibility — the dummy driver is more permissive. Depends on kernel/neko#11 for correct width handling (removes Neko's Go-level rounding that was truncating 390 → 384). ## Test plan - [x] `PATCH /display` with `{"width": 390, "height": 844}` — enables app mode, display is exactly 390x844 - [x] `PATCH /display` with `{"width": 768, "height": 1024}` — no app mode, display is 768x1024 - [x] `PATCH /display` with `{"width": 1920, "height": 1080}` — disables app mode if previously enabled - [x] Verify `RemoveFlagsByPrefix` and `HasFlagWithPrefix` unit tests pass <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes runtime Chromium flag management and automatically triggers restarts based on viewport size, which can impact session stability and resize behavior; also updates Neko/image dependencies that affect display handling. > > **Overview** > Automatically toggles Chromium *app mode* during `PATCH /display`: when the requested size is below `500x200`, the API adds `--app=https://start.duckduckgo.com` to the runtime flags and forces a Chromium restart; when returning to normal sizes it removes the flag. > > Refactors Chromium runtime flag writing around a shared `chromiumFlagsPath` constant + `writeChromiumFlags`, adds `chromiumflags.RemoveFlagsByPrefix`/`HasFlagWithPrefix` helpers (with new tests), and extends the headful Xorg dummy config with exact `390x844` (iPhone) and `768x1024` modelines at 60/30/25 Hz. Also bumps the `neko` base image/dependency version and ignores the built `chromium-launcher` binary in `server/.gitignore`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 9e9dfdf. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Cursor <cursoragent@cursor.com>


Summary
s.Width = s.Width - (s.Width % 8)rounding inChangeScreenSizethat was silently truncating requested widths (e.g. 390 → 384)XCreateScreenModereturn the actual dimensions thatlibxcvtproduced via in/out pointer parameters, so the Go caller uses the correct width forXSetScreenConfigurationXCreateScreenModeInfoto uselibxcvt's actual output dimensions instead of the original request, preventing name/geometry mismatchesContext
The rounding was originally added to match
libxcvt's CVT convention of producing widths as multiples of 8. However, CVT is a timing standard for generating timing parameters for physical monitors — not a hard requirement of X.Org or the Xorg dummy driver used for virtual displays. The rounding made it impossible to use non-multiple-of-8 resolutions like 390x844 for mobile viewports, even when valid modelines existed inxorg.conf, because Neko would turn 390 into 384 before ever searching for a mode.Now the resolution flow is:
xorg.conffor the exact requested dimensions (e.g.390x844),XSetScreenConfigurationfinds and uses it directly.XCreateScreenModedynamically creates a new mode vialibxcvtand reports the actual dimensions back to the caller.Verified
Tested end-to-end in a headful
chromium-headfulcontainer:390x844_25(using a manually crafted modeline inxorg.confthat bypasses CVT rounding)screen.width=390,screen.height=844,innerWidth=390,innerHeight=807(37px app-mode title bar)Note
Medium Risk
Touches XRandR mode selection/creation and changes the resolution-setting flow, which could affect display configuration behavior across environments, but the change is localized to the Xorg wrapper.
Overview
ChangeScreenSizeno longer truncates widths to a multiple of 8 before attempting to apply a screen mode; it now tries to set the exact requested dimensions first and only creates a new mode if no existing mode matches.XCreateScreenModeis updated to take width/height as in/out pointers so the caller receives libxcvt’s actual generated dimensions, andXCreateScreenModeInfonow names modes using those actual dimensions to avoid name/geometry mismatches.Written by Cursor Bugbot for commit 3f90ca6. This will update automatically on new commits. Configure here.