Rewritten X11 video mode support to directly set requested modes and exactly restore the desktop mode at shutdown.
authorSam Lantinga <slouken@libsdl.org>
Wed, 03 Oct 2012 18:56:29 -0700
changeset 6548 fc9e6be24ca9
parent 6547 38bc368a3b87
child 6549 db16b819e1d1
Rewritten X11 video mode support to directly set requested modes and exactly restore the desktop mode at shutdown.
src/video/x11/SDL_x11modes.c
src/video/x11/SDL_x11modes.h
--- a/src/video/x11/SDL_x11modes.c	Wed Oct 03 18:54:31 2012 -0700
+++ b/src/video/x11/SDL_x11modes.c	Wed Oct 03 18:56:29 2012 -0700
@@ -132,129 +132,6 @@
 
     return SDL_PIXELFORMAT_UNKNOWN;
 }
-#if SDL_VIDEO_DRIVER_X11_XINERAMA
-static SDL_bool CheckXinerama(Display * display, int *major, int *minor);
-#endif
-
-int
-X11_InitModes(_THIS)
-{
-    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
-    int screen, screencount;
-
-#if SDL_VIDEO_DRIVER_X11_XINERAMA
-    int xinerama_major, xinerama_minor;
-    XineramaScreenInfo * xinerama = NULL;
-    /* Query Xinerama extention
-     * NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012)
-     *       or newer of the Nvidia binary drivers
-     */
-    if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) {
-        xinerama = XineramaQueryScreens(data->display, &screencount);
-    }
-    if (!xinerama) {
-        screencount = ScreenCount(data->display);
-    }
-#else
-    screencount = ScreenCount(data->display);
-#endif
-
-    for (screen = 0; screen < screencount; ++screen) {
-        XVisualInfo vinfo;
-        SDL_VideoDisplay display;
-        SDL_DisplayData *displaydata;
-        SDL_DisplayMode mode;
-        XPixmapFormatValues *pixmapFormats;
-        int i, n;
-#if SDL_VIDEO_DRIVER_X11_XINERAMA
-        if (xinerama) {
-            if (get_visualinfo(data->display, 0, &vinfo) < 0) {
-                continue;
-            }
-        }
-        else {
-            if (get_visualinfo(data->display, screen, &vinfo) < 0) {
-                continue;
-            }
-        }
-#else
-        if (get_visualinfo(data->display, screen, &vinfo) < 0) {
-            continue;
-        }
-#endif
-
-        mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
-        if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
-            /* We don't support palettized modes now */
-            continue;
-        }
-#if SDL_VIDEO_DRIVER_X11_XINERAMA
-        if (xinerama) {
-            mode.w = xinerama[screen].width;
-            mode.h = xinerama[screen].height;
-        }
-        else {
-            mode.w = DisplayWidth(data->display, screen);
-            mode.h = DisplayHeight(data->display, screen);
-        }
-#else
-        mode.w = DisplayWidth(data->display, screen);
-        mode.h = DisplayHeight(data->display, screen);
-#endif
-        mode.refresh_rate = 0;
-        mode.driverdata = NULL;
-
-        displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
-        if (!displaydata) {
-            continue;
-        }
-#if SDL_VIDEO_DRIVER_X11_XINERAMA
-        /* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active,
-         * there's only one screen available. So we force the screen number to zero and
-         * let Xinerama specific code handle specific functionality using displaydata->xinerama_info
-         */
-        if (xinerama) {
-            displaydata->screen = 0;
-            displaydata->use_xinerama = xinerama_major * 100 + xinerama_minor;
-            displaydata->xinerama_info = xinerama[screen];
-            displaydata->xinerama_screen = screen;
-        }
-        else displaydata->screen = screen;
-#else
-        displaydata->screen = screen;
-#endif
-        displaydata->visual = vinfo.visual;
-        displaydata->depth = vinfo.depth;
-
-        displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8;
-        pixmapFormats = XListPixmapFormats(data->display, &n);
-        if (pixmapFormats) {
-            for (i = 0; i < n; ++i) {
-                if (pixmapFormats[i].depth == displaydata->depth) {
-                    displaydata->scanline_pad = pixmapFormats[i].scanline_pad;
-                    break;
-                }
-            }
-            XFree(pixmapFormats);
-        }
-
-        SDL_zero(display);
-        display.desktop_mode = mode;
-        display.current_mode = mode;
-        display.driverdata = displaydata;
-        SDL_AddVideoDisplay(&display);
-    }
-
-#if SDL_VIDEO_DRIVER_X11_XINERAMA
-    if (xinerama) XFree(xinerama);
-#endif
-
-    if (_this->num_displays == 0) {
-        SDL_SetError("No available displays");
-        return -1;
-    }
-    return 0;
-}
 
 /* Global for the error handler */
 int vm_event, vm_error = -1;
@@ -296,7 +173,7 @@
         return SDL_FALSE;
     }
 #ifdef X11MODES_DEBUG
