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