src/video/x11/SDL_x11modes.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 03 Oct 2012 19:39:12 -0700
changeset 6553 2f03111a2105
parent 6551 b0679a0d5751
child 6558 90f231aa77b9
permissions -rw-r--r--
This hack doesn't work very well. I'd rather just show the problem so it can be fixed.
     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) ? (info->dotClock / (info->hTotal * info->vTotal)) : 0;
   228 }
   229 
   230 static SDL_bool
   231 SetXRandRModeInfo(Display *display, XRRScreenResources *res, XRROutputInfo *output_info,
   232                   RRMode modeID, SDL_DisplayMode *mode)
   233 {
   234     int i;
   235     for (i = 0; i < res->nmode; ++i) {
   236         if (res->modes[i].id == modeID) {
   237             XRRCrtcInfo *crtc;
   238             Rotation rotation = 0;
   239             const XRRModeInfo *info = &res->modes[i];
   240 
   241             crtc = XRRGetCrtcInfo(display, res, output_info->crtc);
   242             if (crtc) {
   243                 rotation = crtc->rotation;
   244                 XRRFreeCrtcInfo(crtc);
   245             }
   246 
   247             if (rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) {
   248                 mode->w = info->height;
   249                 mode->h = info->width;
   250             } else {
   251                 mode->w = info->width;
   252                 mode->h = info->height;
   253             }
   254             mode->refresh_rate = CalculateXRandRRefreshRate(info);
   255             ((SDL_DisplayModeData*)mode->driverdata)->xrandr_mode = modeID;
   256 #ifdef X11MODES_DEBUG
   257             printf("XRandR mode %d: %dx%d@%dHz\n", modeID, mode->w, mode->h, mode->refresh_rate);
   258 #endif
   259             return SDL_TRUE;
   260         }
   261     }
   262     return SDL_FALSE;
   263 }
   264 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   265 
   266 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   267 static SDL_bool
   268 CheckVidMode(Display * display, int *major, int *minor)
   269 {
   270     const char *env;
   271 
   272     /* Default the extension not available */
   273     *major = *minor = 0;
   274 
   275     /* Allow environment override */
   276     env = SDL_GetHint(SDL_HINT_VIDEO_X11_XVIDMODE);
   277     if (env && !SDL_atoi(env)) {
   278 #ifdef X11MODES_DEBUG
   279         printf("XVidMode disabled due to hint\n");
   280 #endif
   281         return SDL_FALSE;
   282     }
   283 
   284     if (!SDL_X11_HAVE_XVIDMODE) {
   285 #ifdef X11MODES_DEBUG
   286         printf("XVidMode support not available\n");
   287 #endif
   288         return SDL_FALSE;
   289     }
   290 
   291     /* Query the extension version */
   292     vm_error = -1;
   293     if (!XF86VidModeQueryExtension(display, &vm_event, &vm_error)
   294         || !XF86VidModeQueryVersion(display, major, minor)) {
   295 #ifdef X11MODES_DEBUG
   296         printf("XVidMode not active on the display\n");
   297 #endif
   298         return SDL_FALSE;
   299     }
   300 #ifdef X11MODES_DEBUG
   301     printf("XVidMode available at version %d.%d!\n", *major, *minor);
   302 #endif
   303     return SDL_TRUE;
   304 }
   305 
   306 static
   307 Bool XF86VidModeGetModeInfo(Display * dpy, int scr,
   308                                        XF86VidModeModeInfo* info)
   309 {
   310     Bool retval;
   311     int dotclock;
   312     XF86VidModeModeLine l;
   313     SDL_zerop(info);
   314     SDL_zero(l);
   315     retval = XF86VidModeGetModeLine(dpy, scr, &dotclock, &l);
   316     info->dotclock = dotclock;
   317     info->hdisplay = l.hdisplay;
   318     info->hsyncstart = l.hsyncstart;
   319     info->hsyncend = l.hsyncend;
   320     info->htotal = l.htotal;
   321     info->hskew = l.hskew;
   322     info->vdisplay = l.vdisplay;
   323     info->vsyncstart = l.vsyncstart;
   324     info->vsyncend = l.vsyncend;
   325     info->vtotal = l.vtotal;
   326     info->flags = l.flags;
   327     info->privsize = l.privsize;
   328     info->private = l.private;
   329     return retval;
   330 }
   331 
   332 static int
   333 CalculateXVidModeRefreshRate(const XF86VidModeModeInfo * info)
   334 {
   335     return (info->htotal
   336             && info->vtotal) ? (1000 * info->dotclock / (info->htotal *
   337                                                          info->vtotal)) : 0;
   338 }
   339 
   340 SDL_bool
   341 SetXVidModeModeInfo(const XF86VidModeModeInfo *info, SDL_DisplayMode *mode)
   342 {
   343     mode->w = info->hdisplay;
   344     mode->h = info->vdisplay;
   345     mode->refresh_rate = CalculateXVidModeRefreshRate(info);
   346     ((SDL_DisplayModeData*)mode->driverdata)->vm_mode = *info;
   347     return SDL_TRUE;
   348 }
   349 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   350 
   351 int
   352 X11_InitModes(_THIS)
   353 {
   354     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   355     int screen, screencount;
   356 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   357     int xinerama_major, xinerama_minor;
   358     int use_xinerama = 0;
   359     XineramaScreenInfo *xinerama = NULL;
   360 #endif
   361 #if SDL_VIDEO_DRIVER_X11_XRANDR
   362     int xrandr_major, xrandr_minor;
   363     int use_xrandr = 0;
   364     XRRScreenResources *res = NULL;
   365 #endif
   366 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   367     int vm_major, vm_minor;
   368     int use_vidmode = 0;
   369 #endif
   370 
   371 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   372     /* Query Xinerama extention
   373      * NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012)
   374      *       or newer of the Nvidia binary drivers
   375      */
   376     if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) {
   377         xinerama = XineramaQueryScreens(data->display, &screencount);
   378         if (xinerama) {
   379             use_xinerama = xinerama_major * 100 + xinerama_minor;
   380         }
   381     }
   382     if (!xinerama) {
   383         screencount = ScreenCount(data->display);
   384     }
   385 #else
   386     screencount = ScreenCount(data->display);
   387 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   388 
   389 #if SDL_VIDEO_DRIVER_X11_XRANDR
   390     /* require at least XRandR v1.2 */
   391     if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) &&
   392         (xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 2))) {
   393         use_xrandr = xrandr_major * 100 + xrandr_minor;
   394     }
   395 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   396 
   397 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   398     if (CheckVidMode(data->display, &vm_major, &vm_minor)) {
   399         use_vidmode = vm_major * 100 + vm_minor;
   400     }
   401 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   402 
   403     for (screen = 0; screen < screencount; ++screen) {
   404         XVisualInfo vinfo;
   405         SDL_VideoDisplay display;
   406         SDL_DisplayData *displaydata;
   407         SDL_DisplayMode mode;
   408         SDL_DisplayModeData *modedata;
   409         XPixmapFormatValues *pixmapFormats;
   410         int i, n;
   411 
   412 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   413         if (xinerama) {
   414             if (get_visualinfo(data->display, 0, &vinfo) < 0) {
   415                 continue;
   416             }
   417         } else {
   418             if (get_visualinfo(data->display, screen, &vinfo) < 0) {
   419                 continue;
   420             }
   421         }
   422 #else
   423         if (get_visualinfo(data->display, screen, &vinfo) < 0) {
   424             continue;
   425         }
   426 #endif
   427 
   428         displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
   429         if (!displaydata) {
   430             continue;
   431         }
   432 
   433         mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
   434         if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
   435             /* We don't support palettized modes now */
   436             SDL_free(displaydata);
   437             continue;
   438         }
   439 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   440         if (xinerama) {
   441             mode.w = xinerama[screen].width;
   442             mode.h = xinerama[screen].height;
   443         } else {
   444             mode.w = DisplayWidth(data->display, screen);
   445             mode.h = DisplayHeight(data->display, screen);
   446         }
   447 #else
   448         mode.w = DisplayWidth(data->display, screen);
   449         mode.h = DisplayHeight(data->display, screen);
   450 #endif
   451         mode.refresh_rate = 0;
   452 
   453         modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   454         if (!modedata) {
   455             SDL_free(displaydata);
   456             continue;
   457         }
   458         mode.driverdata = modedata;
   459 
   460 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   461         /* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active,
   462          * there's only one screen available. So we force the screen number to zero and
   463          * let Xinerama specific code handle specific functionality using displaydata->xinerama_info
   464          */
   465         if (use_xinerama) {
   466             displaydata->screen = 0;
   467             displaydata->use_xinerama = use_xinerama;
   468             displaydata->xinerama_info = xinerama[screen];
   469             displaydata->xinerama_screen = screen;
   470         }
   471         else displaydata->screen = screen;
   472 #else
   473         displaydata->screen = screen;
   474 #endif
   475         displaydata->visual = vinfo.visual;
   476         displaydata->depth = vinfo.depth;
   477 
   478         displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8;
   479         pixmapFormats = XListPixmapFormats(data->display, &n);
   480         if (pixmapFormats) {
   481             for (i = 0; i < n; ++i) {
   482                 if (pixmapFormats[i].depth == displaydata->depth) {
   483                     displaydata->scanline_pad = pixmapFormats[i].scanline_pad;
   484                     break;
   485                 }
   486             }
   487             XFree(pixmapFormats);
   488         }
   489 
   490 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   491         if (use_xinerama) {
   492             displaydata->x = xinerama[screen].x_org;
   493             displaydata->y = xinerama[screen].y_org;
   494         }
   495         else
   496 #endif
   497         {
   498             displaydata->x = 0;
   499             displaydata->y = 0;
   500         }
   501 
   502 #if SDL_VIDEO_DRIVER_X11_XRANDR
   503         if (use_xrandr) {
   504             res = XRRGetScreenResources(data->display, RootWindow(data->display, displaydata->screen));
   505         }
   506         if (res) {
   507             XRROutputInfo *output_info;
   508             XRRCrtcInfo *crtc;
   509             int output;
   510 
   511             for (output = 0; output < res->noutput; output++) {
   512                 output_info = XRRGetOutputInfo(data->display, res, res->outputs[output]);
   513                 if (!output_info || !output_info->crtc ||
   514                     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 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   745 
   746 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   747     if (data->use_vidmode) {
   748         XF86VidModeSwitchToMode(display, data->screen, &modedata->vm_mode);
   749     }
   750 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   751 
   752     return 0;
   753 }
   754 
   755 void
   756 X11_QuitModes(_THIS)
   757 {
   758 }
   759 
   760 int
   761 X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect)
   762 {
   763     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   764     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   765 
   766     rect->x = data->x;
   767     rect->y = data->y;
   768     rect->w = sdl_display->current_mode.w;
   769     rect->h = sdl_display->current_mode.h;
   770 
   771 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   772     /* Get the real current bounds of the display */
   773     if (data->use_xinerama) {
   774         int screencount;
   775         XineramaScreenInfo *xinerama = XineramaQueryScreens(display, &screencount);
   776         if (xinerama) {
   777             rect->x = xinerama[data->xinerama_screen].x_org;
   778             rect->y = xinerama[data->xinerama_screen].y_org;
   779         }
   780     }
   781 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   782     return 0;
   783 }
   784 
   785 #endif /* SDL_VIDEO_DRIVER_X11 */
   786 
   787 /* vi: set ts=4 sw=4 expandtab: */