src/video/x11/SDL_x11modes.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 03 Oct 2012 19:02:46 -0700
changeset 6549 db16b819e1d1
parent 6548 fc9e6be24ca9
child 6550 191f00a080ba
permissions -rw-r--r--
Added a delay hack to let the window manager adjust to the mode change. I'm not sure if this is a good idea, but at least it works sometimes now. :)
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_X11
    24 
    25 #include "SDL_hints.h"
    26 #include "SDL_x11video.h"
    27 
    28 /*#define X11MODES_DEBUG*/
    29 
    30 static int
    31 get_visualinfo(Display * display, int screen, XVisualInfo * vinfo)
    32 {
    33     const char *visual_id = SDL_getenv("SDL_VIDEO_X11_VISUALID");
    34     int depth;
    35 
    36     /* Look for an exact visual, if requested */
    37     if (visual_id) {
    38         XVisualInfo *vi, template;
    39         int nvis;
    40 
    41         SDL_zero(template);
    42         template.visualid = SDL_strtol(visual_id, NULL, 0);
    43         vi = XGetVisualInfo(display, VisualIDMask, &template, &nvis);
    44         if (vi) {
    45             *vinfo = *vi;
    46             XFree(vi);
    47             return 0;
    48         }
    49     }
    50 
    51     depth = DefaultDepth(display, screen);
    52     if ((X11_UseDirectColorVisuals() &&
    53          XMatchVisualInfo(display, screen, depth, DirectColor, vinfo)) ||
    54         XMatchVisualInfo(display, screen, depth, TrueColor, vinfo) ||
    55         XMatchVisualInfo(display, screen, depth, PseudoColor, vinfo) ||
    56         XMatchVisualInfo(display, screen, depth, StaticColor, vinfo)) {
    57         return 0;
    58     }
    59     return -1;
    60 }
    61 
    62 int
    63 X11_GetVisualInfoFromVisual(Display * display, Visual * visual, XVisualInfo * vinfo)
    64 {
    65     XVisualInfo *vi;
    66     int nvis;
    67 
    68     vinfo->visualid = XVisualIDFromVisual(visual);
    69     vi = XGetVisualInfo(display, VisualIDMask, vinfo, &nvis);
    70     if (vi) {
    71         *vinfo = *vi;
    72         XFree(vi);
    73         return 0;
    74     }
    75     return -1;
    76 }
    77 
    78 Uint32
    79 X11_GetPixelFormatFromVisualInfo(Display * display, XVisualInfo * vinfo)
    80 {
    81     if (vinfo->class == DirectColor || vinfo->class == TrueColor) {
    82         int bpp;
    83         Uint32 Rmask, Gmask, Bmask, Amask;
    84 
    85         Rmask = vinfo->visual->red_mask;
    86         Gmask = vinfo->visual->green_mask;
    87         Bmask = vinfo->visual->blue_mask;
    88         if (vinfo->depth == 32) {
    89             Amask = (0xFFFFFFFF & ~(Rmask | Gmask | Bmask));
    90         } else {
    91             Amask = 0;
    92         }
    93 
    94         bpp = vinfo->depth;
    95         if (bpp == 24) {
    96             int i, n;
    97             XPixmapFormatValues *p = XListPixmapFormats(display, &n);
    98             if (p) {
    99                 for (i = 0; i < n; ++i) {
   100                     if (p[i].depth == 24) {
   101                         bpp = p[i].bits_per_pixel;
   102                         break;
   103                     }
   104                 }
   105                 XFree(p);
   106             }
   107         }
   108 
   109         return SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
   110     }
   111 
   112     if (vinfo->class == PseudoColor || vinfo->class == StaticColor) {
   113         switch (vinfo->depth) {
   114         case 8:
   115             return SDL_PIXELTYPE_INDEX8;
   116         case 4:
   117             if (BitmapBitOrder(display) == LSBFirst) {
   118                 return SDL_PIXELFORMAT_INDEX4LSB;
   119             } else {
   120                 return SDL_PIXELFORMAT_INDEX4MSB;
   121             }
   122             break;
   123         case 1:
   124             if (BitmapBitOrder(display) == LSBFirst) {
   125                 return SDL_PIXELFORMAT_INDEX1LSB;
   126             } else {
   127                 return SDL_PIXELFORMAT_INDEX1MSB;
   128             }
   129             break;
   130         }
   131     }
   132 
   133     return SDL_PIXELFORMAT_UNKNOWN;
   134 }
   135 
   136 /* Global for the error handler */
   137 int vm_event, vm_error = -1;
   138 
   139 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   140 static SDL_bool
   141 CheckXinerama(Display * display, int *major, int *minor)
   142 {
   143     int event_base = 0;
   144     int error_base = 0;
   145     const char *env;
   146 
   147     /* Default the extension not available */
   148     *major = *minor = 0;
   149 
   150     /* Allow environment override */
   151     env = SDL_GetHint(SDL_HINT_VIDEO_X11_XINERAMA);
   152     if (env && !SDL_atoi(env)) {
   153 #ifdef X11MODES_DEBUG
   154         printf("Xinerama disabled due to hint\n");
   155 #endif
   156         return SDL_FALSE;
   157     }
   158 
   159     if (!SDL_X11_HAVE_XINERAMA) {
   160 #ifdef X11MODES_DEBUG
   161         printf("Xinerama support not available\n");
   162 #endif
   163         return SDL_FALSE;
   164     }
   165 
   166     /* Query the extension version */
   167     if (!XineramaQueryExtension(display, &event_base, &error_base) ||
   168         !XineramaQueryVersion(display, major, minor) ||
   169         !XineramaIsActive(display)) {
   170 #ifdef X11MODES_DEBUG
   171         printf("Xinerama not active on the display\n");
   172 #endif
   173         return SDL_FALSE;
   174     }
   175 #ifdef X11MODES_DEBUG
   176     printf("Xinerama available at version %d.%d!\n", *major, *minor);
   177 #endif
   178     return SDL_TRUE;
   179 }
   180 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   181 
   182 #if SDL_VIDEO_DRIVER_X11_XRANDR
   183 static SDL_bool
   184 CheckXRandR(Display * display, int *major, int *minor)
   185 {
   186     const char *env;
   187 
   188     /* Default the extension not available */
   189     *major = *minor = 0;
   190 
   191     /* Allow environment override */
   192     env = SDL_GetHint(SDL_HINT_VIDEO_X11_XRANDR);
   193     if (env && !SDL_atoi(env)) {
   194 #ifdef X11MODES_DEBUG
   195         printf("XRandR disabled due to hint\n");
   196 #endif
   197         return SDL_FALSE;
   198     }
   199 
   200     if (!SDL_X11_HAVE_XRANDR) {
   201 #ifdef X11MODES_DEBUG
   202         printf("XRandR support not available\n");
   203 #endif
   204         return SDL_FALSE;
   205     }
   206 
   207     /* Query the extension version */
   208     if (!XRRQueryVersion(display, major, minor)) {
   209 #ifdef X11MODES_DEBUG
   210         printf("XRandR not active on the display\n");
   211 #endif
   212         return SDL_FALSE;
   213     }
   214 #ifdef X11MODES_DEBUG
   215     printf("XRandR available at version %d.%d!\n", *major, *minor);
   216 #endif
   217     return SDL_TRUE;
   218 }
   219 
   220 #define XRANDR_ROTATION_LEFT    (1 << 1)
   221 #define XRANDR_ROTATION_RIGHT   (1 << 3)
   222 
   223 static int
   224 CalculateXRandRRefreshRate(const XRRModeInfo *info)
   225 {
   226     return (info->hTotal
   227             && info->vTotal) ? (1000 * info->dotClock / (info->hTotal *
   228                                                          info->vTotal)) : 0;
   229 }
   230 
   231 static SDL_bool
   232 SetXRandRModeInfo(Display *display, XRRScreenResources *res, XRROutputInfo *output_info,
   233                   RRMode modeID, SDL_DisplayMode *mode)
   234 {
   235     int i;
   236     for (i = 0; i < res->nmode; ++i) {
   237         if (res->modes[i].id == modeID) {
   238             XRRCrtcInfo *crtc;
   239             Rotation rotation = 0;
   240             const XRRModeInfo *info = &res->modes[i];
   241 
   242             crtc = XRRGetCrtcInfo(display, res, output_info->crtc);
   243             if (crtc) {
   244                 rotation = crtc->rotation;
   245                 XRRFreeCrtcInfo(crtc);
   246             }
   247 
   248             if (rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) {
   249                 mode->w = info->height;
   250                 mode->h = info->width;
   251             } else {
   252                 mode->w = info->width;
   253                 mode->h = info->height;
   254             }
   255             mode->refresh_rate = CalculateXRandRRefreshRate(info);
   256             ((SDL_DisplayModeData*)mode->driverdata)->xrandr_mode = modeID;
   257 #ifdef X11MODES_DEBUG
   258             printf("XRandR mode %d: %dx%d@%dHz\n", modeID, mode->w, mode->h, mode->refresh_rate);
   259 #endif
   260             return SDL_TRUE;
   261         }
   262     }
   263     return SDL_FALSE;
   264 }
   265 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   266 
   267 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   268 static SDL_bool
   269 CheckVidMode(Display * display, int *major, int *minor)
   270 {
   271     const char *env;
   272 
   273     /* Default the extension not available */
   274     *major = *minor = 0;
   275 
   276     /* Allow environment override */
   277     env = SDL_GetHint(SDL_HINT_VIDEO_X11_XVIDMODE);
   278     if (env && !SDL_atoi(env)) {
   279 #ifdef X11MODES_DEBUG
   280         printf("XVidMode disabled due to hint\n");
   281 #endif
   282         return SDL_FALSE;
   283     }
   284 
   285     if (!SDL_X11_HAVE_XVIDMODE) {
   286 #ifdef X11MODES_DEBUG
   287         printf("XVidMode support not available\n");
   288 #endif
   289         return SDL_FALSE;
   290     }
   291 
   292     /* Query the extension version */
   293     vm_error = -1;
   294     if (!XF86VidModeQueryExtension(display, &vm_event, &vm_error)
   295         || !XF86VidModeQueryVersion(display, major, minor)) {
   296 #ifdef X11MODES_DEBUG
   297         printf("XVidMode not active on the display\n");
   298 #endif
   299         return SDL_FALSE;
   300     }
   301 #ifdef X11MODES_DEBUG
   302     printf("XVidMode available at version %d.%d!\n", *major, *minor);
   303 #endif
   304     return SDL_TRUE;
   305 }
   306 
   307 static
   308 Bool XF86VidModeGetModeInfo(Display * dpy, int scr,
   309                                        XF86VidModeModeInfo* info)
   310 {
   311     Bool retval;
   312     int dotclock;
   313     XF86VidModeModeLine l;
   314     SDL_zerop(info);
   315     SDL_zero(l);
   316     retval = XF86VidModeGetModeLine(dpy, scr, &dotclock, &l);
   317     info->dotclock = dotclock;
   318     info->hdisplay = l.hdisplay;
   319     info->hsyncstart = l.hsyncstart;
   320     info->hsyncend = l.hsyncend;
   321     info->htotal = l.htotal;
   322     info->hskew = l.hskew;
   323     info->vdisplay = l.vdisplay;
   324     info->vsyncstart = l.vsyncstart;
   325     info->vsyncend = l.vsyncend;
   326     info->vtotal = l.vtotal;
   327     info->flags = l.flags;
   328     info->privsize = l.privsize;
   329     info->private = l.private;
   330     return retval;
   331 }
   332 
   333 static int
   334 CalculateXVidModeRefreshRate(const XF86VidModeModeInfo * info)
   335 {
   336     return (info->htotal
   337             && info->vtotal) ? (1000 * info->dotclock / (info->htotal *
   338                                                          info->vtotal)) : 0;
   339 }
   340 
   341 SDL_bool
   342 SetXVidModeModeInfo(const XF86VidModeModeInfo *info, SDL_DisplayMode *mode)
   343 {
   344     mode->w = info->hdisplay;
   345     mode->h = info->vdisplay;
   346     mode->refresh_rate = CalculateXVidModeRefreshRate(info);
   347     ((SDL_DisplayModeData*)mode->driverdata)->vm_mode = *info;
   348     return SDL_TRUE;
   349 }
   350 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   351 
   352 int
   353 X11_InitModes(_THIS)
   354 {
   355     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   356     int screen, screencount;
   357 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   358     int xinerama_major, xinerama_minor;
   359     int use_xinerama = 0;
   360     XineramaScreenInfo *xinerama = NULL;
   361 #endif
   362 #if SDL_VIDEO_DRIVER_X11_XRANDR
   363     int xrandr_major, xrandr_minor;
   364     int use_xrandr = 0;
   365     XRRScreenResources *res = NULL;
   366 #endif
   367 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   368     int vm_major, vm_minor;
   369     int use_vidmode = 0;
   370 #endif
   371 
   372 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   373     /* Query Xinerama extention
   374      * NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012)
   375      *       or newer of the Nvidia binary drivers
   376      */
   377     if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) {
   378         xinerama = XineramaQueryScreens(data->display, &screencount);
   379         if (xinerama) {
   380             use_xinerama = xinerama_major * 100 + xinerama_minor;
   381         }
   382     }
   383     if (!xinerama) {
   384         screencount = ScreenCount(data->display);
   385     }
   386 #else
   387     screencount = ScreenCount(data->display);
   388 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   389 
   390 #if SDL_VIDEO_DRIVER_X11_XRANDR
   391     /* require at least XRandR v1.2 */
   392     if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) &&
   393         (xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 2))) {
   394         use_xrandr = xrandr_major * 100 + xrandr_minor;
   395     }
   396 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   397 
   398 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   399     if (CheckVidMode(data->display, &vm_major, &vm_minor)) {
   400         use_vidmode = vm_major * 100 + vm_minor;
   401     }
   402 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   403 
   404     for (screen = 0; screen < screencount; ++screen) {
   405         XVisualInfo vinfo;
   406         SDL_VideoDisplay display;
   407         SDL_DisplayData *displaydata;
   408         SDL_DisplayMode mode;
   409         SDL_DisplayModeData *modedata;
   410         XPixmapFormatValues *pixmapFormats;
   411         int i, n;
   412 
   413 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   414         if (xinerama) {
   415             if (get_visualinfo(data->display, 0, &vinfo) < 0) {
   416                 continue;
   417             }
   418         } else {
   419             if (get_visualinfo(data->display, screen, &vinfo) < 0) {
   420                 continue;
   421             }
   422         }
   423 #else
   424         if (get_visualinfo(data->display, screen, &vinfo) < 0) {
   425             continue;
   426         }
   427 #endif
   428 
   429         displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
   430         if (!displaydata) {
   431             continue;
   432         }
   433 
   434         mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
   435         if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
   436             /* We don't support palettized modes now */
   437             SDL_free(displaydata);
   438             continue;
   439         }
   440 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   441         if (xinerama) {
   442             mode.w = xinerama[screen].width;
   443             mode.h = xinerama[screen].height;
   444         } else {
   445             mode.w = DisplayWidth(data->display, screen);
   446             mode.h = DisplayHeight(data->display, screen);
   447         }
   448 #else
   449         mode.w = DisplayWidth(data->display, screen);
   450         mode.h = DisplayHeight(data->display, screen);
   451 #endif
   452         mode.refresh_rate = 0;
   453 
   454         modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   455         if (!modedata) {
   456             SDL_free(displaydata);
   457             continue;
   458         }
   459         mode.driverdata = modedata;
   460 
   461 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   462         /* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active,
   463          * there's only one screen available. So we force the screen number to zero and
   464          * let Xinerama specific code handle specific functionality using displaydata->xinerama_info
   465          */
   466         if (use_xinerama) {
   467             displaydata->screen = 0;
   468             displaydata->use_xinerama = use_xinerama;
   469             displaydata->xinerama_info = xinerama[screen];
   470             displaydata->xinerama_screen = screen;
   471         }
   472         else displaydata->screen = screen;
   473 #else
   474         displaydata->screen = screen;
   475 #endif
   476         displaydata->visual = vinfo.visual;
   477         displaydata->depth = vinfo.depth;
   478 
   479         displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8;
   480         pixmapFormats = XListPixmapFormats(data->display, &n);
   481         if (pixmapFormats) {
   482             for (i = 0; i < n; ++i) {
   483                 if (pixmapFormats[i].depth == displaydata->depth) {
   484                     displaydata->scanline_pad = pixmapFormats[i].scanline_pad;
   485                     break;
   486                 }
   487             }
   488             XFree(pixmapFormats);
   489         }
   490 
   491 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   492         if (use_xinerama) {
   493             displaydata->x = xinerama[screen].x_org;
   494             displaydata->y = xinerama[screen].y_org;
   495         }
   496         else
   497 #endif
   498         {
   499             displaydata->x = 0;
   500             displaydata->y = 0;
   501         }
   502 
   503 #if SDL_VIDEO_DRIVER_X11_XRANDR
   504         if (use_xrandr) {
   505             res = XRRGetScreenResources(data->display, RootWindow(data->display, displaydata->screen));
   506         }
   507         if (res) {
   508             XRROutputInfo *output_info;
   509             XRRCrtcInfo *crtc;
   510             int output;
   511 
   512             for (output = 0; output < res->noutput; output++) {
   513                 output_info = XRRGetOutputInfo(data->display, res, res->outputs[output]);
   514                 if (!output_info || output_info->connection == RR_Disconnected) {
   515                     XRRFreeOutputInfo(output_info);
   516                     continue;
   517                 }
   518 
   519                 /* Is this the output that corresponds to the current screen?
   520                    We're checking the crtc position, but that may not be a valid test
   521                    in all cases.  Anybody want to give this some love?
   522                  */
   523                 crtc = XRRGetCrtcInfo(data->display, res, output_info->crtc);
   524                 if (!crtc || crtc->x != displaydata->x || crtc->y != displaydata->y) {
   525                     XRRFreeOutputInfo(output_info);
   526                     XRRFreeCrtcInfo(crtc);
   527                     continue;
   528                 }
   529 
   530                 displaydata->use_xrandr = use_xrandr;
   531                 displaydata->xrandr_output = res->outputs[output];
   532                 SetXRandRModeInfo(data->display, res, output_info, crtc->mode, &mode);
   533 
   534                 XRRFreeOutputInfo(output_info);
   535                 XRRFreeCrtcInfo(crtc);
   536                 break;
   537             }
   538 #ifdef X11MODES_DEBUG
   539             if (output == res->noutput) {
   540                 printf("Couldn't find XRandR CRTC at %d,%d\n", displaydata->x, displaydata->y);
   541             }
   542 #endif
   543             XRRFreeScreenResources(res);
   544         }
   545 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   546 
   547 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   548         if (!displaydata->use_xrandr &&
   549 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   550             (!displaydata->use_xinerama || displaydata->xinerama_info.screen_number == 0) &&
   551 #endif
   552             use_vidmode) {
   553             displaydata->use_vidmode = use_vidmode;
   554             XF86VidModeGetModeInfo(data->display, screen, &modedata->vm_mode);
   555         }
   556 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   557 
   558         SDL_zero(display);
   559         display.desktop_mode = mode;
   560         display.current_mode = mode;
   561         display.driverdata = displaydata;
   562         SDL_AddVideoDisplay(&display);
   563     }
   564 
   565 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   566     if (xinerama) XFree(xinerama);
   567 #endif
   568 
   569     if (_this->num_displays == 0) {
   570         SDL_SetError("No available displays");
   571         return -1;
   572     }
   573     return 0;
   574 }
   575 
   576 void
   577 X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display)
   578 {
   579     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   580     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   581 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   582     int nmodes;
   583     XF86VidModeModeInfo ** modes;
   584 #endif
   585     int screen_w;
   586     int screen_h;
   587     SDL_DisplayMode mode;
   588     SDL_DisplayModeData *modedata;
   589 
   590     /* Unfortunately X11 requires the window to be created with the correct
   591      * visual and depth ahead of time, but the SDL API allows you to create
   592      * a window before setting the fullscreen display mode.  This means that
   593      * we have to use the same format for all windows and all display modes.
   594      * (or support recreating the window with a new visual behind the scenes)
   595      */
   596     mode.format = sdl_display->current_mode.format;
   597     mode.driverdata = NULL;
   598 
   599     screen_w = DisplayWidth(display, data->screen);
   600     screen_h = DisplayHeight(display, data->screen);
   601 
   602 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   603     if (data->use_xinerama) {
   604         /* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0 */
   605         if (!data->xinerama_info.x_org && !data->xinerama_info.y_org &&
   606            (screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) {
   607             mode.w = screen_w;
   608             mode.h = screen_h;
   609             mode.refresh_rate = 0;
   610             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   611             if (modedata) {
   612                 *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   613             }
   614             mode.driverdata = modedata;
   615             SDL_AddDisplayMode(sdl_display, &mode);
   616         }
   617     }
   618 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   619 
   620 #if SDL_VIDEO_DRIVER_X11_XRANDR
   621     if (data->use_xrandr) {
   622         XRRScreenResources *res;
   623 
   624         res = XRRGetScreenResources (display, RootWindow(display, data->screen));
   625         if (res) {
   626             SDL_DisplayModeData *modedata;
   627             XRROutputInfo *output_info;
   628             int i;
   629 
   630             output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
   631             if (output_info && output_info->connection != RR_Disconnected) {
   632                 for (i = 0; i < output_info->nmode; ++i) {
   633                     modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   634                     if (!modedata) {
   635                         continue;
   636                     }
   637                     mode.driverdata = modedata;
   638 
   639                     if (SetXRandRModeInfo(display, res, output_info, output_info->modes[i], &mode)) {
   640                         SDL_AddDisplayMode(sdl_display, &mode);
   641                     } else {
   642                         SDL_free(modedata);
   643                     }
   644                 }
   645             }
   646             XRRFreeOutputInfo(output_info);
   647             XRRFreeScreenResources(res);
   648         }
   649         return;
   650     }
   651 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   652 
   653 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   654     if (data->use_vidmode &&
   655         XF86VidModeGetAllModeLines(display, data->screen, &nmodes, &modes)) {
   656         int i;
   657 
   658 #ifdef X11MODES_DEBUG
   659         printf("VidMode modes: (unsorted)\n");
   660         for (i = 0; i < nmodes; ++i) {
   661             printf("Mode %d: %d x %d @ %d\n", i,
   662                    modes[i]->hdisplay, modes[i]->vdisplay,
   663                    CalculateXVidModeRefreshRate(modes[i]));
   664         }
   665 #endif
   666         for (i = 0; i < nmodes; ++i) {
   667             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   668             if (!modedata) {
   669                 continue;
   670             }
   671             mode.driverdata = modedata;
   672 
   673             if (SetXVidModeModeInfo(modes[i], &mode)) {
   674                 SDL_AddDisplayMode(sdl_display, &mode);
   675             } else {
   676                 SDL_free(modedata);
   677             }
   678         }
   679         XFree(modes);
   680         return;
   681     }
   682 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   683 
   684     if (!data->use_xrandr && !data->use_vidmode) {
   685         /* Add the desktop mode */
   686         mode = sdl_display->desktop_mode;
   687         modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   688         if (modedata) {
   689             *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   690         }
   691         mode.driverdata = modedata;
   692         SDL_AddDisplayMode(sdl_display, &mode);
   693     }
   694 }
   695 
   696 int
   697 X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode)
   698 {
   699     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   700     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   701     SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
   702 
   703 #if SDL_VIDEO_DRIVER_X11_XRANDR
   704     if (data->use_xrandr) {
   705         XRRScreenResources *res;
   706         XRROutputInfo *output_info;
   707         XRRCrtcInfo *crtc;
   708         Status status;
   709 
   710         res = XRRGetScreenResources (display, RootWindow(display, data->screen));
   711         if (!res) {
   712             SDL_SetError("Couldn't get XRandR screen resources");
   713             return -1;
   714         }
   715 
   716         output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
   717         if (!output_info || output_info->connection == RR_Disconnected) {
   718             SDL_SetError("Couldn't get XRandR output info");
   719             XRRFreeScreenResources(res);
   720             return -1;
   721         }
   722 
   723         crtc = XRRGetCrtcInfo(display, res, output_info->crtc);
   724         if (!crtc) {
   725             SDL_SetError("Couldn't get XRandR crtc info");
   726             XRRFreeOutputInfo(output_info);
   727             XRRFreeScreenResources(res);
   728             return -1;
   729         }
   730 
   731         status = XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
   732           crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation,
   733           &data->xrandr_output, 1);
   734 
   735         XRRFreeCrtcInfo(crtc);
   736         XRRFreeOutputInfo(output_info);
   737         XRRFreeScreenResources(res);
   738 
   739         if (status != Success) {
   740             SDL_SetError("XRRSetCrtcConfig failed");
   741             return -1;
   742         }
   743 
   744         /* Hack to let the window manager adjust to the mode change */
   745         const int WINDOW_MANAGER_DELAY_HACK = 250;
   746         SDL_Delay(WINDOW_MANAGER_DELAY_HACK);
   747     }
   748 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   749 
   750 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   751     if (data->use_vidmode) {
   752         XF86VidModeSwitchToMode(display, data->screen, &modedata->vm_mode);
   753     }
   754 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   755 
   756     return 0;
   757 }
   758 
   759 void
   760 X11_QuitModes(_THIS)
   761 {
   762 }
   763 
   764 int
   765 X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect)
   766 {
   767     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   768     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   769 
   770     rect->x = data->x;
   771     rect->y = data->y;
   772     rect->w = sdl_display->current_mode.w;
   773     rect->h = sdl_display->current_mode.h;
   774 
   775 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   776     /* Get the real current bounds of the display */
   777     if (data->use_xinerama) {
   778         int screencount;
   779         XineramaScreenInfo *xinerama = XineramaQueryScreens(display, &screencount);
   780         if (xinerama) {
   781             rect->x = xinerama[data->xinerama_screen].x_org;
   782             rect->y = xinerama[data->xinerama_screen].y_org;
   783         }
   784     }
   785 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   786     return 0;
   787 }
   788 
   789 #endif /* SDL_VIDEO_DRIVER_X11 */
   790 
   791 /* vi: set ts=4 sw=4 expandtab: */