-    printf("Xinerama available!\n");
+    printf("Xinerama available at version %d.%d!\n", *major, *minor);
 #endif
     return SDL_TRUE;
 }
@@ -335,7 +212,7 @@
         return SDL_FALSE;
     }
 #ifdef X11MODES_DEBUG
-    printf("XRandR available!\n");
+    printf("XRandR available at version %d.%d!\n", *major, *minor);
 #endif
     return SDL_TRUE;
 }
@@ -343,16 +220,47 @@
 #define XRANDR_ROTATION_LEFT    (1 << 1)
 #define XRANDR_ROTATION_RIGHT   (1 << 3)
 
-static void
-get_xrandr_mode_size(XRRModeInfo *mode, Rotation rotation, int *w, int *h)
+static int
+CalculateXRandRRefreshRate(const XRRModeInfo *info)
+{
+    return (info->hTotal
+            && info->vTotal) ? (1000 * info->dotClock / (info->hTotal *
+                                                         info->vTotal)) : 0;
+}
+
+static SDL_bool
+SetXRandRModeInfo(Display *display, XRRScreenResources *res, XRROutputInfo *output_info,
+                  RRMode modeID, SDL_DisplayMode *mode)
 {
-    if (rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) {
-        *w = mode->height;
-        *h = mode->width;
-    } else {
-        *w = mode->width;
-        *h = mode->height;
+    int i;
+    for (i = 0; i < res->nmode; ++i) {
+        if (res->modes[i].id == modeID) {
+            XRRCrtcInfo *crtc;
+            Rotation rotation = 0;
+            const XRRModeInfo *info = &res->modes[i];
+
+            crtc = XRRGetCrtcInfo(display, res, output_info->crtc);
+            if (crtc) {
+                rotation = crtc->rotation;
+                XRRFreeCrtcInfo(crtc);
+            }
+
+            if (rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) {
+                mode->w = info->height;
+                mode->h = info->width;
+            } else {
+                mode->w = info->width;
+                mode->h = info->height;
+            }
+            mode->refresh_rate = CalculateXRandRRefreshRate(info);
+            ((SDL_DisplayModeData*)mode->driverdata)->xrandr_mode = modeID;
+#ifdef X11MODES_DEBUG
+            printf("XRandR mode %d: %dx%d@%dHz\n", modeID, mode->w, mode->h, mode->refresh_rate);
+#endif
+            return SDL_TRUE;
+        }
     }
+    return SDL_FALSE;
 }
 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
 
@@ -391,7 +299,7 @@
         return SDL_FALSE;
     }
 #ifdef X11MODES_DEBUG
-    printf("XVidMode available!\n");
+    printf("XVidMode available at version %d.%d!\n", *major, *minor);
 #endif
     return SDL_TRUE;
 }
@@ -423,62 +331,261 @@
 }
 
 static int
-calculate_rate(XF86VidModeModeInfo * info)
+CalculateXVidModeRefreshRate(const XF86VidModeModeInfo * info)
 {
     return (info->htotal
             && info->vtotal) ? (1000 * info->dotclock / (info->htotal *
                                                          info->vtotal)) : 0;
 }
 
-static void
-save_mode(Display * display, SDL_DisplayData * data)
+SDL_bool
+SetXVidModeModeInfo(const XF86VidModeModeInfo *info, SDL_DisplayMode *mode)
 {
-    XF86VidModeGetModeInfo(display, data->screen,
-                                    &data->saved_mode);
-    XF86VidModeGetViewPort(display, data->screen,
-                                    &data->saved_view.x,
-                                    &data->saved_view.y);
+    mode->w = info->hdisplay;
+    mode->h = info->vdisplay;
+    mode->refresh_rate = CalculateXVidModeRefreshRate(info);
+    ((SDL_DisplayModeData*)mode->driverdata)->vm_mode = *info;
+    return SDL_TRUE;
 }
+#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
 
-/*
-static void
-restore_mode(Display * display, SDL_DisplayData * data)
+int
+X11_InitModes(_THIS)
 {
-    XF86VidModeModeInfo mode;
+    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
+    int screen, screencount;
+#if SDL_VIDEO_DRIVER_X11_XINERAMA
+    int xinerama_major, xinerama_minor;
+    int use_xinerama = 0;
+    XineramaScreenInfo *xinerama = NULL;
+#endif
+#if SDL_VIDEO_DRIVER_X11_XRANDR
+    int xrandr_major, xrandr_minor;
+    int use_xrandr = 0;
+    XRRScreenResources *res = NULL;
+#endif
+#if SDL_VIDEO_DRIVER_X11_XVIDMODE
+    int vm_major, vm_minor;
+    int use_vidmode = 0;
+#endif
 
-    if (XF86VidModeGetModeInfo(display, data->screen, &mode)) {
-        if (SDL_memcmp(&mode, &data->saved_mode, sizeof(mode)) != 0) {
-            XF86VidModeSwitchToMode(display, data->screen, &data->saved_mode);
+#if SDL_VIDEO_DRIVER_X11_XINERAMA
+    /* Query Xinerama extention
+     * NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012)
+     *       or newer of the Nvidia binary drivers
+     */
+    if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) {
+        xinerama = XineramaQueryScreens(data->display, &screencount);
+        if (xinerama) {
+            use_xinerama = xinerama_major * 100 + xinerama_minor;
         }
     }
