src/video/x11/SDL_x11modes.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 25 Jun 2014 00:43:10 -0700
changeset 8922 dfb6f8611ebe
parent 8149 681eb46b8ac4
child 9167 3d2c0f659ad3
permissions -rw-r--r--
Fixed bug 2556 - add compilation flag -Wshadow

Sylvain

here's the full patch for Blit + RLE.
     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 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 (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 = X11_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             X11_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 = X11_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 = X11_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 = X11_XRRGetOutputInfo(data->display, res, res->outputs[output]);
   544                 if (!output_info || !output_info->crtc ||
   545                     output_info->connection == RR_Disconnected) {
   546                     X11_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 = X11_XRRGetCrtcInfo(data->display, res, output_info->crtc);
   555                 if (!crtc || crtc->x != displaydata->x || crtc->y != displaydata->y ||
   556                     crtc->width != mode.w || crtc->height != mode.h) {
   557                     X11_XRRFreeOutputInfo(output_info);
   558                     X11_XRRFreeCrtcInfo(crtc);
   559                     continue;
   560                 }
   561 
   562                 displaydata->use_xrandr = use_xrandr;
   563                 displaydata->xrandr_output = res->outputs[output];
   564                 SetXRandRModeInfo(data->display, res, output_info, crtc->mode, &mode);
   565 
   566                 /* Get the name of this display */
   567                 width_mm = output_info->mm_width;
   568                 height_mm = output_info->mm_height;
   569                 inches = (int)((sqrt(width_mm * width_mm +
   570                                      height_mm * height_mm) / 25.4f) + 0.5f);
   571                 SDL_strlcpy(display_name, output_info->name, sizeof(display_name));
   572 
   573                 /* See if we can get the EDID data for the real monitor name */
   574                 props = X11_XRRListOutputProperties(data->display, res->outputs[output], &nprop);
   575                 for (i = 0; i < nprop; ++i) {
   576                     unsigned char *prop;
   577                     int actual_format;
   578                     unsigned long nitems, bytes_after;
   579                     Atom actual_type;
   580 
   581                     if (props[i] == EDID) {
   582                         if (X11_XRRGetOutputProperty(data->display,
   583                                                  res->outputs[output], props[i],
   584                                                  0, 100, False, False,
   585                                                  AnyPropertyType,
   586                                                  &actual_type, &actual_format,
   587                                                  &nitems, &bytes_after, &prop) == Success ) {
   588                             MonitorInfo *info = decode_edid(prop);
   589                             if (info) {
   590     #ifdef X11MODES_DEBUG
   591                                 printf("Found EDID data for %s\n", output_info->name);
   592                                 dump_monitor_info(info);
   593     #endif
   594                                 SDL_strlcpy(display_name, info->dsc_product_name, sizeof(display_name));
   595                                 free(info);
   596                             }
   597                             X11_XFree(prop);
   598                         }
   599                         break;
   600                     }
   601                 }
   602                 if (props) {
   603                     X11_XFree(props);
   604                 }
   605 
   606                 if (*display_name && inches) {
   607                     size_t len = SDL_strlen(display_name);
   608                     SDL_snprintf(&display_name[len], sizeof(display_name)-len, " %d\"", inches);
   609                 }
   610 #ifdef X11MODES_DEBUG
   611                 printf("Display name: %s\n", display_name);
   612 #endif
   613 
   614                 X11_XRRFreeOutputInfo(output_info);
   615                 X11_XRRFreeCrtcInfo(crtc);
   616                 break;
   617             }
   618 #ifdef X11MODES_DEBUG
   619             if (output == res->noutput) {
   620                 printf("Couldn't find XRandR CRTC at %d,%d\n", displaydata->x, displaydata->y);
   621             }
   622 #endif
   623             X11_XRRFreeScreenResources(res);
   624         }
   625 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   626 
   627 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   628         if (!displaydata->use_xrandr &&
   629 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   630             /* XVidMode only works on the screen at the origin */
   631             (!displaydata->use_xinerama ||
   632              (displaydata->x == 0 && displaydata->y == 0)) &&
   633 #endif
   634             use_vidmode) {
   635             displaydata->use_vidmode = use_vidmode;
   636             if (displaydata->use_xinerama) {
   637                 displaydata->vidmode_screen = 0;
   638             } else {
   639                 displaydata->vidmode_screen = screen;
   640             }
   641             XF86VidModeGetModeInfo(data->display, displaydata->vidmode_screen, &modedata->vm_mode);
   642         }
   643 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   644 
   645         SDL_zero(display);
   646         if (*display_name) {
   647             display.name = display_name;
   648         }
   649         display.desktop_mode = mode;
   650         display.current_mode = mode;
   651         display.driverdata = displaydata;
   652         SDL_AddVideoDisplay(&display);
   653     }
   654 
   655 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   656     if (xinerama) X11_XFree(xinerama);
   657 #endif
   658 
   659     if (_this->num_displays == 0) {
   660         return SDL_SetError("No available displays");
   661     }
   662     return 0;
   663 }
   664 
   665 void
   666 X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display)
   667 {
   668     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   669     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   670 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   671     int nmodes;
   672     XF86VidModeModeInfo ** modes;
   673 #endif
   674     int screen_w;
   675     int screen_h;
   676     SDL_DisplayMode mode;
   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         if (data->use_vidmode && !data->xinerama_info.x_org && !data->xinerama_info.y_org &&
   693            (screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) {
   694             SDL_DisplayModeData *modedata;
   695             /* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0
   696              * if we're using vidmode.
   697              */
   698             mode.w = screen_w;
   699             mode.h = screen_h;
   700             mode.refresh_rate = 0;
   701             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   702             if (modedata) {
   703                 *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   704             }
   705             mode.driverdata = modedata;
   706             SDL_AddDisplayMode(sdl_display, &mode);
   707         }
   708         else if (!data->use_xrandr)
   709         {
   710             SDL_DisplayModeData *modedata;
   711             /* Add the current mode of each monitor otherwise if we can't get them from xrandr */
   712             mode.w = data->xinerama_info.width;
   713             mode.h = data->xinerama_info.height;
   714             mode.refresh_rate = 0;
   715             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   716             if (modedata) {
   717                 *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   718             }
   719             mode.driverdata = modedata;
   720             SDL_AddDisplayMode(sdl_display, &mode);
   721         }
   722 
   723     }
   724 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   725 
   726 #if SDL_VIDEO_DRIVER_X11_XRANDR
   727     if (data->use_xrandr) {
   728         XRRScreenResources *res;
   729 
   730         res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen));
   731         if (res) {
   732             SDL_DisplayModeData *modedata;
   733             XRROutputInfo *output_info;
   734             int i;
   735 
   736             output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output);
   737             if (output_info && output_info->connection != RR_Disconnected) {
   738                 for (i = 0; i < output_info->nmode; ++i) {
   739                     modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   740                     if (!modedata) {
   741                         continue;
   742                     }
   743                     mode.driverdata = modedata;
   744 
   745                     if (SetXRandRModeInfo(display, res, output_info, output_info->modes[i], &mode)) {
   746                         SDL_AddDisplayMode(sdl_display, &mode);
   747                     } else {
   748                         SDL_free(modedata);
   749                     }
   750                 }
   751             }
   752             X11_XRRFreeOutputInfo(output_info);
   753             X11_XRRFreeScreenResources(res);
   754         }
   755         return;
   756     }
   757 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   758 
   759 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   760     if (data->use_vidmode &&
   761         X11_XF86VidModeGetAllModeLines(display, data->vidmode_screen, &nmodes, &modes)) {
   762         int i;
   763         SDL_DisplayModeData *modedata;
   764 
   765 #ifdef X11MODES_DEBUG
   766         printf("VidMode modes: (unsorted)\n");
   767         for (i = 0; i < nmodes; ++i) {
   768             printf("Mode %d: %d x %d @ %d, flags: 0x%x\n", i,
   769                    modes[i]->hdisplay, modes[i]->vdisplay,
   770                    CalculateXVidModeRefreshRate(modes[i]), modes[i]->flags);
   771         }
   772 #endif
   773         for (i = 0; i < nmodes; ++i) {
   774             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   775             if (!modedata) {
   776                 continue;
   777             }
   778             mode.driverdata = modedata;
   779 
   780             if (SetXVidModeModeInfo(modes[i], &mode)) {
   781                 SDL_AddDisplayMode(sdl_display, &mode);
   782             } else {
   783                 SDL_free(modedata);
   784             }
   785         }
   786         X11_XFree(modes);
   787         return;
   788     }
   789 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   790 
   791     if (!data->use_xrandr && !data->use_vidmode) {
   792         SDL_DisplayModeData *modedata;
   793         /* Add the desktop mode */
   794         mode = sdl_display->desktop_mode;
   795         modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   796         if (modedata) {
   797             *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   798         }
   799         mode.driverdata = modedata;
   800         SDL_AddDisplayMode(sdl_display, &mode);
   801     }
   802 }
   803 
   804 int
   805 X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode)
   806 {
   807     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   808     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   809     SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
   810 
   811 #if SDL_VIDEO_DRIVER_X11_XRANDR
   812     if (data->use_xrandr) {
   813         XRRScreenResources *res;
   814         XRROutputInfo *output_info;
   815         XRRCrtcInfo *crtc;
   816         Status status;
   817 
   818         res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen));
   819         if (!res) {
   820             return SDL_SetError("Couldn't get XRandR screen resources");
   821         }
   822 
   823         output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output);
   824         if (!output_info || output_info->connection == RR_Disconnected) {
   825             X11_XRRFreeScreenResources(res);
   826             return SDL_SetError("Couldn't get XRandR output info");
   827         }
   828 
   829         crtc = X11_XRRGetCrtcInfo(display, res, output_info->crtc);
   830         if (!crtc) {
   831             X11_XRRFreeOutputInfo(output_info);
   832             X11_XRRFreeScreenResources(res);
   833             return SDL_SetError("Couldn't get XRandR crtc info");
   834         }
   835 
   836         status = X11_XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
   837           crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation,
   838           &data->xrandr_output, 1);
   839 
   840         X11_XRRFreeCrtcInfo(crtc);
   841         X11_XRRFreeOutputInfo(output_info);
   842         X11_XRRFreeScreenResources(res);
   843 
   844         if (status != Success) {
   845             return SDL_SetError("X11_XRRSetCrtcConfig failed");
   846         }
   847     }
   848 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   849 
   850 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   851     if (data->use_vidmode) {
   852         X11_XF86VidModeSwitchToMode(display, data->vidmode_screen, &modedata->vm_mode);
   853     }
   854 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   855 
   856     return 0;
   857 }
   858 
   859 void
   860 X11_QuitModes(_THIS)
   861 {
   862 }
   863 
   864 int
   865 X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect)
   866 {
   867     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   868 
   869     rect->x = data->x;
   870     rect->y = data->y;
   871     rect->w = sdl_display->current_mode.w;
   872     rect->h = sdl_display->current_mode.h;
   873 
   874 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   875     /* Get the real current bounds of the display */
   876     if (data->use_xinerama) {
   877         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   878         int screencount;
   879         XineramaScreenInfo *xinerama = X11_XineramaQueryScreens(display, &screencount);
   880         if (xinerama) {
   881             rect->x = xinerama[data->xinerama_screen].x_org;
   882             rect->y = xinerama[data->xinerama_screen].y_org;
   883             X11_XFree(xinerama);
   884         }
   885     }
   886 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   887     return 0;
   888 }
   889 
   890 #endif /* SDL_VIDEO_DRIVER_X11 */
   891 
   892 /* vi: set ts=4 sw=4 expandtab: */