src/video/x11/SDL_x11modes.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 03 Oct 2012 19:24:11 -0700
changeset 6550 191f00a080ba
parent 6549 db16b819e1d1
child 6551 b0679a0d5751
permissions -rw-r--r--
Don't try to query outputs that are not hooked up to a crtc
     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->crtc ||
   515                     output_info->connection == RR_Disconnected) {
   516                     XRRFreeOutputInfo(output_info);
   517                     continue;
   518                 }
   519 
   520                 /* Is this the output that corresponds to the current screen?
   521                    We're checking the crtc position, but that may not be a valid test
   522                    in all cases.  Anybody want to give this some love?
   523                  */
   524                 crtc = XRRGetCrtcInfo(data->display, res, output_info->crtc);
   525                 if (!crtc || crtc->x != displaydata->x || crtc->y != displaydata->y) {
   526                     XRRFreeOutputInfo(output_info);
   527                     XRRFreeCrtcInfo(crtc);
   528                     continue;
   529                 }
   530 
   531                 displaydata->use_xrandr = use_xrandr;
   532                 displaydata->xrandr_output = res->outputs[output];
   533                 SetXRandRModeInfo(data->display, res, output_info, crtc->mode, &mode);
   534 
   535                 XRRFreeOutputInfo(output_info);
   536                 XRRFreeCrtcInfo(crtc);
   537                 break;
   538             }
   539 #ifdef X11MODES_DEBUG
   540             if (output == res->noutput) {
   541                 printf("Couldn't find XRandR CRTC at %d,%d\n", displaydata->x, displaydata->y);
   542             }
   543 #endif
   544             XRRFreeScreenResources(res);
   545         }
   546 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   547 
   548 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   549         if (!displaydata->use_xrandr &&
   550 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   551             (!displaydata->use_xinerama || displaydata->xinerama_info.screen_number == 0) &&
   552 #endif
   553             use_vidmode) {
   554             displaydata->use_vidmode = use_vidmode;
   555             XF86VidModeGetModeInfo(data->display, screen, &modedata->vm_mode);
   556         }
   557 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   558 
   559         SDL_zero(display);
   560         display.desktop_mode = mode;
   561         display.current_mode = mode;
   562         display.driverdata = displaydata;
   563         SDL_AddVideoDisplay(&display);
   564     }
   565 
   566 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   567     if (xinerama) XFree(xinerama);
   568 #endif
   569 
   570     if (_this->num_displays == 0) {
   571         SDL_SetError("No available displays");
   572         return -1;
   573     }
   574     return 0;
   575 }
   576 
   577 void
   578 X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display)
   579 {
   580     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   581     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   582 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   583     int nmodes;
   584     XF86VidModeModeInfo ** modes;
   585 #endif
   586     int screen_w;
   587     int screen_h;
   588     SDL_DisplayMode mode;
   589     SDL_DisplayModeData *modedata;
   590 
   591     /* Unfortunately X11 requires the window to be created with the correct
   592      * visual and depth ahead of time, but the SDL API allows you to create
   593      * a window before setting the fullscreen display mode.  This means that
   594      * we have to use the same format for all windows and all display modes.
   595      * (or support recreating the window with a new visual behind the scenes)
   596      */
   597     mode.format = sdl_display->current_mode.format;
   598     mode.driverdata = NULL;
   599 
   600     screen_w = DisplayWidth(display, data->screen);
   601     screen_h = DisplayHeight(display, data->screen);
   602 
   603 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   604     if (data->use_xinerama) {
   605         /* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0 */
   606         if (!data->xinerama_info.x_org && !data->xinerama_info.y_org &&
   607            (screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) {
   608             mode.w = screen_w;
   609             mode.h = screen_h;
   610             mode.refresh_rate = 0;
   611             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   612             if (modedata) {
   613                 *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   614             }
   615             mode.driverdata = modedata;
   616             SDL_AddDisplayMode(sdl_display, &mode);
   617         }
   618     }
   619 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   620 
   621 #if SDL_VIDEO_DRIVER_X11_XRANDR
   622     if (data->use_xrandr) {
   623         XRRScreenResources *res;
   624 
   625         res = XRRGetScreenResources (display, RootWindow(display, data->screen));
   626         if (res) {
   627             SDL_DisplayModeData *modedata;
   628             XRROutputInfo *output_info;
   629             int i;
   630 
   631             output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
   632             if (output_info && output_info->connection != RR_Disconnected) {
   633                 for (i = 0; i < output_info->nmode; ++i) {
   634                     modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   635                     if (!modedata) {
   636                         continue;
   637                     }
   638                     mode.driverdata = modedata;
   639 
   640                     if (SetXRandRModeInfo(display, res, output_info, output_info->modes[i], &mode)) {
   641                         SDL_AddDisplayMode(sdl_display, &mode);
   642                     } else {
   643                         SDL_free(modedata);
   644                     }
   645                 }
   646             }
   647             XRRFreeOutputInfo(output_info);
   648             XRRFreeScreenResources(res);
   649         }
   650         return;
   651     }
   652 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   653 
   654 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   655     if (data->use_vidmode &&
   656         XF86VidModeGetAllModeLines(display, data->screen, &nmodes, &modes)) {
   657         int i;
   658 
   659 #ifdef X11MODES_DEBUG
   660         printf("VidMode modes: (unsorted)\n");
   661         for (i = 0; i < nmodes; ++i) {
   662             printf("Mode %d: %d x %d @ %d\n", i,
   663                    modes[i]->hdisplay, modes[i]->vdisplay,
   664                    CalculateXVidModeRefreshRate(modes[i]));
   665         }
   666 #endif
   667         for (i = 0; i < nmodes; ++i) {
   668             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   669             if (!modedata) {
   670                 continue;
   671             }
   672             mode.driverdata = modedata;
   673 
   674             if (SetXVidModeModeInfo(modes[i], &mode)) {
   675                 SDL_AddDisplayMode(sdl_display, &mode);
   676             } else {
   677                 SDL_free(modedata);
   678             }
   679         }
   680         XFree(modes);
   681         return;
   682     }
   683 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   684 
   685     if (!data->use_xrandr && !data->use_vidmode) {
   686         /* Add the desktop mode */
   687         mode = sdl_display->desktop_mode;
   688         modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   689         if (modedata) {
   690             *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   691         }
   692         mode.driverdata = modedata;
   693         SDL_AddDisplayMode(sdl_display, &mode);
   694     }
   695 }
   696 
   697 int
   698 X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode)
   699 {
   700     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   701     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   702     SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
   703 
   704 #if SDL_VIDEO_DRIVER_X11_XRANDR
   705     if (data->use_xrandr) {
   706         XRRScreenResources *res;
   707         XRROutputInfo *output_info;
   708         XRRCrtcInfo *crtc;
   709         Status status;
   710 
   711         res = XRRGetScreenResources (display, RootWindow(display, data->screen));
   712         if (!res) {
   713             SDL_SetError("Couldn't get XRandR screen resources");
   714             return -1;
   715         }
   716 
   717         output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
   718         if (!output_info || output_info->connection == RR_Disconnected) {
   719             SDL_SetError("Couldn't get XRandR output info");
   720             XRRFreeScreenResources(res);
   721             return -1;
   722         }
   723 
   724         crtc = XRRGetCrtcInfo(display, res, output_info->crtc);
   725         if (!crtc) {
   726             SDL_SetError("Couldn't get XRandR crtc info");
   727             XRRFreeOutputInfo(output_info);
   728             XRRFreeScreenResources(res);
   729             return -1;
   730         }
   731 
   732         status = XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
   733           crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation,
   734           &data->xrandr_output, 1);
   735 
   736         XRRFreeCrtcInfo(crtc);
   737         XRRFreeOutputInfo(output_info);
   738         XRRFreeScreenResources(res);
   739 
   740         if (status != Success) {
   741             SDL_SetError("XRRSetCrtcConfig failed");
   742             return -1;
   743         }
   744 
   745         /* Hack to let the window manager adjust to the mode change */
   746         const int WINDOW_MANAGER_DELAY_HACK = 250;
   747         SDL_Delay(WINDOW_MANAGER_DELAY_HACK);
   748     }
   749 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   750 
   751 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   752     if (data->use_vidmode) {
   753         XF86VidModeSwitchToMode(display, data->screen, &modedata->vm_mode);
   754     }
   755 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   756 
   757     return 0;
   758 }
   759 
   760 void
   761 X11_QuitModes(_THIS)
   762 {
   763 }
   764 
   765 int
   766 X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect)
   767 {
   768     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   769     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   770 
   771     rect->x = data->x;
   772     rect->y = data->y;
   773     rect->w = sdl_display->current_mode.w;
   774     rect->h = sdl_display->current_mode.h;
   775 
   776 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   777     /* Get the real current bounds of the display */
   778     if (data->use_xinerama) {
   779         int screencount;
   780         XineramaScreenInfo *xinerama = XineramaQueryScreens(display, &screencount);
   781         if (xinerama) {
   782             rect->x = xinerama[data->xinerama_screen].x_org;
   783             rect->y = xinerama[data->xinerama_screen].y_org;
   784         }
   785     }
   786 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   787     return 0;
   788 }
   789 
   790 #endif /* SDL_VIDEO_DRIVER_X11 */
   791 
   792 /* vi: set ts=4 sw=4 expandtab: */