src/video/x11/SDL_x11modes.c
author Gabriel Jacobo <gabomdq@gmail.com>
Fri, 22 Feb 2013 10:44:44 -0300
changeset 6906 85ac6fbdf171
parent 6885 700f1b25f77f
child 6940 142dcc136188
permissions -rw-r--r--
Fixes Bug 1726 - Memory leak in X11_GetDisplayBounds
     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                         XRRGetOutputProperty(data->display, res->outputs[output], props[i],
   582                                              0, 100, False, False,
   583                                              AnyPropertyType,
   584                                              &actual_type, &actual_format,
   585                                              &nitems, &bytes_after, &prop);
   586 
   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                         break;
   597                     }
   598                 }
   599 
   600                 if (*display_name && inches) {
   601                     size_t len = SDL_strlen(display_name);
   602                     SDL_snprintf(&display_name[len], sizeof(display_name)-len, " %d\"", inches);
   603                 }
   604 #ifdef X11MODES_DEBUG
   605                 printf("Display name: %s\n", display_name);
   606 #endif
   607 
   608                 XRRFreeOutputInfo(output_info);
   609                 XRRFreeCrtcInfo(crtc);
   610                 break;
   611             }
   612 #ifdef X11MODES_DEBUG
   613             if (output == res->noutput) {
   614                 printf("Couldn't find XRandR CRTC at %d,%d\n", displaydata->x, displaydata->y);
   615             }
   616 #endif
   617             XRRFreeScreenResources(res);
   618         }
   619 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   620 
   621 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   622         if (!displaydata->use_xrandr &&
   623 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   624             /* XVidMode only works on the screen at the origin */
   625             (!displaydata->use_xinerama ||
   626              (displaydata->x == 0 && displaydata->y == 0)) &&
   627 #endif
   628             use_vidmode) {
   629             displaydata->use_vidmode = use_vidmode;
   630             if (displaydata->use_xinerama) {
   631                 displaydata->vidmode_screen = 0;
   632             } else {
   633                 displaydata->vidmode_screen = screen;
   634             }
   635             XF86VidModeGetModeInfo(data->display, displaydata->vidmode_screen, &modedata->vm_mode);
   636         }
   637 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   638 
   639         SDL_zero(display);
   640         if (*display_name) {
   641             display.name = display_name;
   642         }
   643         display.desktop_mode = mode;
   644         display.current_mode = mode;
   645         display.driverdata = displaydata;
   646         SDL_AddVideoDisplay(&display);
   647     }
   648 
   649 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   650     if (xinerama) XFree(xinerama);
   651 #endif
   652 
   653     if (_this->num_displays == 0) {
   654         SDL_SetError("No available displays");
   655         return -1;
   656     }
   657     return 0;
   658 }
   659 
   660 void
   661 X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display)
   662 {
   663     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   664     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   665 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   666     int nmodes;
   667     XF86VidModeModeInfo ** modes;
   668 #endif
   669     int screen_w;
   670     int screen_h;
   671     SDL_DisplayMode mode;
   672     SDL_DisplayModeData *modedata;
   673 
   674     /* Unfortunately X11 requires the window to be created with the correct
   675      * visual and depth ahead of time, but the SDL API allows you to create
   676      * a window before setting the fullscreen display mode.  This means that
   677      * we have to use the same format for all windows and all display modes.
   678      * (or support recreating the window with a new visual behind the scenes)
   679      */
   680     mode.format = sdl_display->current_mode.format;
   681     mode.driverdata = NULL;
   682 
   683     screen_w = DisplayWidth(display, data->screen);
   684     screen_h = DisplayHeight(display, data->screen);
   685 
   686 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   687     if (data->use_xinerama) {
   688         /* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0 */
   689         if (!data->xinerama_info.x_org && !data->xinerama_info.y_org &&
   690            (screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) {
   691             mode.w = screen_w;
   692             mode.h = screen_h;
   693             mode.refresh_rate = 0;
   694             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   695             if (modedata) {
   696                 *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   697             }
   698             mode.driverdata = modedata;
   699             SDL_AddDisplayMode(sdl_display, &mode);
   700         }
   701     }
   702 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   703 
   704 #if SDL_VIDEO_DRIVER_X11_XRANDR
   705     if (data->use_xrandr) {
   706         XRRScreenResources *res;
   707 
   708         res = XRRGetScreenResources (display, RootWindow(display, data->screen));
   709         if (res) {
   710             SDL_DisplayModeData *modedata;
   711             XRROutputInfo *output_info;
   712             int i;
   713 
   714             output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
   715             if (output_info && output_info->connection != RR_Disconnected) {
   716                 for (i = 0; i < output_info->nmode; ++i) {
   717                     modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   718                     if (!modedata) {
   719                         continue;
   720                     }
   721                     mode.driverdata = modedata;
   722 
   723                     if (SetXRandRModeInfo(display, res, output_info, output_info->modes[i], &mode)) {
   724                         SDL_AddDisplayMode(sdl_display, &mode);
   725                     } else {
   726                         SDL_free(modedata);
   727                     }
   728                 }
   729             }
   730             XRRFreeOutputInfo(output_info);
   731             XRRFreeScreenResources(res);
   732         }
   733         return;
   734     }
   735 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   736 
   737 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   738     if (data->use_vidmode &&
   739         XF86VidModeGetAllModeLines(display, data->vidmode_screen, &nmodes, &modes)) {
   740         int i;
   741 
   742 #ifdef X11MODES_DEBUG
   743         printf("VidMode modes: (unsorted)\n");
   744         for (i = 0; i < nmodes; ++i) {
   745             printf("Mode %d: %d x %d @ %d, flags: 0x%x\n", i,
   746                    modes[i]->hdisplay, modes[i]->vdisplay,
   747                    CalculateXVidModeRefreshRate(modes[i]), modes[i]->flags);
   748         }
   749 #endif
   750         for (i = 0; i < nmodes; ++i) {
   751             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   752             if (!modedata) {
   753                 continue;
   754             }
   755             mode.driverdata = modedata;
   756 
   757             if (SetXVidModeModeInfo(modes[i], &mode)) {
   758                 SDL_AddDisplayMode(sdl_display, &mode);
   759             } else {
   760                 SDL_free(modedata);
   761             }
   762         }
   763         XFree(modes);
   764         return;
   765     }
   766 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   767 
   768     if (!data->use_xrandr && !data->use_vidmode) {
   769         /* Add the desktop mode */
   770         mode = sdl_display->desktop_mode;
   771         modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   772         if (modedata) {
   773             *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   774         }
   775         mode.driverdata = modedata;
   776         SDL_AddDisplayMode(sdl_display, &mode);
   777     }
   778 }
   779 
   780 int
   781 X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode)
   782 {
   783     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   784     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   785     SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
   786 
   787 #if SDL_VIDEO_DRIVER_X11_XRANDR
   788     if (data->use_xrandr) {
   789         XRRScreenResources *res;
   790         XRROutputInfo *output_info;
   791         XRRCrtcInfo *crtc;
   792         Status status;
   793 
   794         res = XRRGetScreenResources (display, RootWindow(display, data->screen));
   795         if (!res) {
   796             SDL_SetError("Couldn't get XRandR screen resources");
   797             return -1;
   798         }
   799 
   800         output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
   801         if (!output_info || output_info->connection == RR_Disconnected) {
   802             SDL_SetError("Couldn't get XRandR output info");
   803             XRRFreeScreenResources(res);
   804             return -1;
   805         }
   806 
   807         crtc = XRRGetCrtcInfo(display, res, output_info->crtc);
   808         if (!crtc) {
   809             SDL_SetError("Couldn't get XRandR crtc info");
   810             XRRFreeOutputInfo(output_info);
   811             XRRFreeScreenResources(res);
   812             return -1;
   813         }
   814 
   815         status = XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
   816           crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation,
   817           &data->xrandr_output, 1);
   818 
   819         XRRFreeCrtcInfo(crtc);
   820         XRRFreeOutputInfo(output_info);
   821         XRRFreeScreenResources(res);
   822 
   823         if (status != Success) {
   824             SDL_SetError("XRRSetCrtcConfig failed");
   825             return -1;
   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: */