From 5224dfcc9aaa00452ee2516ccde009071ed9bffd Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 17 Nov 2015 12:15:35 -0500 Subject: [PATCH] X11: Let XRandR respect multiple screens (DISPLAY=:0.0 vs :0.1, etc). --- src/video/x11/SDL_x11modes.c | 207 ++++++++++++++++++----------------- 1 file changed, 105 insertions(+), 102 deletions(-) diff --git a/src/video/x11/SDL_x11modes.c b/src/video/x11/SDL_x11modes.c index eb4bf7e27e26b..d3f8874b5c816 100644 --- a/src/video/x11/SDL_x11modes.c +++ b/src/video/x11/SDL_x11modes.c @@ -357,16 +357,12 @@ SetXRandRDisplayName(Display *dpy, Atom EDID, char *name, const size_t namelen, int X11_InitModes_XRandR(_THIS) { - /* In theory, you _could_ have multiple screens (like DISPLAY=:0.0 - and DISPLAY=:0.1) but no XRandR system we care about is like this, - as all the physical displays would be separate XRandR "outputs" on - the one X11 virtual "screen". So we don't use ScreenCount() here. */ - SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; Display *dpy = data->display; + const int screencount = ScreenCount(dpy); + const int default_screen = DefaultScreen(dpy); + RROutput primary = X11_XRRGetOutputPrimary(dpy, RootWindow(dpy, default_screen)); Atom EDID = X11_XInternAtom(dpy, "EDID", False); - const int screen = DefaultScreen(dpy); - RROutput primary; XRRScreenResources *res = NULL; Uint32 pixelformat; XVisualInfo vinfo; @@ -374,120 +370,127 @@ X11_InitModes_XRandR(_THIS) int looking_for_primary; int scanline_pad; int output; - int i, n; - - if (get_visualinfo(dpy, screen, &vinfo) < 0) { - return -1; - } + int screen, i, n; - pixelformat = X11_GetPixelFormatFromVisualInfo(dpy, &vinfo); - if (SDL_ISPIXELFORMAT_INDEXED(pixelformat)) { - return SDL_SetError("Palettized video modes are no longer supported"); - } + for (looking_for_primary = 1; looking_for_primary >= 0; looking_for_primary--) { + for (screen = 0; screen < screencount; screen++) { - scanline_pad = SDL_BYTESPERPIXEL(pixelformat) * 8; - pixmapformats = X11_XListPixmapFormats(dpy, &n); - if (pixmapformats) { - for (i = 0; i < n; ++i) { - if (pixmapformats[i].depth == vinfo.depth) { - scanline_pad = pixmapformats[i].scanline_pad; - break; + /* we want the primary output first, and then skipped later. */ + if ((looking_for_primary && (screen != default_screen)) || + (!looking_for_primary && (screen == default_screen))) { + continue; } - } - X11_XFree(pixmapformats); - } - res = X11_XRRGetScreenResources(dpy, RootWindow(dpy, screen)); - if (!res) { - return -1; - } + if (get_visualinfo(dpy, screen, &vinfo) < 0) { + continue; /* uh, skip this screen? */ + } - primary = X11_XRRGetOutputPrimary(dpy, RootWindow(dpy, screen)); + pixelformat = X11_GetPixelFormatFromVisualInfo(dpy, &vinfo); + if (SDL_ISPIXELFORMAT_INDEXED(pixelformat)) { + continue; /* Palettized video modes are no longer supported */ + } - for (looking_for_primary = 1; looking_for_primary >= 0; looking_for_primary--) { - for (output = 0; output < res->noutput; output++) { - XRROutputInfo *output_info; - int display_x, display_y; - unsigned long display_mm_width, display_mm_height; - SDL_DisplayData *displaydata; - char display_name[128]; - SDL_DisplayMode mode; - SDL_DisplayModeData *modedata; - SDL_VideoDisplay display; - RRMode modeID; - RRCrtc output_crtc; - XRRCrtcInfo *crtc; - - /* The primary output _should_ always be sorted first, but just in case... */ - if ((looking_for_primary && (res->outputs[output] != primary)) || - (!looking_for_primary && (res->outputs[output] == primary))) { - continue; + scanline_pad = SDL_BYTESPERPIXEL(pixelformat) * 8; + pixmapformats = X11_XListPixmapFormats(dpy, &n); + if (pixmapformats) { + for (i = 0; i < n; ++i) { + if (pixmapformats[i].depth == vinfo.depth) { + scanline_pad = pixmapformats[i].scanline_pad; + break; + } + } + X11_XFree(pixmapformats); } - output_info = X11_XRRGetOutputInfo(dpy, res, res->outputs[output]); - if (!output_info || !output_info->crtc || output_info->connection == RR_Disconnected) { - X11_XRRFreeOutputInfo(output_info); + res = X11_XRRGetScreenResources(dpy, RootWindow(dpy, screen)); + if (!res) { continue; } - SDL_strlcpy(display_name, output_info->name, sizeof(display_name)); - display_mm_width = output_info->mm_width; - display_mm_height = output_info->mm_height; - output_crtc = output_info->crtc; - X11_XRRFreeOutputInfo(output_info); + for (output = 0; output < res->noutput; output++) { + XRROutputInfo *output_info; + int display_x, display_y; + unsigned long display_mm_width, display_mm_height; + SDL_DisplayData *displaydata; + char display_name[128]; + SDL_DisplayMode mode; + SDL_DisplayModeData *modedata; + SDL_VideoDisplay display; + RRMode modeID; + RRCrtc output_crtc; + XRRCrtcInfo *crtc; + + /* The primary output _should_ always be sorted first, but just in case... */ + if ((looking_for_primary && ((screen != default_screen) || (res->outputs[output] != primary))) || + (!looking_for_primary && (screen == default_screen) && (res->outputs[output] == primary))) { + continue; + } - crtc = X11_XRRGetCrtcInfo(dpy, res, output_crtc); - if (!crtc) { - continue; - } + output_info = X11_XRRGetOutputInfo(dpy, res, res->outputs[output]); + if (!output_info || !output_info->crtc || output_info->connection == RR_Disconnected) { + X11_XRRFreeOutputInfo(output_info); + continue; + } + + SDL_strlcpy(display_name, output_info->name, sizeof(display_name)); + display_mm_width = output_info->mm_width; + display_mm_height = output_info->mm_height; + output_crtc = output_info->crtc; + X11_XRRFreeOutputInfo(output_info); - SDL_zero(mode); - modeID = crtc->mode; - mode.w = crtc->width; - mode.h = crtc->height; - mode.format = pixelformat; + crtc = X11_XRRGetCrtcInfo(dpy, res, output_crtc); + if (!crtc) { + continue; + } - display_x = crtc->x; - display_y = crtc->y; + SDL_zero(mode); + modeID = crtc->mode; + mode.w = crtc->width; + mode.h = crtc->height; + mode.format = pixelformat; - X11_XRRFreeCrtcInfo(crtc); + display_x = crtc->x; + display_y = crtc->y; - displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata)); - if (!displaydata) { - return SDL_OutOfMemory(); - } + X11_XRRFreeCrtcInfo(crtc); - modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); - if (!modedata) { - SDL_free(displaydata); - return SDL_OutOfMemory(); - } - modedata->xrandr_mode = modeID; - mode.driverdata = modedata; + displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata)); + if (!displaydata) { + return SDL_OutOfMemory(); + } - displaydata->screen = screen; - displaydata->visual = vinfo.visual; - displaydata->depth = vinfo.depth; - displaydata->hdpi = ((float) mode.w) * 25.4f / display_mm_width; - displaydata->vdpi = ((float) mode.h) * 25.4f / display_mm_height; - displaydata->ddpi = SDL_ComputeDiagonalDPI(mode.w, mode.h, ((float) display_mm_width) / 25.4f,((float) display_mm_height) / 25.4f); - displaydata->scanline_pad = scanline_pad; - displaydata->x = display_x; - displaydata->y = display_y; - displaydata->use_xrandr = 1; - displaydata->xrandr_output = res->outputs[output]; - - SetXRandRModeInfo(dpy, res, output_crtc, modeID, &mode); - SetXRandRDisplayName(dpy, EDID, display_name, sizeof (display_name), res->outputs[output], display_mm_width, display_mm_height); - - SDL_zero(display); - if (*display_name) { - display.name = display_name; + modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); + if (!modedata) { + SDL_free(displaydata); + return SDL_OutOfMemory(); + } + modedata->xrandr_mode = modeID; + mode.driverdata = modedata; + + displaydata->screen = screen; + displaydata->visual = vinfo.visual; + displaydata->depth = vinfo.depth; + displaydata->hdpi = ((float) mode.w) * 25.4f / display_mm_width; + displaydata->vdpi = ((float) mode.h) * 25.4f / display_mm_height; + displaydata->ddpi = SDL_ComputeDiagonalDPI(mode.w, mode.h, ((float) display_mm_width) / 25.4f,((float) display_mm_height) / 25.4f); + displaydata->scanline_pad = scanline_pad; + displaydata->x = display_x; + displaydata->y = display_y; + displaydata->use_xrandr = 1; + displaydata->xrandr_output = res->outputs[output]; + + SetXRandRModeInfo(dpy, res, output_crtc, modeID, &mode); + SetXRandRDisplayName(dpy, EDID, display_name, sizeof (display_name), res->outputs[output], display_mm_width, display_mm_height); + + SDL_zero(display); + if (*display_name) { + display.name = display_name; + } + display.desktop_mode = mode; + display.current_mode = mode; + display.driverdata = displaydata; + SDL_AddVideoDisplay(&display); } - display.desktop_mode = mode; - display.current_mode = mode; - display.driverdata = displaydata; - SDL_AddVideoDisplay(&display); } }