src/video/x11/SDL_x11modes.c
author Ryan C. Gordon <icculus@icculus.org>
Sun, 31 Mar 2013 12:48:50 -0400
changeset 7037 3fedf1f25b94
parent 6941 9bb475091e51
child 7191 75360622e65f
permissions -rw-r--r--
Make SDL_SetError and friends unconditionally return -1.

This lets us change things like this...

if (Failed) {
SDL_SetError("We failed");
return -1;
}

...into this...

if (Failed) {
return SDL_SetError("We failed");
}


Fixes Bugzilla #1778.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 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 #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 = XGetVisualInfo(display, VisualIDMask, &template, &nvis);
    58         if (vi) {
    59             *vinfo = *vi;
    60             XFree(vi);
    61             return 0;
    62         }
    63     }
    64 
    65     depth = DefaultDepth(display, screen);
    66     if ((X11_UseDirectColorVisuals() &&
    67          XMatchVisualInfo(display, screen, depth, DirectColor, vinfo)) ||
    68         XMatchVisualInfo(display, screen, depth, TrueColor, vinfo) ||
    69         XMatchVisualInfo(display, screen, depth, PseudoColor, vinfo) ||
    70         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 = XVisualIDFromVisual(visual);
    83     vi = XGetVisualInfo(display, VisualIDMask, vinfo, &nvis);
    84     if (vi) {
    85         *vinfo = *vi;
    86         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 = 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                 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 (!XineramaQueryExtension(display, &event_base, &error_base) ||
   182         !XineramaQueryVersion(display, major, minor) ||
   183         !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 (!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 = XRRGetCrtcInfo(display, res, output_info->crtc);
   265             if (crtc) {
   266                 rotation = crtc->rotation;
   267                 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 (!XF86VidModeQueryExtension(display, &vm_event, &vm_error)
   317         || !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 = 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 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 = 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 (screen = 0; screen < screencount; ++screen) {
   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 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   437         if (xinerama) {
   438             if (get_visualinfo(data->display, 0, &vinfo) < 0) {
   439                 continue;
   440             }
   441         } else {
   442             if (get_visualinfo(data->display, screen, &vinfo) < 0) {
   443                 continue;
   444             }
   445         }
   446 #else
   447         if (get_visualinfo(data->display, screen, &vinfo) < 0) {
   448             continue;
   449         }
   450 #endif
   451 
   452         displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
   453         if (!displaydata) {
   454             continue;
   455         }
   456         display_name[0] = '\0';
   457 
   458         mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
   459         if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
   460             /* We don't support palettized modes now */
   461             SDL_free(displaydata);
   462             continue;
   463         }
   464 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   465         if (xinerama) {
   466             mode.w = xinerama[screen].width;
   467             mode.h = xinerama[screen].height;
   468         } else {
   469             mode.w = DisplayWidth(data->display, screen);
   470             mode.h = DisplayHeight(data->display, screen);
   471         }
   472 #else
   473         mode.w = DisplayWidth(data->display, screen);
   474         mode.h = DisplayHeight(data->display, screen);
   475 #endif
   476         mode.refresh_rate = 0;
   477 
   478         modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   479         if (!modedata) {
   480             SDL_free(displaydata);
   481             continue;
   482         }
   483         mode.driverdata = modedata;
   484 
   485 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   486         /* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active,
   487          * there's only one screen available. So we force the screen number to zero and
   488          * let Xinerama specific code handle specific functionality using displaydata->xinerama_info
   489          */
   490         if (use_xinerama) {
   491             displaydata->screen = 0;
   492             displaydata->use_xinerama = use_xinerama;
   493             displaydata->xinerama_info = xinerama[screen];
   494             displaydata->xinerama_screen = screen;
   495         }
   496         else displaydata->screen = screen;
   497 #else
   498         displaydata->screen = screen;
   499 #endif
   500         displaydata->visual = vinfo.visual;
   501         displaydata->depth = vinfo.depth;
   502 
   503         displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8;
   504         pixmapFormats = XListPixmapFormats(data->display, &n);
   505         if (pixmapFormats) {
   506             for (i = 0; i < n; ++i) {
   507                 if (pixmapFormats[i].depth == displaydata->depth) {
   508                     displaydata->scanline_pad = pixmapFormats[i].scanline_pad;
   509                     break;
   510                 }
   511             }
   512             XFree(pixmapFormats);
   513         }
   514 
   515 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   516         if (use_xinerama) {
   517             displaydata->x = xinerama[screen].x_org;
   518             displaydata->y = xinerama[screen].y_org;
   519         }
   520         else
   521 #endif
   522         {
   523             displaydata->x = 0;
   524             displaydata->y = 0;
   525         }
   526 
   527 #if SDL_VIDEO_DRIVER_X11_XRANDR
   528         if (use_xrandr) {
   529             res = XRRGetScreenResources(data->display, RootWindow(data->display, displaydata->screen));
   530         }
   531         if (res) {
   532             XRROutputInfo *output_info;
   533             XRRCrtcInfo *crtc;
   534             int output;
   535             Atom EDID = XInternAtom(data->display, "EDID", False);
   536             Atom *props;
   537             int nprop;
   538             unsigned long width_mm;
   539             unsigned long height_mm;
   540             int inches = 0;
   541 
   542             for (output = 0; output < res->noutput; output++) {
   543                 output_info = XRRGetOutputInfo(data->display, res, res->outputs[output]);
   544                 if (!output_info || !output_info->crtc ||
   545                     output_info->connection == RR_Disconnected) {
   546                     XRRFreeOutputInfo(output_info);
   547                     continue;
   548                 }
   549 
   550                 /* Is this the output that corresponds to the current screen?
   551                    We're checking the crtc position, but that may not be a valid test
   552                    in all cases.  Anybody want to give this some love?
   553                  */
   554                 crtc = XRRGetCrtcInfo(data->display, res, output_info->crtc);
   555                 if (!crtc || crtc->x != displaydata->x || crtc->y != displaydata->y) {
   556                     XRRFreeOutputInfo(output_info);
   557                     XRRFreeCrtcInfo(crtc);
   558                     continue;
   559                 }
   560 
   561                 displaydata->use_xrandr = use_xrandr;
   562                 displaydata->xrandr_output = res->outputs[output];
   563                 SetXRandRModeInfo(data->display, res, output_info, crtc->mode, &mode);
   564 
   565                 /* Get the name of this display */
   566                 width_mm = output_info->mm_width;
   567                 height_mm = output_info->mm_height;
   568                 inches = (int)((sqrt(width_mm * width_mm +
   569                                      height_mm * height_mm) / 25.4f) + 0.5f);
   570                 SDL_strlcpy(display_name, output_info->name, sizeof(display_name));
   571 
   572                 /* See if we can get the EDID data for the real monitor name */
   573                 props = XRRListOutputProperties(data->display, res->outputs[output], &nprop);
   574                 for (i = 0; i < nprop; ++i) {
   575                     unsigned char *prop;
   576                     int actual_format;
   577                     unsigned long nitems, bytes_after;
   578                     Atom actual_type;
   579 
   580 	                if (props[i] == EDID) {
   581                         if (XRRGetOutputProperty(data->display,
   582                                                  res->outputs[output], props[i],
   583                                                  0, 100, False, False,
   584                                                  AnyPropertyType,
   585                                                  &actual_type, &actual_format,
   586                                                  &nitems, &bytes_after, &prop) == Success ) {
   587                             MonitorInfo *info = decode_edid(prop);
   588                             if (info) {
   589     #ifdef X11MODES_DEBUG
   590                                 printf("Found EDID data for %s\n", output_info->name);
   591                                 dump_monitor_info(info);
   592     #endif
   593                                 SDL_strlcpy(display_name, info->dsc_product_name, sizeof(display_name));
   594                                 free(info);
   595                             }
   596                             XFree(prop);
   597                         }
   598                         break;
   599                     }
   600                 }
   601                 if (props) {
   602                     XFree(props);
   603                 }
   604 
   605                 if (*display_name && inches) {
   606                     size_t len = SDL_strlen(display_name);
   607                     SDL_snprintf(&display_name[len], sizeof(display_name)-len, " %d\"", inches);
   608                 }
   609 #ifdef X11MODES_DEBUG
   610                 printf("Display name: %s\n", display_name);
   611 #endif
   612 
   613                 XRRFreeOutputInfo(output_info);
   614                 XRRFreeCrtcInfo(crtc);
   615                 break;
   616             }
   617 #ifdef X11MODES_DEBUG
   618             if (output == res->noutput) {
   619                 printf("Couldn't find XRandR CRTC at %d,%d\n", displaydata->x, displaydata->y);
   620             }
   621 #endif
   622             XRRFreeScreenResources(res);
   623         }
   624 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   625 
   626 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   627         if (!displaydata->use_xrandr &&
   628 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   629             /* XVidMode only works on the screen at the origin */
   630             (!displaydata->use_xinerama ||
   631              (displaydata->x == 0 && displaydata->y == 0)) &&
   632 #endif
   633             use_vidmode) {
   634             displaydata->use_vidmode = use_vidmode;
   635             if (displaydata->use_xinerama) {
   636                 displaydata->vidmode_screen = 0;
   637             } else {
   638                 displaydata->vidmode_screen = screen;
   639             }
   640             XF86VidModeGetModeInfo(data->display, displaydata->vidmode_screen, &modedata->vm_mode);
   641         }
   642 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   643 
   644         SDL_zero(display);
   645         if (*display_name) {
   646             display.name = display_name;
   647         }
   648         display.desktop_mode = mode;
   649         display.current_mode = mode;
   650         display.driverdata = displaydata;
   651         SDL_AddVideoDisplay(&display);
   652     }
   653 
   654 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   655     if (xinerama) XFree(xinerama);
   656 #endif
   657 
   658     if (_this->num_displays == 0) {
   659         return SDL_SetError("No available displays");
   660     }
   661     return 0;
   662 }
   663 
   664 void
   665 X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display)
   666 {
   667     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   668     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   669 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   670     int nmodes;
   671     XF86VidModeModeInfo ** modes;
   672 #endif
   673     int screen_w;
   674     int screen_h;
   675     SDL_DisplayMode mode;
   676     SDL_DisplayModeData *modedata;
   677 
   678     /* Unfortunately X11 requires the window to be created with the correct
   679      * visual and depth ahead of time, but the SDL API allows you to create
   680      * a window before setting the fullscreen display mode.  This means that
   681      * we have to use the same format for all windows and all display modes.
   682      * (or support recreating the window with a new visual behind the scenes)
   683      */
   684     mode.format = sdl_display->current_mode.format;
   685     mode.driverdata = NULL;
   686 
   687     screen_w = DisplayWidth(display, data->screen);
   688     screen_h = DisplayHeight(display, data->screen);
   689 
   690 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   691     if (data->use_xinerama) {
   692         /* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0 */
   693         if (!data->xinerama_info.x_org && !data->xinerama_info.y_org &&
   694            (screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) {
   695             mode.w = screen_w;
   696             mode.h = screen_h;
   697             mode.refresh_rate = 0;
   698             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   699             if (modedata) {
   700                 *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   701             }
   702             mode.driverdata = modedata;
   703             SDL_AddDisplayMode(sdl_display, &mode);
   704         }
   705     }
   706 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   707 
   708 #if SDL_VIDEO_DRIVER_X11_XRANDR
   709     if (data->use_xrandr) {
   710         XRRScreenResources *res;
   711 
   712         res = XRRGetScreenResources (display, RootWindow(display, data->screen));
   713         if (res) {
   714             SDL_DisplayModeData *modedata;
   715             XRROutputInfo *output_info;
   716             int i;
   717 
   718             output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
   719             if (output_info && output_info->connection != RR_Disconnected) {
   720                 for (i = 0; i < output_info->nmode; ++i) {
   721                     modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   722                     if (!modedata) {
   723                         continue;
   724                     }
   725                     mode.driverdata = modedata;
   726 
   727                     if (SetXRandRModeInfo(display, res, output_info, output_info->modes[i], &mode)) {
   728                         SDL_AddDisplayMode(sdl_display, &mode);
   729                     } else {
   730                         SDL_free(modedata);
   731                     }
   732                 }
   733             }
   734             XRRFreeOutputInfo(output_info);
   735             XRRFreeScreenResources(res);
   736         }
   737         return;
   738     }
   739 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   740 
   741 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   742     if (data->use_vidmode &&
   743         XF86VidModeGetAllModeLines(display, data->vidmode_screen, &nmodes, &modes)) {
   744         int i;
   745 
   746 #ifdef X11MODES_DEBUG
   747         printf("VidMode modes: (unsorted)\n");
   748         for (i = 0; i < nmodes; ++i) {
   749             printf("Mode %d: %d x %d @ %d, flags: 0x%x\n", i,
   750                    modes[i]->hdisplay, modes[i]->vdisplay,
   751                    CalculateXVidModeRefreshRate(modes[i]), modes[i]->flags);
   752         }
   753 #endif
   754         for (i = 0; i < nmodes; ++i) {
   755             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   756             if (!modedata) {
   757                 continue;
   758             }
   759             mode.driverdata = modedata;
   760 
   761             if (SetXVidModeModeInfo(modes[i], &mode)) {
   762                 SDL_AddDisplayMode(sdl_display, &mode);
   763             } else {
   764                 SDL_free(modedata);
   765             }
   766         }
   767         XFree(modes);
   768         return;
   769     }
   770 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   771 
   772     if (!data->use_xrandr && !data->use_vidmode) {
   773         /* Add the desktop mode */
   774         mode = sdl_display->desktop_mode;
   775         modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   776         if (modedata) {
   777             *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   778         }
   779         mode.driverdata = modedata;
   780         SDL_AddDisplayMode(sdl_display, &mode);
   781     }
   782 }
   783 
   784 int
   785 X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode)
   786 {
   787     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   788     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   789     SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
   790 
   791 #if SDL_VIDEO_DRIVER_X11_XRANDR
   792     if (data->use_xrandr) {
   793         XRRScreenResources *res;
   794         XRROutputInfo *output_info;
   795         XRRCrtcInfo *crtc;
   796         Status status;
   797 
   798         res = XRRGetScreenResources (display, RootWindow(display, data->screen));
   799         if (!res) {
   800             return SDL_SetError("Couldn't get XRandR screen resources");
   801         }
   802 
   803         output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
   804         if (!output_info || output_info->connection == RR_Disconnected) {
   805             XRRFreeScreenResources(res);
   806             return SDL_SetError("Couldn't get XRandR output info");
   807         }
   808 
   809         crtc = XRRGetCrtcInfo(display, res, output_info->crtc);
   810         if (!crtc) {
   811             XRRFreeOutputInfo(output_info);
   812             XRRFreeScreenResources(res);
   813             return SDL_SetError("Couldn't get XRandR crtc info");
   814         }
   815 
   816         status = XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
   817           crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation,
   818           &data->xrandr_output, 1);
   819 
   820         XRRFreeCrtcInfo(crtc);
   821         XRRFreeOutputInfo(output_info);
   822         XRRFreeScreenResources(res);
   823 
   824         if (status != Success) {
   825             return SDL_SetError("XRRSetCrtcConfig failed");
   826         }
   827     }
   828 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   829 
   830 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   831     if (data->use_vidmode) {
   832         XF86VidModeSwitchToMode(display, data->vidmode_screen, &modedata->vm_mode);
   833     }
   834 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   835 
   836     return 0;
   837 }
   838 
   839 void
   840 X11_QuitModes(_THIS)
   841 {
   842 }
   843 
   844 int
   845 X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect)
   846 {
   847     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   848     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   849 
   850     rect->x = data->x;
   851     rect->y = data->y;
   852     rect->w = sdl_display->current_mode.w;
   853     rect->h = sdl_display->current_mode.h;
   854 
   855 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   856     /* Get the real current bounds of the display */
   857     if (data->use_xinerama) {
   858         int screencount;
   859         XineramaScreenInfo *xinerama = XineramaQueryScreens(display, &screencount);
   860         if (xinerama) {
   861             rect->x = xinerama[data->xinerama_screen].x_org;
   862             rect->y = xinerama[data->xinerama_screen].y_org;
   863             XFree(xinerama);
   864         }
   865     }
   866 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   867     return 0;
   868 }
   869 
   870 #endif /* SDL_VIDEO_DRIVER_X11 */
   871 
   872 /* vi: set ts=4 sw=4 expandtab: */