src/video/x11/SDL_x11modes.c
author Gabriel Jacobo <gabomdq@gmail.com>
Wed, 15 Oct 2014 18:33:43 -0300
changeset 9167 3d2c0f659ad3
parent 8922 dfb6f8611ebe
child 9319 ad4f430cc9f5
permissions -rw-r--r--
[X11] Obey DISPLAY environment variable when selecting screen (Steaphan Greene)

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