From c08aeb6040685c104bed6e681045f07f9b44856c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 30 Jul 2015 15:06:37 +0200 Subject: [PATCH] Set user/client requested mode as preferred Desktop environments like to change to the monitor's preferred mode, especially at login. Lacking one, they pick the highest resolution they can find. This tends to override what the user has picked, so try to work around the desktop environments by setting the preferred mode to what the user has chosen. Credit goes to Michal Srb who figured out the problem. --- unix/xserver/hw/vnc/XorgGlue.c | 32 ++--------- unix/xserver/hw/vnc/XorgGlue.h | 2 +- unix/xserver/hw/vnc/vncModule.c | 23 ++++++-- unix/xserver/hw/vnc/xvnc.c | 94 ++++++++++++++++++++++++--------- 4 files changed, 93 insertions(+), 58 deletions(-) diff --git a/unix/xserver/hw/vnc/XorgGlue.c b/unix/xserver/hw/vnc/XorgGlue.c index 8a3a2735..d7892b18 100644 --- a/unix/xserver/hw/vnc/XorgGlue.c +++ b/unix/xserver/hw/vnc/XorgGlue.c @@ -291,25 +291,6 @@ void vncRandRGetOutputDimensions(int scrIdx, int outputIdx, #endif } -#ifdef RANDR -static RRModePtr findRandRMode(RROutputPtr output, int width, int height) -{ - RRModePtr mode; - - for (int i = 0;i < output->numModes;i++) { - if ((output->modes[i]->mode.width == width) && - (output->modes[i]->mode.height == height)) - return output->modes[i]; - } - - mode = vncRandRModeGet(width, height); - if (mode != NULL) - return mode; - - return NULL; -} -#endif - int vncRandRReconfigureOutput(int scrIdx, int outputIdx, int x, int y, int width, int height) { @@ -340,15 +321,10 @@ int vncRandRReconfigureOutput(int scrIdx, int outputIdx, int x, int y, return -1; } - mode = crtc->mode; - - /* Need to switch mode? */ - if ((mode == NULL) || - (mode->mode.width != width) || (mode->mode.height != height)) { - mode = findRandRMode(output, width, height); - if (mode == NULL) - return -1; - } + /* Make sure we have the mode we want */ + mode = vncRandRCreatePreferredMode(output, width, height); + if (mode == NULL) + return -1; /* Reconfigure new mode and position */ return RRCrtcSet(crtc, mode, x, y, crtc->rotation, 1, &output); diff --git a/unix/xserver/hw/vnc/XorgGlue.h b/unix/xserver/hw/vnc/XorgGlue.h index 05ca7ba9..92b0d18d 100644 --- a/unix/xserver/hw/vnc/XorgGlue.h +++ b/unix/xserver/hw/vnc/XorgGlue.h @@ -59,8 +59,8 @@ void vncRandRGetOutputDimensions(int scrIdx, int outputIdx, // These hide in xvnc.c or vncModule.c void vncClientGone(int fd); -void *vncRandRModeGet(int width, int height); int vncRandRCreateOutputs(int scrIdx, int extraOutputs); +void *vncRandRCreatePreferredMode(void *output, int width, int height); #ifdef __cplusplus } diff --git a/unix/xserver/hw/vnc/vncModule.c b/unix/xserver/hw/vnc/vncModule.c index 8cbf9c2d..21f87ce9 100644 --- a/unix/xserver/hw/vnc/vncModule.c +++ b/unix/xserver/hw/vnc/vncModule.c @@ -112,13 +112,28 @@ void vncClientGone(int fd) } #ifdef RANDR -void *vncRandRModeGet(int width, int height) +int vncRandRCreateOutputs(int scrIdx, int extraOutputs) { - return NULL; + return -1; } -int vncRandRCreateOutputs(int scrIdx, int extraOutputs) +void *vncRandRCreatePreferredMode(void *out, int width, int height) { - return -1; + RROutputPtr output; + + /* + * We're not going to change which modes are preferred, but let's + * see if we can at least find a mode with matching dimensions. + */ + + output = out; + + for (int i = 0;i < output->numModes;i++) { + if ((output->modes[i]->mode.width == width) && + (output->modes[i]->mode.height == height)) + return output->modes[i]; + } + + return NULL; } #endif diff --git a/unix/xserver/hw/vnc/xvnc.c b/unix/xserver/hw/vnc/xvnc.c index 714d8a2f..cac2aeeb 100644 --- a/unix/xserver/hw/vnc/xvnc.c +++ b/unix/xserver/hw/vnc/xvnc.c @@ -1071,6 +1071,7 @@ xf86SetRootClip (ScreenPtr pScreen, Bool enable) static Bool vncRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode, int x, int y, Rotation rotation, int num_outputs, RROutputPtr *outputs); +static RRModePtr vncRandRModeGet(int width, int height); static Bool vncRandRScreenSetSize(ScreenPtr pScreen, CARD16 width, CARD16 height, @@ -1179,7 +1180,7 @@ static Bool vncRandRScreenSetSize(ScreenPtr pScreen, continue; } - /* Just needs to be resized */ + /* Just needs to be resized to a temporary mode */ mode = vncRandRModeGet(width - crtc->x, height - crtc->y); if (mode == NULL) { ErrorF("Warning: Unable to create custom mode for %dx%d", @@ -1244,8 +1245,7 @@ static const int vncRandRHeights[] = { 1200, 1080, 1200, 1050, 1050, 768, 1024, static int vncRandRIndex = 0; -/* This is a global symbol since findRandRMode() also uses it */ -void *vncRandRModeGet(int width, int height) +static RRModePtr vncRandRModeGet(int width, int height) { xRRModeInfo modeInfo; char name[100]; @@ -1267,16 +1267,51 @@ void *vncRandRModeGet(int width, int height) return mode; } +static void vncRandRSetModes(RROutputPtr output, int pref_width, int pref_height) +{ + RRModePtr mode; + RRModePtr *modes; + int i, num_modes, num_pref; + + num_modes = sizeof(vncRandRWidths)/sizeof(*vncRandRWidths) + 1; + modes = malloc(sizeof(RRModePtr)*num_modes); + if (modes == NULL) + return; + + num_modes = 0; + num_pref = 0; + + if ((pref_width > 0) && (pref_height > 0)) { + mode = vncRandRModeGet(pref_width, pref_height); + if (mode != NULL) { + modes[num_modes] = mode; + num_modes++; + num_pref++; + } + } + + for (i = 0;i < sizeof(vncRandRWidths)/sizeof(*vncRandRWidths);i++) { + if ((vncRandRWidths[i] == pref_width) && + (vncRandRHeights[i] == pref_height)) + continue; + mode = vncRandRModeGet(vncRandRWidths[i], vncRandRHeights[i]); + if (mode != NULL) { + modes[num_modes] = mode; + num_modes++; + } + } + + RROutputSetModes(output, modes, num_modes, num_pref); + + free(modes); +} + static RRCrtcPtr vncRandRCrtcCreate(ScreenPtr pScreen) { RRCrtcPtr crtc; RROutputPtr output; - RRModePtr mode; char name[100]; - RRModePtr *modes; - int i, num_modes; - /* First we create the CRTC... */ crtc = RRCrtcCreate(pScreen, NULL); @@ -1296,22 +1331,7 @@ static RRCrtcPtr vncRandRCrtcCreate(ScreenPtr pScreen) vncRandRCrtcSet(pScreen, crtc, NULL, 0, 0, RR_Rotate_0, 1, &output); /* Populate a list of default modes */ - modes = malloc(sizeof(RRModePtr)*sizeof(vncRandRWidths)/sizeof(*vncRandRWidths)); - if (modes == NULL) - return NULL; - - num_modes = 0; - for (i = 0;i < sizeof(vncRandRWidths)/sizeof(*vncRandRWidths);i++) { - mode = vncRandRModeGet(vncRandRWidths[i], vncRandRHeights[i]); - if (mode != NULL) { - modes[num_modes] = mode; - num_modes++; - } - } - - RROutputSetModes(output, modes, num_modes, 0); - - free(modes); + vncRandRSetModes(output, -1, -1); return crtc; } @@ -1331,6 +1351,30 @@ int vncRandRCreateOutputs(int scrIdx, int extraOutputs) return 0; } +/* Used to create a preferred mode from various places */ +void *vncRandRCreatePreferredMode(void *out, int width, int height) +{ + RROutputPtr output; + + output = out; + + /* Already the preferred mode? */ + if ((output->numModes >= 1) && (output->numPreferred == 1) && + (output->modes[0]->mode.width == width) && + (output->modes[0]->mode.height == height)) + return output->modes[0]; + + /* Recreate the list, with the mode we want as preferred */ + vncRandRSetModes(output, width, height); + + if ((output->numModes >= 1) && (output->numPreferred == 1) && + (output->modes[0]->mode.width == width) && + (output->modes[0]->mode.height == height)) + return output->modes[0]; + + return NULL; +} + static Bool vncRandRInit(ScreenPtr pScreen) { RRCrtcPtr crtc; @@ -1350,13 +1394,13 @@ static Bool vncRandRInit(ScreenPtr pScreen) crtc = vncRandRCrtcCreate(pScreen); /* Make sure the current screen size is the active mode */ - mode = vncRandRModeGet(pScreen->width, pScreen->height); + mode = vncRandRCreatePreferredMode(crtc->outputs[0], + pScreen->width, pScreen->height); if (mode == NULL) return FALSE; ret = vncRandRCrtcSet(pScreen, crtc, mode, 0, 0, RR_Rotate_0, crtc->numOutputs, crtc->outputs); - RRModeDestroy(mode); if (!ret) return FALSE; -- 2.39.5