-    if ((data->saved_view.x != 0) || (data->saved_view.y != 0)) {
-        XF86VidModeSetViewPort(display, data->screen,
-                                        data->saved_view.x,
-                                        data->saved_view.y);
+    if (!xinerama) {
+        screencount = ScreenCount(data->display);
+    }
+#else
+    screencount = ScreenCount(data->display);
+#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
+
+#if SDL_VIDEO_DRIVER_X11_XRANDR
+    /* require at least XRandR v1.2 */
+    if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) &&
+        (xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 2))) {
+        use_xrandr = xrandr_major * 100 + xrandr_minor;
+    }
+#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
+
+#if SDL_VIDEO_DRIVER_X11_XVIDMODE
+    if (CheckVidMode(data->display, &vm_major, &vm_minor)) {
+        use_vidmode = vm_major * 100 + vm_minor;
     }
+#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
+
+    for (screen = 0; screen < screencount; ++screen) {
+        XVisualInfo vinfo;
+        SDL_VideoDisplay display;
+        SDL_DisplayData *displaydata;
+        SDL_DisplayMode mode;
+        SDL_DisplayModeData *modedata;
+        XPixmapFormatValues *pixmapFormats;
+        int i, n;
+
+#if SDL_VIDEO_DRIVER_X11_XINERAMA
+        if (xinerama) {
+            if (get_visualinfo(data->display, 0, &vinfo) < 0) {
+                continue;
+            }
+        } else {
+            if (get_visualinfo(data->display, screen, &vinfo) < 0) {
+                continue;
+            }
+        }
+#else
+        if (get_visualinfo(data->display, screen, &vinfo) < 0) {
+            continue;
+        }
+#endif
+
+        displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
+        if (!displaydata) {
+            continue;
+        }
+
+        mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
+        if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
+            /* We don't support palettized modes now */
+            SDL_free(displaydata);
+            continue;
+        }
+#if SDL_VIDEO_DRIVER_X11_XINERAMA
+        if (xinerama) {
+            mode.w = xinerama[screen].width;
+            mode.h = xinerama[screen].height;
+        } else {
+            mode.w = DisplayWidth(data->display, screen);
+            mode.h = DisplayHeight(data->display, screen);
+        }
+#else
+        mode.w = DisplayWidth(data->display, screen);
+        mode.h = DisplayHeight(data->display, screen);
+#endif
+        mode.refresh_rate = 0;
+
+        modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
+        if (!modedata) {
+            SDL_free(displaydata);
+            continue;
+        }
+        mode.driverdata = modedata;
+
+#if SDL_VIDEO_DRIVER_X11_XINERAMA
+        /* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active,
+         * there's only one screen available. So we force the screen number to zero and
+         * let Xinerama specific code handle specific functionality using displaydata->xinerama_info
+         */
+        if (use_xinerama) {
+            displaydata->screen = 0;
+            displaydata->use_xinerama = use_xinerama;
+            displaydata->xinerama_info = xinerama[screen];
+            displaydata->xinerama_screen = screen;
+        }
+        else displaydata->screen = screen;
+#else
+        displaydata->screen = screen;
+#endif
+        displaydata->visual = vinfo.visual;
+        displaydata->depth = vinfo.depth;
+
+        displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8;
+        pixmapFormats = XListPixmapFormats(data->display, &n);
+        if (pixmapFormats) {
+            for (i = 0; i < n; ++i) {
+                if (pixmapFormats[i].depth == displaydata->depth) {
+                    displaydata->scanline_pad = pixmapFormats[i].scanline_pad;
+                    break;
+                }
+            }
+            XFree(pixmapFormats);
+        }
+
+#if SDL_VIDEO_DRIVER_X11_XINERAMA
+        if (use_xinerama) {
+            displaydata->x = xinerama[screen].x_org;
+            displaydata->y = xinerama[screen].y_org;
+        }
+        else
+#endif
+        {
+            displaydata->x = 0;
+            displaydata->y = 0;
+        }
+
+#if SDL_VIDEO_DRIVER_X11_XRANDR
+        if (use_xrandr) {
+            res = XRRGetScreenResources(data->display, RootWindow(data->display, displaydata->screen));
+        }
+        if (res) {
+            XRROutputInfo *output_info;
+            XRRCrtcInfo *crtc;
+            int output;
+
+            for (output = 0; output < res->noutput; output++) {
+                output_info = XRRGetOutputInfo(data->display, res, res->outputs[output]);
+                if (!output_info || output_info->connection == RR_Disconnected) {
+                    XRRFreeOutputInfo(output_info);
+                    continue;
+                }
+
+                /* Is this the output that corresponds to the current screen?
+                   We're checking the crtc position, but that may not be a valid test
+                   in all cases.  Anybody want to give this some love?
+                 */
+                crtc = XRRGetCrtcInfo(data->display, res, output_info->crtc);
+                if (!crtc || crtc->x != displaydata->x || crtc->y != displaydata->y) {
+                    XRRFreeOutputInfo(output_info);
+                    XRRFreeCrtcInfo(crtc);
+                    continue;
+                }
+
+                displaydata->use_xrandr = use_xrandr;
+                displaydata->xrandr_output = res->outputs[output];
+                SetXRandRModeInfo(data->display, res, output_info, crtc->mode, &mode);
+
+                XRRFreeOutputInfo(output_info);
+                XRRFreeCrtcInfo(crtc);
+                break;
+            }
+#ifdef X11MODES_DEBUG
+            if (output == res->noutput) {
+                printf("Couldn't find XRandR CRTC at %d,%d\n", displaydata->x, displaydata->y);
+            }
+#endif
+            XRRFreeScreenResources(res);
+        }
+#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
+
+#if SDL_VIDEO_DRIVER_X11_XVIDMODE
+        if (!displaydata->use_xrandr &&
+#if SDL_VIDEO_DRIVER_X11_XINERAMA
+            (!displaydata->use_xinerama || displaydata->xinerama_info.screen_number == 0) &&
+#endif
+            use_vidmode) {
+            displaydata->use_vidmode = use_vidmode;
+            XF86VidModeGetModeInfo(data->display, screen, &modedata->vm_mode);
+        }
+#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
+
+        SDL_zero(display);
+        display.desktop_mode = mode;
+        display.current_mode = mode;
+        display.driverdata = displaydata;
+        SDL_AddVideoDisplay(&display);
+    }
+
+#if SDL_VIDEO_DRIVER_X11_XINERAMA
+    if (xinerama) XFree(xinerama);
+#endif
+
+    if (_this->num_displays == 0) {
+        SDL_SetError("No available displays");
+        return -1;
+    }
+    return 0;
 }
