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