Skip to content

Commit 77b82c8

Browse files
fix: remove unnecessary screen width rounding in ChangeScreenSize
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. Instead of pre-rounding in Go, we now: - Pass the requested width directly to XSetScreenConfiguration - Make XCreateScreenMode return the actual dimensions that libxcvt produced (via in/out pointer parameters) - Use the actual libxcvt output dimensions for the mode name so it matches the real mode geometry - Update the returned ScreenSize with the actual created dimensions This way callers get accurate feedback about what resolution was set, and existing modes with non-rounded widths (from xorg.conf) are found correctly. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 5073274 commit 77b82c8

3 files changed

Lines changed: 28 additions & 12 deletions

File tree

server/pkg/xorg/xorg.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -302,12 +302,18 @@ void XGetScreenConfigurations() {
302302
}
303303

304304
// Inspired by https://github.com/raboof/xrandr/blob/master/xrandr.c
305-
void XCreateScreenMode(int width, int height, short rate) {
305+
// width and height are in/out: on return they contain the actual dimensions
306+
// of the created mode (libxcvt may round width to a multiple of 8).
307+
void XCreateScreenMode(int *width, int *height, short rate) {
306308
Display *display = getXDisplay();
307309
Window root = DefaultRootWindow(display);
308310

309311
// create new mode info
310-
XRRModeInfo *mode_info = XCreateScreenModeInfo(width, height, rate);
312+
XRRModeInfo *mode_info = XCreateScreenModeInfo(*width, *height, rate);
313+
314+
// write back the actual dimensions that were created
315+
*width = mode_info->width;
316+
*height = mode_info->height;
311317

312318
// create new mode
313319
RRMode mode = XRRCreateMode(display, root, mode_info);
@@ -325,16 +331,19 @@ void XCreateScreenMode(int width, int height, short rate) {
325331

326332
// Inspired by https://fossies.org/linux/xwayland/hw/xwayland/xwayland-cvt.c
327333
XRRModeInfo *XCreateScreenModeInfo(int hdisplay, int vdisplay, short vrefresh) {
328-
char name[128];
329-
snprintf(name, sizeof name, "%dx%d_%d", hdisplay, vdisplay, vrefresh);
330-
XRRModeInfo *modeinfo = XRRAllocModeInfo(name, strlen(name));
331-
332334
#ifdef _LIBCVT_H_
333335
struct libxcvt_mode_info *mode_info;
334336

335337
// get screen mode from libxcvt, if available
338+
// NOTE: libxcvt may round hdisplay up to a multiple of 8 (CVT convention).
339+
// We use the actual output dimensions for both the mode name and geometry
340+
// so that they are consistent.
336341
mode_info = libxcvt_gen_mode_info(hdisplay, vdisplay, vrefresh, false, false);
337342

343+
char name[128];
344+
snprintf(name, sizeof name, "%dx%d_%d", mode_info->hdisplay, mode_info->vdisplay, vrefresh);
345+
XRRModeInfo *modeinfo = XRRAllocModeInfo(name, strlen(name));
346+
338347
modeinfo->width = mode_info->hdisplay;
339348
modeinfo->height = mode_info->vdisplay;
340349
modeinfo->dotClock = mode_info->dot_clock * 1000;
@@ -349,6 +358,10 @@ XRRModeInfo *XCreateScreenModeInfo(int hdisplay, int vdisplay, short vrefresh) {
349358
free(mode_info);
350359
#else
351360
// fallback to a simple mode without refresh rate
361+
char name[128];
362+
snprintf(name, sizeof name, "%dx%d_%d", hdisplay, vdisplay, vrefresh);
363+
XRRModeInfo *modeinfo = XRRAllocModeInfo(name, strlen(name));
364+
352365
modeinfo->width = hdisplay;
353366
modeinfo->height = vdisplay;
354367
#endif

server/pkg/xorg/xorg.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,6 @@ func ChangeScreenSize(s types.ScreenSize) (types.ScreenSize, error) {
201201
mu.Lock()
202202
defer mu.Unlock()
203203

204-
// round width to 8, because of Xorg
205-
s.Width = s.Width - (s.Width % 8)
206-
207204
// if rate is 0, set it to 60
208205
if s.Rate == 0 {
209206
s.Rate = 60
@@ -215,8 +212,14 @@ func ChangeScreenSize(s types.ScreenSize) (types.ScreenSize, error) {
215212
// if screen configuration already exists, just set it
216213
status := C.XSetScreenConfiguration(c_width, c_height, c_rate)
217214
if status != C.RRSetConfigSuccess {
218-
// create new screen configuration
219-
C.XCreateScreenMode(c_width, c_height, c_rate)
215+
// create new screen configuration; XCreateScreenMode may adjust
216+
// width/height (e.g. libxcvt rounds width to a multiple of 8) so
217+
// we use in/out parameters to get the actual dimensions back.
218+
C.XCreateScreenMode(&c_width, &c_height, c_rate)
219+
220+
// update s with the actual dimensions created
221+
s.Width = int(c_width)
222+
s.Height = int(c_height)
220223

221224
// screen configuration should exist now, set it
222225
status = C.XSetScreenConfiguration(c_width, c_height, c_rate)

server/pkg/xorg/xorg.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ void XKey(KeySym keysym, int down);
3939
Status XSetScreenConfiguration(int width, int height, short rate);
4040
void XGetScreenConfiguration(int *width, int *height, short *rate);
4141
void XGetScreenConfigurations();
42-
void XCreateScreenMode(int width, int height, short rate);
42+
void XCreateScreenMode(int *width, int *height, short rate);
4343
XRRModeInfo *XCreateScreenModeInfo(int hdisplay, int vdisplay, short vrefresh);
4444

4545
void XSetKeyboardModifier(unsigned char mod, int on);

0 commit comments

Comments
 (0)