-*/
-#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
 
 void
 X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display)
 {
     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
-#if SDL_VIDEO_DRIVER_X11_XRANDR
-    int xrandr_major, xrandr_minor;
-    int nsizes, nrates;
-    XRRScreenSize *sizes;
-    short *rates;
-#endif
 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
-    int vm_major, vm_minor;
     int nmodes;
     XF86VidModeModeInfo ** modes;
 #endif
     int screen_w;
     int screen_h;
     SDL_DisplayMode mode;
+    SDL_DisplayModeData *modedata;
 
     /* Unfortunately X11 requires the window to be created with the correct
      * visual and depth ahead of time, but the SDL API allows you to create
@@ -500,69 +607,51 @@
             mode.w = screen_w;
             mode.h = screen_h;
             mode.refresh_rate = 0;
+            modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
+            if (modedata) {
+                *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
+            }
+            mode.driverdata = modedata;
             SDL_AddDisplayMode(sdl_display, &mode);
         }
-
-        /* Add the head xinerama mode */
-        mode.w = data->xinerama_info.width;
-        mode.h = data->xinerama_info.height;
-        mode.refresh_rate = 0;
-        SDL_AddDisplayMode(sdl_display, &mode);
     }
 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
 
 #if SDL_VIDEO_DRIVER_X11_XRANDR
