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