src/video/x11/SDL_x11modes.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 02 Feb 2014 00:53:27 -0800
changeset 8149 681eb46b8ac4
parent 8093 b43765095a6f
child 8922 dfb6f8611ebe
permissions -rw-r--r--
Fixed bug 2374 - Update copyright for 2014...

Is it that time already??
     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     SDL_DisplayModeData *modedata;
   678 
   679     /* Unfortunately X11 requires the window to be created with the correct
   680      * visual and depth ahead of time, but the SDL API allows you to create
   681      * a window before setting the fullscreen display mode.  This means that
   682      * we have to use the same format for all windows and all display modes.
   683      * (or support recreating the window with a new visual behind the scenes)
   684      */
   685     mode.format = sdl_display->current_mode.format;
   686     mode.driverdata = NULL;
   687 
   688     screen_w = DisplayWidth(display, data->screen);
   689     screen_h = DisplayHeight(display, data->screen);
   690 
   691 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   692     if (data->use_xinerama) {
   693         if (data->use_vidmode && !data->xinerama_info.x_org && !data->xinerama_info.y_org &&
   694            (screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) {
   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             /* Add the current mode of each monitor otherwise if we can't get them from xrandr */
   711             mode.w = data->xinerama_info.width;
   712             mode.h = data->xinerama_info.height;
   713             mode.refresh_rate = 0;
   714             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   715             if (modedata) {
   716                 *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   717             }
   718             mode.driverdata = modedata;
   719             SDL_AddDisplayMode(sdl_display, &mode);
   720         }
   721 
   722     }
   723 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   724 
   725 #if SDL_VIDEO_DRIVER_X11_XRANDR
   726     if (data->use_xrandr) {
   727         XRRScreenResources *res;
   728 
   729         res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen));
   730         if (res) {
   731             SDL_DisplayModeData *modedata;
   732             XRROutputInfo *output_info;
   733             int i;
   734 
   735             output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output);
   736             if (output_info && output_info->connection != RR_Disconnected) {
   737                 for (i = 0; i < output_info->nmode; ++i) {
   738                     modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   739                     if (!modedata) {
   740                         continue;
   741                     }
   742                     mode.driverdata = modedata;
   743 
   744                     if (SetXRandRModeInfo(display, res, output_info, output_info->modes[i], &mode)) {
   745                         SDL_AddDisplayMode(sdl_display, &mode);
   746                     } else {
   747                         SDL_free(modedata);
   748                     }
   749                 }
   750             }
   751             X11_XRRFreeOutputInfo(output_info);
   752             X11_XRRFreeScreenResources(res);
   753         }
   754         return;
   755     }
   756 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   757 
   758 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   759     if (data->use_vidmode &&
   760         X11_XF86VidModeGetAllModeLines(display, data->vidmode_screen, &nmodes, &modes)) {
   761         int i;
   762 
   763 #ifdef X11MODES_DEBUG
   764         printf("VidMode modes: (unsorted)\n");
   765         for (i = 0; i < nmodes; ++i) {
   766             printf("Mode %d: %d x %d @ %d, flags: 0x%x\n", i,
   767                    modes[i]->hdisplay, modes[i]->vdisplay,
   768                    CalculateXVidModeRefreshRate(modes[i]), modes[i]->flags);
   769         }
   770 #endif
   771         for (i = 0; i < nmodes; ++i) {
   772             modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   773             if (!modedata) {
   774                 continue;
   775             }
   776             mode.driverdata = modedata;
   777 
   778             if (SetXVidModeModeInfo(modes[i], &mode)) {
   779                 SDL_AddDisplayMode(sdl_display, &mode);
   780             } else {
   781                 SDL_free(modedata);
   782             }
   783         }
   784         X11_XFree(modes);
   785         return;
   786     }
   787 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   788 
   789     if (!data->use_xrandr && !data->use_vidmode) {
   790         /* Add the desktop mode */
   791         mode = sdl_display->desktop_mode;
   792         modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
   793         if (modedata) {
   794             *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
   795         }
   796         mode.driverdata = modedata;
   797         SDL_AddDisplayMode(sdl_display, &mode);
   798     }
   799 }
   800 
   801 int
   802 X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode)
   803 {
   804     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   805     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   806     SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
   807 
   808 #if SDL_VIDEO_DRIVER_X11_XRANDR
   809     if (data->use_xrandr) {
   810         XRRScreenResources *res;
   811         XRROutputInfo *output_info;
   812         XRRCrtcInfo *crtc;
   813         Status status;
   814 
   815         res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen));
   816         if (!res) {
   817             return SDL_SetError("Couldn't get XRandR screen resources");
   818         }
   819 
   820         output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output);
   821         if (!output_info || output_info->connection == RR_Disconnected) {
   822             X11_XRRFreeScreenResources(res);
   823             return SDL_SetError("Couldn't get XRandR output info");
   824         }
   825 
   826         crtc = X11_XRRGetCrtcInfo(display, res, output_info->crtc);
   827         if (!crtc) {
   828             X11_XRRFreeOutputInfo(output_info);
   829             X11_XRRFreeScreenResources(res);
   830             return SDL_SetError("Couldn't get XRandR crtc info");
   831         }
   832 
   833         status = X11_XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
   834           crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation,
   835           &data->xrandr_output, 1);
   836 
   837         X11_XRRFreeCrtcInfo(crtc);
   838         X11_XRRFreeOutputInfo(output_info);
   839         X11_XRRFreeScreenResources(res);
   840 
   841         if (status != Success) {
   842             return SDL_SetError("X11_XRRSetCrtcConfig failed");
   843         }
   844     }
   845 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   846 
   847 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   848     if (data->use_vidmode) {
   849         X11_XF86VidModeSwitchToMode(display, data->vidmode_screen, &modedata->vm_mode);
   850     }
   851 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   852 
   853     return 0;
   854 }
   855 
   856 void
   857 X11_QuitModes(_THIS)
   858 {
   859 }
   860 
   861 int
   862 X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect)
   863 {
   864     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   865 
   866     rect->x = data->x;
   867     rect->y = data->y;
   868     rect->w = sdl_display->current_mode.w;
   869     rect->h = sdl_display->current_mode.h;
   870 
   871 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   872     /* Get the real current bounds of the display */
   873     if (data->use_xinerama) {
   874         Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   875         int screencount;
   876         XineramaScreenInfo *xinerama = X11_XineramaQueryScreens(display, &screencount);
   877         if (xinerama) {
   878             rect->x = xinerama[data->xinerama_screen].x_org;
   879             rect->y = xinerama[data->xinerama_screen].y_org;
   880             X11_XFree(xinerama);
   881         }
   882     }
   883 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   884     return 0;
   885 }
   886 
   887 #endif /* SDL_VIDEO_DRIVER_X11 */
   888 
   889 /* vi: set ts=4 sw=4 expandtab: */