X11: Let XRandR respect multiple screens (DISPLAY=:0.0 vs :0.1, etc).
authorRyan C. Gordon <icculus@icculus.org>
Tue, 17 Nov 2015 12:15:35 -0500
changeset 9920183936dd34d5
parent 9919 ac5490d5aefc
child 9921 8865d17947de
X11: Let XRandR respect multiple screens (DISPLAY=:0.0 vs :0.1, etc).
src/video/x11/SDL_x11modes.c
     1.1 --- a/src/video/x11/SDL_x11modes.c	Mon Nov 16 21:20:38 2015 -0800
     1.2 +++ b/src/video/x11/SDL_x11modes.c	Tue Nov 17 12:15:35 2015 -0500
     1.3 @@ -357,16 +357,12 @@
     1.4  int
     1.5  X11_InitModes_XRandR(_THIS)
     1.6  {
     1.7 -    /* In theory, you _could_ have multiple screens (like DISPLAY=:0.0
     1.8 -       and DISPLAY=:0.1) but no XRandR system we care about is like this,
     1.9 -       as all the physical displays would be separate XRandR "outputs" on
    1.10 -       the one X11 virtual "screen". So we don't use ScreenCount() here. */
    1.11 -
    1.12      SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    1.13      Display *dpy = data->display;
    1.14 +    const int screencount = ScreenCount(dpy);
    1.15 +    const int default_screen = DefaultScreen(dpy);
    1.16 +    RROutput primary = X11_XRRGetOutputPrimary(dpy, RootWindow(dpy, default_screen));
    1.17      Atom EDID = X11_XInternAtom(dpy, "EDID", False);
    1.18 -    const int screen = DefaultScreen(dpy);
    1.19 -    RROutput primary;
    1.20      XRRScreenResources *res = NULL;
    1.21      Uint32 pixelformat;
    1.22      XVisualInfo vinfo;
    1.23 @@ -374,120 +370,127 @@
    1.24      int looking_for_primary;
    1.25      int scanline_pad;
    1.26      int output;
    1.27 -    int i, n;
    1.28 -
    1.29 -    if (get_visualinfo(dpy, screen, &vinfo) < 0) {
    1.30 -        return -1;
    1.31 -    }
    1.32 -
    1.33 -    pixelformat = X11_GetPixelFormatFromVisualInfo(dpy, &vinfo);
    1.34 -    if (SDL_ISPIXELFORMAT_INDEXED(pixelformat)) {
    1.35 -        return SDL_SetError("Palettized video modes are no longer supported");
    1.36 -    }
    1.37 -
    1.38 -    scanline_pad = SDL_BYTESPERPIXEL(pixelformat) * 8;
    1.39 -    pixmapformats = X11_XListPixmapFormats(dpy, &n);
    1.40 -    if (pixmapformats) {
    1.41 -        for (i = 0; i < n; ++i) {
    1.42 -            if (pixmapformats[i].depth == vinfo.depth) {
    1.43 -                scanline_pad = pixmapformats[i].scanline_pad;
    1.44 -                break;
    1.45 -            }
    1.46 -        }
    1.47 -        X11_XFree(pixmapformats);
    1.48 -    }
    1.49 -
    1.50 -    res = X11_XRRGetScreenResources(dpy, RootWindow(dpy, screen));
    1.51 -    if (!res) {
    1.52 -        return -1;
    1.53 -    }
    1.54 -
    1.55 -    primary = X11_XRRGetOutputPrimary(dpy, RootWindow(dpy, screen));
    1.56 +    int screen, i, n;
    1.57  
    1.58      for (looking_for_primary = 1; looking_for_primary >= 0; looking_for_primary--) {
    1.59 -        for (output = 0; output < res->noutput; output++) {
    1.60 -            XRROutputInfo *output_info;
    1.61 -            int display_x, display_y;
    1.62 -            unsigned long display_mm_width, display_mm_height;
    1.63 -            SDL_DisplayData *displaydata;
    1.64 -            char display_name[128];
    1.65 -            SDL_DisplayMode mode;
    1.66 -            SDL_DisplayModeData *modedata;
    1.67 -            SDL_VideoDisplay display;
    1.68 -            RRMode modeID;
    1.69 -            RRCrtc output_crtc;
    1.70 -            XRRCrtcInfo *crtc;
    1.71 +        for (screen = 0; screen < screencount; screen++) {
    1.72  
    1.73 -            /* The primary output _should_ always be sorted first, but just in case... */
    1.74 -            if ((looking_for_primary && (res->outputs[output] != primary)) ||
    1.75 -                (!looking_for_primary && (res->outputs[output] == primary))) {
    1.76 +            /* we want the primary output first, and then skipped later. */
    1.77 +            if ((looking_for_primary && (screen != default_screen)) ||
    1.78 +                (!looking_for_primary && (screen == default_screen))) {
    1.79                  continue;
    1.80              }
    1.81  
    1.82 -            output_info = X11_XRRGetOutputInfo(dpy, res, res->outputs[output]);
    1.83 -            if (!output_info || !output_info->crtc || output_info->connection == RR_Disconnected) {
    1.84 -                X11_XRRFreeOutputInfo(output_info);
    1.85 +            if (get_visualinfo(dpy, screen, &vinfo) < 0) {
    1.86 +                continue;  /* uh, skip this screen? */
    1.87 +            }
    1.88 +
    1.89 +            pixelformat = X11_GetPixelFormatFromVisualInfo(dpy, &vinfo);
    1.90 +            if (SDL_ISPIXELFORMAT_INDEXED(pixelformat)) {
    1.91 +                continue;  /* Palettized video modes are no longer supported */
    1.92 +            }
    1.93 +
    1.94 +            scanline_pad = SDL_BYTESPERPIXEL(pixelformat) * 8;
    1.95 +            pixmapformats = X11_XListPixmapFormats(dpy, &n);
    1.96 +            if (pixmapformats) {
    1.97 +                for (i = 0; i < n; ++i) {
    1.98 +                    if (pixmapformats[i].depth == vinfo.depth) {
    1.99 +                        scanline_pad = pixmapformats[i].scanline_pad;
   1.100 +                        break;
   1.101 +                    }
   1.102 +                }
   1.103 +                X11_XFree(pixmapformats);
   1.104 +            }
   1.105 +
   1.106 +            res = X11_XRRGetScreenResources(dpy, RootWindow(dpy, screen));
   1.107 +            if (!res) {
   1.108                  continue;
   1.109              }
   1.110  
   1.111 -            SDL_strlcpy(display_name, output_info->name, sizeof(display_name));
   1.112 -            display_mm_width = output_info->mm_width;
   1.113 -            display_mm_height = output_info->mm_height;
   1.114 -            output_crtc = output_info->crtc;
   1.115 -            X11_XRRFreeOutputInfo(output_info);
   1.116 +            for (output = 0; output < res->noutput; output++) {
   1.117 +                XRROutputInfo *output_info;
   1.118 +                int display_x, display_y;
   1.119 +                unsigned long display_mm_width, display_mm_height;
   1.120 +                SDL_DisplayData *displaydata;
   1.121 +                char display_name[128];
   1.122 +                SDL_DisplayMode mode;
   1.123 +                SDL_DisplayModeData *modedata;
   1.124 +                SDL_VideoDisplay display;
   1.125 +                RRMode modeID;
   1.126 +                RRCrtc output_crtc;
   1.127 +                XRRCrtcInfo *crtc;
   1.128  
   1.129 -            crtc = X11_XRRGetCrtcInfo(dpy, res, output_crtc);
   1.130 -            if (!crtc) {
   1.131 -                continue;
   1.132 +                /* The primary output _should_ always be sorted first, but just in case... */
   1.133 +                if ((looking_for_primary && ((screen != default_screen) || (res->outputs[output] != primary))) ||
   1.134 +                    (!looking_for_primary && (screen == default_screen) && (res->outputs[output] == primary))) {
   1.135 +                    continue;
   1.136 +                }
   1.137 +
   1.138 +                output_info = X11_XRRGetOutputInfo(dpy, res, res->outputs[output]);
   1.139 +                if (!output_info || !output_info->crtc || output_info->connection == RR_Disconnected) {
   1.140 +                    X11_XRRFreeOutputInfo(output_info);
   1.141 +                    continue;
   1.142 +                }
   1.143 +
   1.144 +                SDL_strlcpy(display_name, output_info->name, sizeof(display_name));
   1.145 +                display_mm_width = output_info->mm_width;
   1.146 +                display_mm_height = output_info->mm_height;
   1.147 +                output_crtc = output_info->crtc;
   1.148 +                X11_XRRFreeOutputInfo(output_info);
   1.149 +
   1.150 +                crtc = X11_XRRGetCrtcInfo(dpy, res, output_crtc);
   1.151 +                if (!crtc) {
   1.152 +                    continue;
   1.153 +                }
   1.154 +
   1.155 +                SDL_zero(mode);
   1.156 +                modeID = crtc->mode;
   1.157 +                mode.w = crtc->width;
   1.158 +                mode.h = crtc->height;
   1.159 +                mode.format = pixelformat;
   1.160 +
   1.161 +                display_x = crtc->x;
   1.162 +                display_y = crtc->y;
   1.163 +
   1.164 +                X11_XRRFreeCrtcInfo(crtc);
   1.165 +
   1.166 +                displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
   1.167 +                if (!displaydata) {
   1.168 +                    return SDL_OutOfMemory();
   1.169 +                }
   1.170 +
   1.171 +                modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   1.172 +                if (!modedata) {
   1.173 +                    SDL_free(displaydata);
   1.174 +                    return SDL_OutOfMemory();
   1.175 +                }
   1.176 +                modedata->xrandr_mode = modeID;
   1.177 +                mode.driverdata = modedata;
   1.178 +
   1.179 +                displaydata->screen = screen;
   1.180 +                displaydata->visual = vinfo.visual;
   1.181 +                displaydata->depth = vinfo.depth;
   1.182 +                displaydata->hdpi = ((float) mode.w) * 25.4f / display_mm_width;
   1.183 +                displaydata->vdpi = ((float) mode.h) * 25.4f / display_mm_height;
   1.184 +                displaydata->ddpi = SDL_ComputeDiagonalDPI(mode.w, mode.h, ((float) display_mm_width) / 25.4f,((float) display_mm_height) / 25.4f);
   1.185 +                displaydata->scanline_pad = scanline_pad;
   1.186 +                displaydata->x = display_x;
   1.187 +                displaydata->y = display_y;
   1.188 +                displaydata->use_xrandr = 1;
   1.189 +                displaydata->xrandr_output = res->outputs[output];
   1.190 +
   1.191 +                SetXRandRModeInfo(dpy, res, output_crtc, modeID, &mode);
   1.192 +                SetXRandRDisplayName(dpy, EDID, display_name, sizeof (display_name), res->outputs[output], display_mm_width, display_mm_height);
   1.193 +
   1.194 +                SDL_zero(display);
   1.195 +                if (*display_name) {
   1.196 +                    display.name = display_name;
   1.197 +                }
   1.198 +                display.desktop_mode = mode;
   1.199 +                display.current_mode = mode;
   1.200 +                display.driverdata = displaydata;
   1.201 +                SDL_AddVideoDisplay(&display);
   1.202              }
   1.203 -
   1.204 -            SDL_zero(mode);
   1.205 -            modeID = crtc->mode;
   1.206 -            mode.w = crtc->width;
   1.207 -            mode.h = crtc->height;
   1.208 -            mode.format = pixelformat;
   1.209 -
   1.210 -            display_x = crtc->x;
   1.211 -            display_y = crtc->y;
   1.212 -
   1.213 -            X11_XRRFreeCrtcInfo(crtc);
   1.214 -
   1.215 -            displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
   1.216 -            if (!displaydata) {
   1.217 -                return SDL_OutOfMemory();
   1.218 -            }
   1.219 -
   1.220 -            modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   1.221 -            if (!modedata) {
   1.222 -                SDL_free(displaydata);
   1.223 -                return SDL_OutOfMemory();
   1.224 -            }
   1.225 -            modedata->xrandr_mode = modeID;
   1.226 -            mode.driverdata = modedata;
   1.227 -
   1.228 -            displaydata->screen = screen;
   1.229 -            displaydata->visual = vinfo.visual;
   1.230 -            displaydata->depth = vinfo.depth;
   1.231 -            displaydata->hdpi = ((float) mode.w) * 25.4f / display_mm_width;
   1.232 -            displaydata->vdpi = ((float) mode.h) * 25.4f / display_mm_height;
   1.233 -            displaydata->ddpi = SDL_ComputeDiagonalDPI(mode.w, mode.h, ((float) display_mm_width) / 25.4f,((float) display_mm_height) / 25.4f);
   1.234 -            displaydata->scanline_pad = scanline_pad;
   1.235 -            displaydata->x = display_x;
   1.236 -            displaydata->y = display_y;
   1.237 -            displaydata->use_xrandr = 1;
   1.238 -            displaydata->xrandr_output = res->outputs[output];
   1.239 -
   1.240 -            SetXRandRModeInfo(dpy, res, output_crtc, modeID, &mode);
   1.241 -            SetXRandRDisplayName(dpy, EDID, display_name, sizeof (display_name), res->outputs[output], display_mm_width, display_mm_height);
   1.242 -
   1.243 -            SDL_zero(display);
   1.244 -            if (*display_name) {
   1.245 -                display.name = display_name;
   1.246 -            }
   1.247 -            display.desktop_mode = mode;
   1.248 -            display.current_mode = mode;
   1.249 -            display.driverdata = displaydata;
   1.250 -            SDL_AddVideoDisplay(&display);
   1.251          }
   1.252      }
   1.253