src/video/x11/SDL_x11modes.c
author Gabriel Jacobo <gabomdq@gmail.com>
Wed, 21 Aug 2013 09:47:10 -0300
changeset 7678 286c42d7c5ed
parent 7677 871d43c6968a
child 7827 a03ec8de0426
permissions -rw-r--r--
OCD fixes: Adds a space after /* (glory to regular expressions!)
     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         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             /* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0
   695              * if we're using vidmode.
   696              */
   697             mode.w = screen_w;
   698             mode.h = screen_h;
   699             mode.refresh_rate = 0;
   700             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   701             if (modedata) {
   702                 *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   703             }
   704             mode.driverdata = modedata;
   705             SDL_AddDisplayMode(sdl_display, &mode);
   706         }
   707         else if (!data->use_xrandr)
   708         {
   709             /* Add the current mode of each monitor otherwise if we can't get them from xrandr */
   710             mode.w = data->xinerama_info.width;
   711             mode.h = data->xinerama_info.height;
   712             mode.refresh_rate = 0;
   713             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   714             if (modedata) {
   715                 *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   716             }
   717             mode.driverdata = modedata;
   718             SDL_AddDisplayMode(sdl_display, &mode);
   719         }
   720 
   721     }
   722 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   723 
   724 #if SDL_VIDEO_DRIVER_X11_XRANDR
   725     if (data->use_xrandr) {
   726         XRRScreenResources *res;
   727 
   728         res = XRRGetScreenResources (display, RootWindow(display, data->screen));
   729         if (res) {
   730             SDL_DisplayModeData *modedata;
   731             XRROutputInfo *output_info;
   732             int i;
   733 
   734             output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
   735             if (output_info && output_info->connection != RR_Disconnected) {
   736                 for (i = 0; i < output_info->nmode; ++i) {
   737                     modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   738                     if (!modedata) {
   739                         continue;
   740                     }
   741                     mode.driverdata = modedata;
   742 
   743                     if (SetXRandRModeInfo(display, res, output_info, output_info->modes[i], &mode)) {
   744                         SDL_AddDisplayMode(sdl_display, &mode);
   745                     } else {
   746                         SDL_free(modedata);
   747                     }
   748                 }
   749             }
   750             XRRFreeOutputInfo(output_info);
   751             XRRFreeScreenResources(res);
   752         }
   753         return;
   754     }
   755 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   756 
   757 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   758     if (data->use_vidmode &&
   759         XF86VidModeGetAllModeLines(display, data->vidmode_screen, &nmodes, &modes)) {
   760         int i;
   761 
   762 #ifdef X11MODES_DEBUG
   763         printf("VidMode modes: (unsorted)\n");
   764         for (i = 0; i < nmodes; ++i) {
   765             printf("Mode %d: %d x %d @ %d, flags: 0x%x\n", i,
   766                    modes[i]->hdisplay, modes[i]->vdisplay,
   767                    CalculateXVidModeRefreshRate(modes[i]), modes[i]->flags);
   768         }
   769 #endif
   770         for (i = 0; i < nmodes; ++i) {
   771             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   772             if (!modedata) {
   773                 continue;
   774             }
   775             mode.driverdata = modedata;
   776 
   777             if (SetXVidModeModeInfo(modes[i], &mode)) {
   778                 SDL_AddDisplayMode(sdl_display, &mode);
   779             } else {
   780                 SDL_free(modedata);
   781             }
   782         }
   783         XFree(modes);
   784         return;
   785     }
   786 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   787 
   788     if (!data->use_xrandr && !data->use_vidmode) {
   789         /* Add the desktop mode */
   790         mode = sdl_display->desktop_mode;
   791         modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   792         if (modedata) {
   793             *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   794         }
   795         mode.driverdata = modedata;
   796         SDL_AddDisplayMode(sdl_display, &mode);
   797     }
   798 }
   799 
   800 int
   801 X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode)
   802 {
   803     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   804     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   805     SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
   806 
   807 #if SDL_VIDEO_DRIVER_X11_XRANDR
   808     if (data->use_xrandr) {
   809         XRRScreenResources *res;
   810         XRROutputInfo *output_info;
   811         XRRCrtcInfo *crtc;
   812         Status status;
   813 
   814         res = XRRGetScreenResources (display, RootWindow(display, data->screen));
   815         if (!res) {
   816             return SDL_SetError("Couldn't get XRandR screen resources");
   817         }
   818 
   819         output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
   820         if (!output_info || output_info->connection == RR_Disconnected) {
   821             XRRFreeScreenResources(res);
   822             return SDL_SetError("Couldn't get XRandR output info");
   823         }
   824 
   825         crtc = XRRGetCrtcInfo(display, res, output_info->crtc);
   826         if (!crtc) {
   827             XRRFreeOutputInfo(output_info);
   828             XRRFreeScreenResources(res);
   829             return SDL_SetError("Couldn't get XRandR crtc info");
   830         }
   831 
   832         status = XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
   833           crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation,
   834           &data->xrandr_output, 1);
   835 
   836         XRRFreeCrtcInfo(crtc);
   837         XRRFreeOutputInfo(output_info);
   838         XRRFreeScreenResources(res);
   839 
   840         if (status != Success) {
   841             return SDL_SetError("XRRSetCrtcConfig failed");
   842         }
   843     }
   844 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   845 
   846 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   847     if (data->use_vidmode) {
   848         XF86VidModeSwitchToMode(display, data->vidmode_screen, &modedata->vm_mode);
   849     }
   850 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   851 
   852     return 0;
   853 }
   854 
   855 void
   856 X11_QuitModes(_THIS)
   857 {
   858 }
   859 
   860 int
   861 X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect)
   862 {
   863     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   864 
   865     rect->x = data->x;
   866     rect->y = data->y;
   867     rect->w = sdl_display->current_mode.w;
   868     rect->h = sdl_display->current_mode.h;
   869 
   870 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   871     /* Get the real current bounds of the display */
   872     if (data->use_xinerama) {
   873         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   874         int screencount;
   875         XineramaScreenInfo *xinerama = XineramaQueryScreens(display, &screencount);
   876         if (xinerama) {
   877             rect->x = xinerama[data->xinerama_screen].x_org;
   878             rect->y = xinerama[data->xinerama_screen].y_org;
   879             XFree(xinerama);
   880         }
   881     }
   882 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   883     return 0;
   884 }
   885 
   886 #endif /* SDL_VIDEO_DRIVER_X11 */
   887 
   888 /* vi: set ts=4 sw=4 expandtab: */