diff --git a/server/pkg/xorg/xorg.c b/server/pkg/xorg/xorg.c index e2c04dcc2..8542a0188 100644 --- a/server/pkg/xorg/xorg.c +++ b/server/pkg/xorg/xorg.c @@ -302,12 +302,18 @@ void XGetScreenConfigurations() { } // Inspired by https://github.com/raboof/xrandr/blob/master/xrandr.c -void XCreateScreenMode(int width, int height, short rate) { +// width and height are in/out: on return they contain the actual dimensions +// of the created mode (libxcvt may round width to a multiple of 8). +void XCreateScreenMode(int *width, int *height, short rate) { Display *display = getXDisplay(); Window root = DefaultRootWindow(display); // create new mode info - XRRModeInfo *mode_info = XCreateScreenModeInfo(width, height, rate); + XRRModeInfo *mode_info = XCreateScreenModeInfo(*width, *height, rate); + + // write back the actual dimensions that were created + *width = mode_info->width; + *height = mode_info->height; // create new mode RRMode mode = XRRCreateMode(display, root, mode_info); @@ -325,16 +331,19 @@ void XCreateScreenMode(int width, int height, short rate) { // Inspired by https://fossies.org/linux/xwayland/hw/xwayland/xwayland-cvt.c XRRModeInfo *XCreateScreenModeInfo(int hdisplay, int vdisplay, short vrefresh) { - char name[128]; - snprintf(name, sizeof name, "%dx%d_%d", hdisplay, vdisplay, vrefresh); - XRRModeInfo *modeinfo = XRRAllocModeInfo(name, strlen(name)); - #ifdef _LIBCVT_H_ struct libxcvt_mode_info *mode_info; // get screen mode from libxcvt, if available + // NOTE: libxcvt may round hdisplay up to a multiple of 8 (CVT convention). + // We use the actual output dimensions for both the mode name and geometry + // so that they are consistent. mode_info = libxcvt_gen_mode_info(hdisplay, vdisplay, vrefresh, false, false); + char name[128]; + snprintf(name, sizeof name, "%dx%d_%d", mode_info->hdisplay, mode_info->vdisplay, vrefresh); + XRRModeInfo *modeinfo = XRRAllocModeInfo(name, strlen(name)); + modeinfo->width = mode_info->hdisplay; modeinfo->height = mode_info->vdisplay; modeinfo->dotClock = mode_info->dot_clock * 1000; @@ -349,6 +358,10 @@ XRRModeInfo *XCreateScreenModeInfo(int hdisplay, int vdisplay, short vrefresh) { free(mode_info); #else // fallback to a simple mode without refresh rate + char name[128]; + snprintf(name, sizeof name, "%dx%d_%d", hdisplay, vdisplay, vrefresh); + XRRModeInfo *modeinfo = XRRAllocModeInfo(name, strlen(name)); + modeinfo->width = hdisplay; modeinfo->height = vdisplay; #endif diff --git a/server/pkg/xorg/xorg.go b/server/pkg/xorg/xorg.go index a6a387995..8d5ee050d 100644 --- a/server/pkg/xorg/xorg.go +++ b/server/pkg/xorg/xorg.go @@ -201,9 +201,6 @@ func ChangeScreenSize(s types.ScreenSize) (types.ScreenSize, error) { mu.Lock() defer mu.Unlock() - // round width to 8, because of Xorg - s.Width = s.Width - (s.Width % 8) - // if rate is 0, set it to 60 if s.Rate == 0 { s.Rate = 60 @@ -212,16 +209,21 @@ func ChangeScreenSize(s types.ScreenSize) (types.ScreenSize, error) { // convert variables to C types c_width, c_height, c_rate := C.int(s.Width), C.int(s.Height), C.short(s.Rate) - // if screen configuration already exists, just set it + // try to set the screen configuration with the exact requested dimensions status := C.XSetScreenConfiguration(c_width, c_height, c_rate) + + // 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) + C.XCreateScreenMode(&c_width, &c_height, c_rate) // screen configuration should exist now, set it status = C.XSetScreenConfiguration(c_width, c_height, c_rate) } + // update s with the actual dimensions that were set + s.Width = int(c_width) + s.Height = int(c_height) + var err error // if screen configuration was not set successfully, return error diff --git a/server/pkg/xorg/xorg.h b/server/pkg/xorg/xorg.h index 781bcef81..92d834eeb 100644 --- a/server/pkg/xorg/xorg.h +++ b/server/pkg/xorg/xorg.h @@ -39,7 +39,7 @@ void XKey(KeySym keysym, int down); Status XSetScreenConfiguration(int width, int height, short rate); void XGetScreenConfiguration(int *width, int *height, short *rate); void XGetScreenConfigurations(); -void XCreateScreenMode(int width, int height, short rate); +void XCreateScreenMode(int *width, int *height, short rate); XRRModeInfo *XCreateScreenModeInfo(int hdisplay, int vdisplay, short vrefresh); void XSetKeyboardModifier(unsigned char mod, int on);