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