src/video/x11/SDL_x11modes.c
author Ryan C. Gordon
Mon, 24 Oct 2011 15:33:58 -0400
changeset 6027 56185b574d61
parent 5535 96594ac5fd1a
child 6138 4c64952a58fb
permissions -rw-r--r--
Use correct Xinerama APIs for querying version and availability.

Fixes Bugzilla #1314.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2011 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_x11video.h"
    26 
    27 /*#define X11MODES_DEBUG*/
    28 
    29 static int
    30 get_visualinfo(Display * display, int screen, XVisualInfo * vinfo)
    31 {
    32     const char *visual_id = SDL_getenv("SDL_VIDEO_X11_VISUALID");
    33     int depth;
    34 
    35     /* Look for an exact visual, if requested */
    36     if (visual_id) {
    37         XVisualInfo *vi, template;
    38         int nvis;
    39 
    40         SDL_zero(template);
    41         template.visualid = SDL_strtol(visual_id, NULL, 0);
    42         vi = XGetVisualInfo(display, VisualIDMask, &template, &nvis);
    43         if (vi) {
    44             *vinfo = *vi;
    45             XFree(vi);
    46             return 0;
    47         }
    48     }
    49 
    50     depth = DefaultDepth(display, screen);
    51     if ((X11_UseDirectColorVisuals() &&
    52          XMatchVisualInfo(display, screen, depth, DirectColor, vinfo)) ||
    53         XMatchVisualInfo(display, screen, depth, TrueColor, vinfo) ||
    54         XMatchVisualInfo(display, screen, depth, PseudoColor, vinfo) ||
    55         XMatchVisualInfo(display, screen, depth, StaticColor, vinfo)) {
    56         return 0;
    57     }
    58     return -1;
    59 }
    60 
    61 int
    62 X11_GetVisualInfoFromVisual(Display * display, Visual * visual, XVisualInfo * vinfo)
    63 {
    64     XVisualInfo *vi;
    65     int nvis;
    66 
    67     vinfo->visualid = XVisualIDFromVisual(visual);
    68     vi = XGetVisualInfo(display, VisualIDMask, vinfo, &nvis);
    69     if (vi) {
    70         *vinfo = *vi;
    71         XFree(vi);
    72         return 0;
    73     }
    74     return -1;
    75 }
    76 
    77 Uint32
    78 X11_GetPixelFormatFromVisualInfo(Display * display, XVisualInfo * vinfo)
    79 {
    80     if (vinfo->class == DirectColor || vinfo->class == TrueColor) {
    81         int bpp;
    82         Uint32 Rmask, Gmask, Bmask, Amask;
    83 
    84         Rmask = vinfo->visual->red_mask;
    85         Gmask = vinfo->visual->green_mask;
    86         Bmask = vinfo->visual->blue_mask;
    87         if (vinfo->depth == 32) {
    88             Amask = (0xFFFFFFFF & ~(Rmask | Gmask | Bmask));
    89         } else {
    90             Amask = 0;
    91         }
    92 
    93         bpp = vinfo->depth;
    94         if (bpp == 24) {
    95             int i, n;
    96             XPixmapFormatValues *p = XListPixmapFormats(display, &n);
    97             if (p) {
    98                 for (i = 0; i < n; ++i) {
    99                     if (p[i].depth == 24) {
   100                         bpp = p[i].bits_per_pixel;
   101                         break;
   102                     }
   103                 }
   104                 XFree(p);
   105             }
   106         }
   107 
   108         return SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
   109     }
   110 
   111     if (vinfo->class == PseudoColor || vinfo->class == StaticColor) {
   112         switch (vinfo->depth) {
   113         case 8:
   114             return SDL_PIXELTYPE_INDEX8;
   115         case 4:
   116             if (BitmapBitOrder(display) == LSBFirst) {
   117                 return SDL_PIXELFORMAT_INDEX4LSB;
   118             } else {
   119                 return SDL_PIXELFORMAT_INDEX4MSB;
   120             }
   121             break;
   122         case 1:
   123             if (BitmapBitOrder(display) == LSBFirst) {
   124                 return SDL_PIXELFORMAT_INDEX1LSB;
   125             } else {
   126                 return SDL_PIXELFORMAT_INDEX1MSB;
   127             }
   128             break;
   129         }
   130     }
   131 
   132     return SDL_PIXELFORMAT_UNKNOWN;
   133 }
   134 
   135 int
   136 X11_InitModes(_THIS)
   137 {
   138     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   139     int screen;
   140 
   141     for (screen = 0; screen < ScreenCount(data->display); ++screen) {
   142         XVisualInfo vinfo;
   143         SDL_VideoDisplay display;
   144         SDL_DisplayData *displaydata;
   145         SDL_DisplayMode mode;
   146         XPixmapFormatValues *pixmapFormats;
   147         int i, n;
   148 
   149         if (get_visualinfo(data->display, screen, &vinfo) < 0) {
   150             continue;
   151         }
   152 
   153         mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
   154         if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
   155             /* We don't support palettized modes now */
   156             continue;
   157         }
   158         mode.w = DisplayWidth(data->display, screen);
   159         mode.h = DisplayHeight(data->display, screen);
   160         mode.refresh_rate = 0;
   161         mode.driverdata = NULL;
   162 
   163         displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata));
   164         if (!displaydata) {
   165             continue;
   166         }
   167         displaydata->screen = screen;
   168         displaydata->visual = vinfo.visual;
   169         displaydata->depth = vinfo.depth;
   170 
   171         displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8;
   172         pixmapFormats = XListPixmapFormats(data->display, &n);
   173         if (pixmapFormats) {
   174             for (i = 0; i < n; ++i) {
   175                 if (pixmapFormats[i].depth == displaydata->depth) {
   176                     displaydata->scanline_pad = pixmapFormats[i].scanline_pad;
   177                     break;
   178                 }
   179             }
   180             XFree(pixmapFormats);
   181         }
   182 
   183         SDL_zero(display);
   184         display.desktop_mode = mode;
   185         display.current_mode = mode;
   186         display.driverdata = displaydata;
   187         SDL_AddVideoDisplay(&display);
   188     }
   189     if (_this->num_displays == 0) {
   190         SDL_SetError("No available displays");
   191         return -1;
   192     }
   193     return 0;
   194 }
   195 
   196 /* Global for the error handler */
   197 int vm_event, vm_error = -1;
   198 
   199 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   200 static SDL_bool
   201 CheckXinerama(Display * display, int *major, int *minor)
   202 {
   203     int event_base = 0;
   204     int error_base = 0;
   205     const char *env;
   206 
   207     /* Default the extension not available */
   208     *major = *minor = 0;
   209 
   210     /* Allow environment override */
   211     env = getenv("SDL_VIDEO_X11_XINERAMA");
   212     if (env && !SDL_atoi(env)) {
   213         return SDL_FALSE;
   214     }
   215 
   216     if (!SDL_X11_HAVE_XINERAMA) {
   217         return SDL_FALSE;
   218     }
   219 
   220     /* Query the extension version */
   221     if (!XineramaQueryExtension(display, &event_base, &error_base) ||
   222         !XineramaQueryVersion(display, major, minor) ||
   223         !XineramaIsActive(display)) {
   224         return SDL_FALSE;
   225     }
   226     return SDL_TRUE;
   227 }
   228 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   229 
   230 #if SDL_VIDEO_DRIVER_X11_XRANDR
   231 static SDL_bool
   232 CheckXRandR(Display * display, int *major, int *minor)
   233 {
   234     const char *env;
   235 
   236     /* Default the extension not available */
   237     *major = *minor = 0;
   238 
   239     /* Allow environment override */
   240     env = getenv("SDL_VIDEO_X11_XRANDR");
   241     if (env && !SDL_atoi(env)) {
   242         return SDL_FALSE;
   243     }
   244 
   245     if (!SDL_X11_HAVE_XRANDR) {
   246         return SDL_FALSE;
   247     }
   248 
   249     /* Query the extension version */
   250     if (!XRRQueryVersion(display, major, minor)) {
   251         return SDL_FALSE;
   252     }
   253     return SDL_TRUE;
   254 }
   255 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   256 
   257 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   258 static SDL_bool
   259 CheckVidMode(Display * display, int *major, int *minor)
   260 {
   261     const char *env;
   262 
   263     /* Default the extension not available */
   264     *major = *minor = 0;
   265 
   266     /* Allow environment override */
   267     env = getenv("SDL_VIDEO_X11_XVIDMODE");
   268     if (env && !SDL_atoi(env)) {
   269         return SDL_FALSE;
   270     }
   271 
   272     if (!SDL_X11_HAVE_XVIDMODE) {
   273         return SDL_FALSE;
   274     }
   275 
   276     /* Query the extension version */
   277     vm_error = -1;
   278     if (!XF86VidModeQueryExtension(display, &vm_event, &vm_error)
   279         || !XF86VidModeQueryVersion(display, major, minor)) {
   280         return SDL_FALSE;
   281     }
   282     return SDL_TRUE;
   283 }
   284 
   285 static
   286 Bool XF86VidModeGetModeInfo(Display * dpy, int scr,
   287                                        XF86VidModeModeInfo* info)
   288 {
   289     Bool retval;
   290     int dotclock;
   291     XF86VidModeModeLine l;
   292     SDL_zerop(info);
   293     SDL_zero(l);
   294     retval = XF86VidModeGetModeLine(dpy, scr, &dotclock, &l);
   295     info->dotclock = dotclock;
   296     info->hdisplay = l.hdisplay;
   297     info->hsyncstart = l.hsyncstart;
   298     info->hsyncend = l.hsyncend;
   299     info->htotal = l.htotal;
   300     info->hskew = l.hskew;
   301     info->vdisplay = l.vdisplay;
   302     info->vsyncstart = l.vsyncstart;
   303     info->vsyncend = l.vsyncend;
   304     info->vtotal = l.vtotal;
   305     info->flags = l.flags;
   306     info->privsize = l.privsize;
   307     info->private = l.private;
   308     return retval;
   309 }
   310 
   311 static int
   312 calculate_rate(XF86VidModeModeInfo * info)
   313 {
   314     return (info->htotal
   315             && info->vtotal) ? (1000 * info->dotclock / (info->htotal *
   316                                                          info->vtotal)) : 0;
   317 }
   318 
   319 static void
   320 save_mode(Display * display, SDL_DisplayData * data)
   321 {
   322     XF86VidModeGetModeInfo(display, data->screen,
   323                                     &data->saved_mode);
   324     XF86VidModeGetViewPort(display, data->screen,
   325                                     &data->saved_view.x,
   326                                     &data->saved_view.y);
   327 }
   328 
   329 /*
   330 static void
   331 restore_mode(Display * display, SDL_DisplayData * data)
   332 {
   333     XF86VidModeModeInfo mode;
   334 
   335     if (XF86VidModeGetModeInfo(display, data->screen, &mode)) {
   336         if (SDL_memcmp(&mode, &data->saved_mode, sizeof(mode)) != 0) {
   337             XF86VidModeSwitchToMode(display, data->screen, &data->saved_mode);
   338         }
   339     }
   340     if ((data->saved_view.x != 0) || (data->saved_view.y != 0)) {
   341         XF86VidModeSetViewPort(display, data->screen,
   342                                         data->saved_view.x,
   343                                         data->saved_view.y);
   344     }
   345 }
   346 */
   347 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   348 
   349 void
   350 X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display)
   351 {
   352     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   353     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   354 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   355     int xinerama_major, xinerama_minor;
   356     int screens;
   357     XineramaScreenInfo * xinerama;
   358 #endif
   359 #if SDL_VIDEO_DRIVER_X11_XRANDR
   360     int xrandr_major, xrandr_minor;
   361     int nsizes, nrates;
   362     XRRScreenSize *sizes;
   363     short *rates;
   364 #endif
   365 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   366     int vm_major, vm_minor;
   367     int nmodes;
   368     XF86VidModeModeInfo ** modes;
   369 #endif
   370     int screen_w;
   371     int screen_h;
   372     SDL_DisplayMode mode;
   373 
   374     /* Unfortunately X11 requires the window to be created with the correct
   375      * visual and depth ahead of time, but the SDL API allows you to create
   376      * a window before setting the fullscreen display mode.  This means that
   377      * we have to use the same format for all windows and all display modes.
   378      * (or support recreating the window with a new visual behind the scenes)
   379      */
   380     mode.format = sdl_display->current_mode.format;
   381     mode.driverdata = NULL;
   382 
   383     data->use_xinerama = 0;
   384     data->use_xrandr = 0;
   385     data->use_vidmode = 0;
   386     screen_w = DisplayWidth(display, data->screen);
   387     screen_h = DisplayHeight(display, data->screen);
   388 
   389 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   390     /* Query Xinerama extention */
   391     if (CheckXinerama(display, &xinerama_major, &xinerama_minor)) {
   392 #ifdef X11MODES_DEBUG
   393         printf("X11 detected Xinerama:\n");
   394 #endif
   395         xinerama = XineramaQueryScreens(display, &screens);
   396         if (xinerama) {
   397             int i;
   398             for (i = 0; i < screens; i++) {
   399 #ifdef X11MODES_DEBUG
   400                 printf("xinerama %d: %dx%d+%d+%d\n",
   401                        xinerama[i].screen_number,
   402                        xinerama[i].width, xinerama[i].height,
   403                        xinerama[i].x_org, xinerama[i].y_org);
   404 #endif
   405                 if (xinerama[i].screen_number == data->screen) {
   406                     data->use_xinerama =
   407                         xinerama_major * 100 + xinerama_minor;
   408                     data->xinerama_info = xinerama[i];
   409                 }
   410             }
   411             XFree(xinerama);
   412         }
   413 
   414         if (data->use_xinerama) {
   415             /* Add the full xinerama mode */
   416             if (screen_w > data->xinerama_info.width ||
   417                 screen_h > data->xinerama_info.height) {
   418                 mode.w = screen_w;
   419                 mode.h = screen_h;
   420                 mode.refresh_rate = 0;
   421                 SDL_AddDisplayMode(sdl_display, &mode);
   422             }
   423 
   424             /* Add the head xinerama mode */
   425             mode.w = data->xinerama_info.width;
   426             mode.h = data->xinerama_info.height;
   427             mode.refresh_rate = 0;
   428             SDL_AddDisplayMode(sdl_display, &mode);
   429         }
   430     }
   431 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   432 
   433 #if SDL_VIDEO_DRIVER_X11_XRANDR
   434     /* XRandR */
   435     /* require at least XRandR v1.0 (arbitrary) */
   436     if (CheckXRandR(display, &xrandr_major, &xrandr_minor)
   437         && xrandr_major >= 1) {
   438 #ifdef X11MODES_DEBUG
   439         fprintf(stderr, "XRANDR: XRRQueryVersion: V%d.%d\n",
   440                 xrandr_major, xrandr_minor);
   441 #endif
   442 
   443         /* save the screen configuration since we must reference it
   444            each time we toggle modes.
   445          */
   446         data->screen_config =
   447             XRRGetScreenInfo(display, RootWindow(display, data->screen));
   448 
   449         /* retrieve the list of resolution */
   450         sizes = XRRConfigSizes(data->screen_config, &nsizes);
   451         if (nsizes > 0) {
   452             int i, j;
   453             for (i = 0; i < nsizes; i++) {
   454                 mode.w = sizes[i].width;
   455                 mode.h = sizes[i].height;
   456 
   457                 rates = XRRConfigRates(data->screen_config, i, &nrates);
   458                 for (j = 0; j < nrates; ++j) {
   459                     mode.refresh_rate = rates[j];
   460 #ifdef X11MODES_DEBUG
   461                     fprintf(stderr,
   462                             "XRANDR: mode = %4d[%d], w = %4d, h = %4d, rate = %4d\n",
   463                             i, j, mode.w, mode.h, mode.refresh_rate);
   464 #endif
   465                     SDL_AddDisplayMode(sdl_display, &mode);
   466                 }
   467             }
   468 
   469             data->use_xrandr = xrandr_major * 100 + xrandr_minor;
   470             data->saved_size =
   471                 XRRConfigCurrentConfiguration(data->screen_config,
   472                                               &data->saved_rotation);
   473             data->saved_rate = XRRConfigCurrentRate(data->screen_config);
   474         }
   475     }
   476 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   477 
   478 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   479     /* XVidMode */
   480     if (!data->use_xrandr &&
   481 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   482         (!data->use_xinerama || data->xinerama_info.screen_number == 0) &&
   483 #endif
   484         CheckVidMode(display, &vm_major, &vm_minor) &&
   485         XF86VidModeGetAllModeLines(display, data->screen, &nmodes, &modes)) {
   486         int i;
   487 
   488 #ifdef X11MODES_DEBUG
   489         printf("VidMode modes: (unsorted)\n");
   490         for (i = 0; i < nmodes; ++i) {
   491             printf("Mode %d: %d x %d @ %d\n", i,
   492                    modes[i]->hdisplay, modes[i]->vdisplay,
   493                    calculate_rate(modes[i]));
   494         }
   495 #endif
   496         for (i = 0; i < nmodes; ++i) {
   497             mode.w = modes[i]->hdisplay;
   498             mode.h = modes[i]->vdisplay;
   499             mode.refresh_rate = calculate_rate(modes[i]);
   500             SDL_AddDisplayMode(sdl_display, &mode);
   501         }
   502         XFree(modes);
   503 
   504         data->use_vidmode = vm_major * 100 + vm_minor;
   505         save_mode(display, data);
   506     }
   507 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   508 
   509     if (!data->use_xrandr && !data->use_vidmode) {
   510         mode.w = screen_w;
   511         mode.h = screen_h;
   512         mode.refresh_rate = 0;
   513         SDL_AddDisplayMode(sdl_display, &mode);
   514     }
   515 #ifdef X11MODES_DEBUG
   516     if (data->use_xinerama) {
   517         printf("Xinerama is enabled\n");
   518     }
   519 
   520     if (data->use_xrandr) {
   521         printf("XRandR is enabled\n");
   522     }
   523 
   524     if (data->use_vidmode) {
   525         printf("VidMode is enabled\n");
   526     }
   527 #endif /* X11MODES_DEBUG */
   528 }
   529 
   530 static void
   531 get_real_resolution(Display * display, SDL_DisplayData * data, int *w, int *h,
   532                     int *rate)
   533 {
   534 #if SDL_VIDEO_DRIVER_X11_XRANDR
   535     if (data->use_xrandr) {
   536         int nsizes;
   537         XRRScreenSize *sizes;
   538 
   539         sizes = XRRConfigSizes(data->screen_config, &nsizes);
   540         if (nsizes > 0) {
   541             int cur_size;
   542             Rotation cur_rotation;
   543 
   544             cur_size =
   545                 XRRConfigCurrentConfiguration(data->screen_config,
   546                                               &cur_rotation);
   547             *w = sizes[cur_size].width;
   548             *h = sizes[cur_size].height;
   549             *rate = XRRConfigCurrentRate(data->screen_config);
   550 #ifdef X11MODES_DEBUG
   551             fprintf(stderr,
   552                     "XRANDR: get_real_resolution: w = %d, h = %d, rate = %d\n",
   553                     *w, *h, *rate);
   554 #endif
   555             return;
   556         }
   557     }
   558 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   559 
   560 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   561     if (data->use_vidmode) {
   562         XF86VidModeModeInfo mode;
   563 
   564         if (XF86VidModeGetModeInfo(display, data->screen, &mode)) {
   565             *w = mode.hdisplay;
   566             *h = mode.vdisplay;
   567             *rate = calculate_rate(&mode);
   568             return;
   569         }
   570     }
   571 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   572 
   573 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   574     if (data->use_xinerama) {
   575         *w = data->xinerama_info.width;
   576         *h = data->xinerama_info.height;
   577         *rate = 0;
   578         return;
   579     }
   580 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   581 
   582     *w = DisplayWidth(display, data->screen);
   583     *h = DisplayHeight(display, data->screen);
   584     *rate = 0;
   585 }
   586 
   587 static void
   588 set_best_resolution(Display * display, SDL_DisplayData * data, int w, int h,
   589                     int rate)
   590 {
   591     int real_w, real_h, real_rate;
   592 
   593     /* check current mode so we can avoid uneccessary mode changes */
   594     get_real_resolution(display, data, &real_w, &real_h, &real_rate);
   595     if (w == real_w && h == real_h && (!rate || rate == real_rate)) {
   596         return;
   597     }
   598 #if SDL_VIDEO_DRIVER_X11_XRANDR
   599     if (data->use_xrandr) {
   600 #ifdef X11MODES_DEBUG
   601         fprintf(stderr, "XRANDR: set_best_resolution(): w = %d, h = %d\n",
   602                 w, h);
   603 #endif
   604         int i, nsizes, nrates;
   605         int best;
   606         int best_rate;
   607         XRRScreenSize *sizes;
   608         short *rates;
   609 
   610         /* find the smallest resolution that is at least as big as the user requested */
   611         best = -1;
   612         sizes = XRRConfigSizes(data->screen_config, &nsizes);
   613         for (i = 0; i < nsizes; ++i) {
   614             if (sizes[i].width < w || sizes[i].height < h) {
   615                 continue;
   616             }
   617             if (sizes[i].width == w && sizes[i].height == h) {
   618                 best = i;
   619                 break;
   620             }
   621             if (best == -1 ||
   622                 (sizes[i].width < sizes[best].width) ||
   623                 (sizes[i].width == sizes[best].width
   624                  && sizes[i].height < sizes[best].height)) {
   625                 best = i;
   626             }
   627         }
   628 
   629         if (best >= 0) {
   630             best_rate = 0;
   631             rates = XRRConfigRates(data->screen_config, best, &nrates);
   632             for (i = 0; i < nrates; ++i) {
   633                 if (rates[i] == rate) {
   634                     best_rate = rate;
   635                     break;
   636                 }
   637                 if (!rate) {
   638                     /* Higher is better, right? */
   639                     if (rates[i] > best_rate) {
   640                         best_rate = rates[i];
   641                     }
   642                 } else {
   643                     if (SDL_abs(rates[i] - rate) < SDL_abs(best_rate - rate)) {
   644                         best_rate = rates[i];
   645                     }
   646                 }
   647             }
   648             XRRSetScreenConfigAndRate(display, data->screen_config,
   649                                       RootWindow(display, data->screen), best,
   650                                       data->saved_rotation, best_rate,
   651                                       CurrentTime);
   652         }
   653         return;
   654     }
   655 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
   656 
   657 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
   658     if (data->use_vidmode) {
   659         XF86VidModeModeInfo ** modes;
   660         int i, nmodes;
   661         int best;
   662 
   663         if (XF86VidModeGetAllModeLines(display, data->screen, &nmodes, &modes)) {
   664             best = -1;
   665             for (i = 0; i < nmodes; ++i) {
   666                 if (modes[i]->hdisplay < w || modes[i]->vdisplay < h) {
   667                     continue;
   668                 }
   669                 if (best == -1 ||
   670                     (modes[i]->hdisplay < modes[best]->hdisplay) ||
   671                     (modes[i]->hdisplay == modes[best]->hdisplay
   672                      && modes[i]->vdisplay < modes[best]->vdisplay)) {
   673                     best = i;
   674                     continue;
   675                 }
   676                 if ((modes[i]->hdisplay == modes[best]->hdisplay) &&
   677                     (modes[i]->vdisplay == modes[best]->vdisplay)) {
   678                     if (!rate) {
   679                         /* Higher is better, right? */
   680                         if (calculate_rate(modes[i]) >
   681                             calculate_rate(modes[best])) {
   682                             best = i;
   683                         }
   684                     } else {
   685                         if (SDL_abs(calculate_rate(modes[i]) - rate) <
   686                             SDL_abs(calculate_rate(modes[best]) - rate)) {
   687                             best = i;
   688                         }
   689                     }
   690                 }
   691             }
   692             if (best >= 0) {
   693 #ifdef X11MODES_DEBUG
   694                 printf("Best Mode %d: %d x %d @ %d\n", best,
   695                        modes[best]->hdisplay, modes[best]->vdisplay,
   696                        calculate_rate(modes[best]));
   697 #endif
   698                 XF86VidModeSwitchToMode(display, data->screen, modes[best]);
   699             }
   700             XFree(modes);
   701         }
   702         return;
   703     }
   704 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
   705 }
   706 
   707 int
   708 X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode)
   709 {
   710     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
   711     SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
   712 
   713     set_best_resolution(display, data, mode->w, mode->h, mode->refresh_rate);
   714     return 0;
   715 }
   716 
   717 void
   718 X11_QuitModes(_THIS)
   719 {
   720 }
   721 
   722 #endif /* SDL_VIDEO_DRIVER_X11 */
   723 
   724 /* vi: set ts=4 sw=4 expandtab: */