-    /* XRandR */
-    /* require at least XRandR v1.0 (arbitrary) */
-    if (CheckXRandR(display, &xrandr_major, &xrandr_minor)
-        && xrandr_major >= 1) {
-#ifdef X11MODES_DEBUG
-        fprintf(stderr, "XRANDR: XRRQueryVersion: V%d.%d\n",
-                xrandr_major, xrandr_minor);
-#endif
+    if (data->use_xrandr) {
+        XRRScreenResources *res;
 
-        /* save the screen configuration since we must reference it
-           each time we toggle modes.
-         */
-        data->screen_config =
-            XRRGetScreenInfo(display, RootWindow(display, data->screen));
+        res = XRRGetScreenResources (display, RootWindow(display, data->screen));
+        if (res) {
+            SDL_DisplayModeData *modedata;
+            XRROutputInfo *output_info;
+            int i;
 
-        /* retrieve the list of resolution */
-        sizes = XRRConfigSizes(data->screen_config, &nsizes);
-        if (nsizes > 0) {
-            int i, j;
-            for (i = 0; i < nsizes; i++) {
-                mode.w = sizes[i].width;
-                mode.h = sizes[i].height;
+            output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
+            if (output_info && output_info->connection != RR_Disconnected) {
+                for (i = 0; i < output_info->nmode; ++i) {
+                    modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
+                    if (!modedata) {
+                        continue;
+                    }
+                    mode.driverdata = modedata;
 
-                rates = XRRConfigRates(data->screen_config, i, &nrates);
-                for (j = 0; j < nrates; ++j) {
-                    mode.refresh_rate = rates[j];
-#ifdef X11MODES_DEBUG
-                    fprintf(stderr,
-                            "XRANDR: mode = %4d[%d], w = %4d, h = %4d, rate = %4d\n",
-                            i, j, mode.w, mode.h, mode.refresh_rate);
-#endif
-                    SDL_AddDisplayMode(sdl_display, &mode);
+                    if (SetXRandRModeInfo(display, res, output_info, output_info->modes[i], &mode)) {
+                        SDL_AddDisplayMode(sdl_display, &mode);
+                    } else {
+                        SDL_free(modedata);
+                    }
                 }
             }
-
-            data->use_xrandr = xrandr_major * 100 + xrandr_minor;
-            data->saved_size =
-                XRRConfigCurrentConfiguration(data->screen_config,
-                                              &data->saved_rotation);
-            data->saved_rate = XRRConfigCurrentRate(data->screen_config);
+            XRRFreeOutputInfo(output_info);
+            XRRFreeScreenResources(res);
         }
+        return;
     }
 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
 
 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
-    /* XVidMode */
-    if (!data->use_xrandr &&
-#if SDL_VIDEO_DRIVER_X11_XINERAMA
-        (!data->use_xinerama || data->xinerama_info.screen_number == 0) &&
-#endif
-        CheckVidMode(display, &vm_major, &vm_minor) &&
+    if (data->use_vidmode &&
         XF86VidModeGetAllModeLines(display, data->screen, &nmodes, &modes)) {
         int i;
 
@@ -571,332 +660,37 @@
         for (i = 0; i < nmodes; ++i) {
             printf("Mode %d: %d x %d @ %d\n", i,
                    modes[i]->hdisplay, modes[i]->vdisplay,
-                   calculate_rate(modes[i]));
+                   CalculateXVidModeRefreshRate(modes[i]));
         }
 #endif
         for (i = 0; i < nmodes; ++i) {
-            mode.w = modes[i]->hdisplay;
-            mode.h = modes[i]->vdisplay;
-            mode.refresh_rate = calculate_rate(modes[i]);
-            SDL_AddDisplayMode(sdl_display, &mode);
+            modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
+            if (!modedata) {
+                continue;
+            }
+            mode.driverdata = modedata;
+
+            if (SetXVidModeModeInfo(modes[i], &mode)) {
+                SDL_AddDisplayMode(sdl_display, &mode);
+            } else {
+                SDL_free(modedata);
+            }
         }
         XFree(modes);
-
-        data->use_vidmode = vm_major * 100 + vm_minor;
-        save_mode(display, data);
+        return;
     }
 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
 
     if (!data->use_xrandr && !data->use_vidmode) {
-        mode.w = screen_w;
-        mode.h = screen_h;
-        mode.refresh_rate = 0;
+        /* Add the desktop mode */
+        mode = sdl_display->desktop_mode;
+        modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
+        if (modedata) {
+            *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
+        }
+        mode.driverdata = modedata;
         SDL_AddDisplayMode(sdl_display, &mode);
     }
-#ifdef X11MODES_DEBUG
-    if (data->use_xinerama) {
-        printf("Xinerama is enabled\n");
-    }
-
-    if (data->use_xrandr) {
-        printf("XRandR is enabled\n");
-    }
-
-    if (data->use_vidmode) {
-        printf("VidMode is enabled\n");
-    }
-#endif /* X11MODES_DEBUG */
-}
-
-static void
-get_real_resolution(Display * display, SDL_DisplayData * data, int *w, int *h,
-                    int *rate)
-{
-#if SDL_VIDEO_DRIVER_X11_XRANDR
-    if (data->use_xrandr) {
-        int nsizes;
-        XRRScreenSize *sizes;
-
-        sizes = XRRConfigSizes(data->screen_config, &nsizes);
-        if (nsizes > 0) {
-            int cur_size;
-            Rotation cur_rotation;
-
-            cur_size =
-                XRRConfigCurrentConfiguration(data->screen_config,
-                                              &cur_rotation);
-            *w = sizes[cur_size].width;
-            *h = sizes[cur_size].height;
-            *rate = XRRConfigCurrentRate(data->screen_config);
-#ifdef X11MODES_DEBUG
-            fprintf(stderr,
-                    "XRANDR: get_real_resolution: w = %d, h = %d, rate = %d\n",
-                    *w, *h, *rate);
-#endif
-            return;
-        }
-    }
-#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
-
-#if SDL_VIDEO_DRIVER_X11_XVIDMODE
-    if (data->use_vidmode) {
-        XF86VidModeModeInfo mode;
-
-        if (XF86VidModeGetModeInfo(display, data->screen, &mode)) {
-            *w = mode.hdisplay;
-            *h = mode.vdisplay;
-            *rate = calculate_rate(&mode);
-            return;
-        }
-    }
-#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
-
-#if SDL_VIDEO_DRIVER_X11_XINERAMA
-    if (data->use_xinerama) {
-        int screencount;
-        XineramaScreenInfo *xinerama;
-
-        /* Update the current screen layout information */
-        xinerama = XineramaQueryScreens(display, &screencount);
-        if (xinerama && data->xinerama_screen < screencount) {
-            data->xinerama_info = xinerama[data->xinerama_screen];
-        }
-        if (xinerama) XFree(xinerama);
-
-        *w = data->xinerama_info.width;
-        *h = data->xinerama_info.height;
-        *rate = 0;
-        return;
-    }
-#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
-
-    *w = DisplayWidth(display, data->screen);
-    *h = DisplayHeight(display, data->screen);
-    *rate = 0;
-}
-
-static void
-set_best_resolution(Display * display, SDL_DisplayData * data, int w, int h,
-                    int rate)
-{
-    int real_w, real_h, real_rate;
-
-    /* check current mode so we can avoid uneccessary mode changes */
-    get_real_resolution(display, data, &real_w, &real_h, &real_rate);
-
-    if (w == real_w && h == real_h && (!rate || !real_rate || rate == real_rate)) {
-        return;
-    }
-
-#if SDL_VIDEO_DRIVER_X11_XRANDR
-    if (data->use_xrandr) {
-#ifdef X11MODES_DEBUG
-        fprintf(stderr, "XRANDR: set_best_resolution(): w = %d, h = %d\n",
-                w, h);
-#endif
-        int i, nsizes, nrates;
-        int best;
-        int best_rate;
-        XRRScreenSize *sizes;
-        short *rates;
-
-#if SDL_VIDEO_DRIVER_X11_XINERAMA
-        if (data->use_xrandr >= 102 && data->use_xinerama) {
-            /* See http://cgit.freedesktop.org/xorg/app/xrandr/tree/xrandr.c for the rationale behind this */
-            /* Note by Gabriel: the refresh rate is ignored in this code, and seeing that both xrandr
-             * and nvidia-settings don't provide a way to set it when Xinerama is enabled, it may not be possible to set it */
-            int screencount;
-            XineramaScreenInfo * xinerama = NULL;
-            XRRScreenResources  *res;
-
-            /* Update the current screen layout information */
-            xinerama = XineramaQueryScreens(display, &screencount);
-            if (xinerama && data->xinerama_screen < screencount) {
-                data->xinerama_info = xinerama[data->xinerama_screen];
-            }
-            if (xinerama) XFree(xinerama);
-
-            res = XRRGetScreenResources (display, RootWindow(display, data->screen));
-            if (res) {
-                XRROutputInfo *output_info = NULL;
-                XRRCrtcInfo *crtc = NULL;
-                XRRModeInfo *mode_info, *best_mode_info = NULL;
-                int mode_index = 0, output_mode_index = 0, output;
-                int mode_w, mode_h, best_w = 0, best_h = 0;
-
-                for ( output = 0; output < res->noutput; output++) {
-                    output_info = XRRGetOutputInfo (display, res, res->outputs[output]);
-                    if (!output_info || !output_info->crtc) {
-                        XRRFreeOutputInfo(output_info);
-                        continue;
-                    }
-
-                    crtc = XRRGetCrtcInfo (display, res, output_info->crtc);
-                    if (!crtc || data->xinerama_info.x_org != crtc->x || data->xinerama_info.y_org != crtc->y) {
-                        XRRFreeCrtcInfo(crtc);
-                        continue;
-                    }
-
-                    /* The CRT offset matches the Xinerama mode, let's hope it's the right one! */
-#ifdef X11MODES_DEBUG
-                    fprintf(stderr, "XRANDR: set_best_resolution, matched Xinerama screen %d to CRT %ld at %d,%d\n",
-                        data->xinerama_info.screen_number, output_info->crtc, crtc->x, crtc->y);
-#endif
-                    /* Find out the best mode we can use */
-                    for (mode_index = 0; mode_index < res->nmode; mode_index++) {
-                        mode_info = &res->modes[mode_index];
-                        get_xrandr_mode_size(mode_info, crtc->rotation, &mode_w, &mode_h);
-                        if (mode_w >= w && mode_h >= h) {
-                            /* This may be a useful mode, check out if it belongs to the correct output */
-#ifdef X11MODES_DEBUG
-                            fprintf(stderr, "Evaluating valid mode %d, w: %d, h: %d\n", mode_index, mode_info->width, mode_info->height);
-#endif
-                            for ( output_mode_index = 0; output_mode_index < output_info->nmode; output_mode_index++) {
-                                if (output_info->modes[output_mode_index] == mode_info->id) {
-                                    break;
-                                }
-                            }
-                            if (output_mode_index < output_info->nmode) {
-#ifdef X11MODES_DEBUG
-                                fprintf(stderr, "Mode belongs to the desired output %d w: %d, h: %d, rotation: %x\n", mode_index, mode_info->width, mode_info->height, crtc->rotation);
-#endif
-                                /* We have a mode that belongs to the right output and that can contain the w,h required, see if it's smaller than the current one */
-                                if ( !best_mode_info || mode_w < best_w || (mode_w == best_w && mode_h < best_h) ) {
-                                    best_mode_info = mode_info;
-                                    best_w = mode_w;
-                                    best_h = mode_h;
-                                }
-                            }
-#ifdef X11MODES_DEBUG
-                            else {
-                                fprintf(stderr, "Discarding mode because it does not belong to the desired output %d, w: %d, h: %d, rotation: %d\n", mode_index, mode_info->width, mode_info->height, crtc->rotation);
-                            }
-#endif
-                        }
-                    }
-
-                    if (best_mode_info) {
-#ifdef X11MODES_DEBUG
-                            fprintf(stderr, "XRANDR: set_best_resolution, setting mode w = %d, h = %d on output: %d, CRT with offsets: %d,%d for Xinerama screen: %d\n",
-                                    best_mode_info->width, best_mode_info->height, output, crtc->x, crtc->y, data->xinerama_info.screen_number);
-#endif
-                        XGrabServer (display);
-                        XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
-                          crtc->x, crtc->y, best_mode_info->id, crtc->rotation,
-                          &res->outputs[output], 1);
-                        /* TODO: Handle screen rotations, should we call XRRSetCrtcTransform if Xrandr >=1.3 ? */
-                        XUngrabServer (display);
-                    } else {
-                        /* If we reach here, we have found the right screen but no valid best mode */
-                        SDL_SetError("The selected screen can't support a resolution of the size desired");
-                    }
-                    XRRFreeCrtcInfo(crtc);
-                    XRRFreeOutputInfo(output_info);
-                    break;
-                }
-                XRRFreeScreenResources(res);
-            }
-        }
-        else
-#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
-        {
-            /* Use older xrandr functions that don't play along very nicely with multi monitors setups */
-            /* find the smallest resolution that is at least as big as the user requested */
-            best = -1;
-            sizes = XRRConfigSizes(data->screen_config, &nsizes);
-            for (i = 0; i < nsizes; ++i) {
-                if (sizes[i].width < w || sizes[i].height < h) {
-                    continue;
-                }
-                if (sizes[i].width == w && sizes[i].height == h) {
-                    best = i;
-                    break;
-                }
-                if (best == -1 ||
-                    (sizes[i].width < sizes[best].width) ||
-                    (sizes[i].width == sizes[best].width
-                     && sizes[i].height < sizes[best].height)) {
-                    best = i;
-                }
-            }
-
-            if (best >= 0) {
-                best_rate = 0;
-                rates = XRRConfigRates(data->screen_config, best, &nrates);
-                for (i = 0; i < nrates; ++i) {
-                    if (rates[i] == rate) {
-                        best_rate = rate;
-                        break;
-                    }
-                    if (!rate) {
-                        /* Higher is better, right? */
-                        if (rates[i] > best_rate) {
-                            best_rate = rates[i];
-                        }
-                    } else {
-                        if (SDL_abs(rates[i] - rate) < SDL_abs(best_rate - rate)) {
-                            best_rate = rates[i];
-                        }
-                    }
-                }
-                XRRSetScreenConfigAndRate(display, data->screen_config,
-                                          RootWindow(display, data->screen), best,
-                                          data->saved_rotation, best_rate,
-                                          CurrentTime);
-            }
-        }
-        return;
-    }
-#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
-
-#if SDL_VIDEO_DRIVER_X11_XVIDMODE
-    if (data->use_vidmode) {
-        XF86VidModeModeInfo ** modes;
-        int i, nmodes;
-        int best;
-
-        if (XF86VidModeGetAllModeLines(display, data->screen, &nmodes, &modes)) {
-            best = -1;
-            for (i = 0; i < nmodes; ++i) {
-                if (modes[i]->hdisplay < w || modes[i]->vdisplay < h) {
-                    continue;
-                }
-                if (best == -1 ||
-                    (modes[i]->hdisplay < modes[best]->hdisplay) ||
-                    (modes[i]->hdisplay == modes[best]->hdisplay
-                     && modes[i]->vdisplay < modes[best]->vdisplay)) {
-                    best = i;
-                    continue;
-                }
-                if ((modes[i]->hdisplay == modes[best]->hdisplay) &&
-                    (modes[i]->vdisplay == modes[best]->vdisplay)) {
-                    if (!rate) {
-                        /* Higher is better, right? */
-                        if (calculate_rate(modes[i]) >
-                            calculate_rate(modes[best])) {
-                            best = i;
-                        }
-                    } else {
-                        if (SDL_abs(calculate_rate(modes[i]) - rate) <
-                            SDL_abs(calculate_rate(modes[best]) - rate)) {
-                            best = i;
-                        }
-                    }
-                }
-            }
-            if (best >= 0) {
-#ifdef X11MODES_DEBUG
-                printf("Best Mode %d: %d x %d @ %d\n", best,
-                       modes[best]->hdisplay, modes[best]->vdisplay,
-                       calculate_rate(modes[best]));
-#endif
-                XF86VidModeSwitchToMode(display, data->screen, modes[best]);
-            }
-            XFree(modes);
-        }
-        return;
-    }
-#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
 }
 
 int
@@ -904,8 +698,57 @@
 {
     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
+    SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
 
-    set_best_resolution(display, data, mode->w, mode->h, mode->refresh_rate);
+#if SDL_VIDEO_DRIVER_X11_XRANDR
+    if (data->use_xrandr) {
+        XRRScreenResources *res;
+        XRROutputInfo *output_info;
+        XRRCrtcInfo *crtc;
+        Status status;
+
+        res = XRRGetScreenResources (display, RootWindow(display, data->screen));
+        if (!res) {
+            SDL_SetError("Couldn't get XRandR screen resources");
+            return -1;
+        }
+
+        output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
+        if (!output_info || output_info->connection == RR_Disconnected) {
+            SDL_SetError("Couldn't get XRandR output info");
+            XRRFreeScreenResources(res);
+            return -1;
+        }
+
+        crtc = XRRGetCrtcInfo(display, res, output_info->crtc);
+        if (!crtc) {
+            SDL_SetError("Couldn't get XRandR crtc info");
+            XRRFreeOutputInfo(output_info);
+            XRRFreeScreenResources(res);
+            return -1;
+        }
+
+        status = XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
+          crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation,
+          &data->xrandr_output, 1);
+
+        XRRFreeCrtcInfo(crtc);
+        XRRFreeOutputInfo(output_info);
+        XRRFreeScreenResources(res);
+
+        if (status != Success) {
+            SDL_SetError("XRRSetCrtcConfig failed");
+            return -1;
+        }
+    }
+#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
+
+#if SDL_VIDEO_DRIVER_X11_XVIDMODE
+    if (data->use_vidmode) {
+        XF86VidModeSwitchToMode(display, data->screen, &modedata->vm_mode);
+    }
+#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
+
     return 0;
 }
 
@@ -919,18 +762,23 @@
 {
     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
-    int real_rate;
 
-    rect->x = 0;
-    rect->y = 0;
-    get_real_resolution(display, data, &rect->w, &rect->h, &real_rate);
+    rect->x = data->x;
+    rect->y = data->y;
+    rect->w = sdl_display->current_mode.w;
+    rect->h = sdl_display->current_mode.h;
 
 #if SDL_VIDEO_DRIVER_X11_XINERAMA
+    /* Get the real current bounds of the display */
     if (data->use_xinerama) {
-        rect->x = data->xinerama_info.x_org;
-        rect->y = data->xinerama_info.y_org;
+        int screencount;
+        XineramaScreenInfo *xinerama = XineramaQueryScreens(display, &screencount);
+        if (xinerama) {
+            rect->x = xinerama[data->xinerama_screen].x_org;
+            rect->y = xinerama[data->xinerama_screen].y_org;
+        }
     }
-#endif
+#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
     return 0;
 }
 
--- a/src/video/x11/SDL_x11modes.h	Wed Oct 03 18:54:31 2012 -0700
+++ b/src/video/x11/SDL_x11modes.h	Wed Oct 03 18:56:29 2012 -0700
@@ -29,6 +29,8 @@
     Visual *visual;
     int depth;
     int scanline_pad;
+    int x;
+    int y;
 
     int use_xinerama;
     int use_xrandr;
@@ -38,22 +40,25 @@
     XineramaScreenInfo xinerama_info;
     int xinerama_screen;
 #endif
+
 #if SDL_VIDEO_DRIVER_X11_XRANDR
-    XRRScreenConfiguration *screen_config;
-    int saved_size;
-    Rotation saved_rotation;
-    short saved_rate;
-#endif
-#if SDL_VIDEO_DRIVER_X11_XVIDMODE
-    XF86VidModeModeInfo saved_mode;
-    struct
-    {
-        int x, y;
-    } saved_view;
+    RROutput xrandr_output;
 #endif
 
 } SDL_DisplayData;
 
+typedef struct
+{
+#if SDL_VIDEO_DRIVER_X11_XRANDR
+    RRMode xrandr_mode;
+#endif
+
+#if SDL_VIDEO_DRIVER_X11_XVIDMODE
+    XF86VidModeModeInfo vm_mode;
+#endif
+
+} SDL_DisplayModeData;
+
 extern int X11_InitModes(_THIS);
 extern void X11_GetDisplayModes(_THIS, SDL_VideoDisplay * display);
 extern int X11_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);