/* Simple DirectMedia Layer Copyright (C) 1997-2012 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include "SDL_config.h" #if SDL_VIDEO_DRIVER_X11 #include "SDL_hints.h" #include "SDL_x11video.h" #define X11MODES_DEBUG static int get_visualinfo(Display * display, int screen, XVisualInfo * vinfo) { const char *visual_id = SDL_getenv("SDL_VIDEO_X11_VISUALID"); int depth; /* Look for an exact visual, if requested */ if (visual_id) { XVisualInfo *vi, template; int nvis; SDL_zero(template); template.visualid = SDL_strtol(visual_id, NULL, 0); vi = XGetVisualInfo(display, VisualIDMask, &template, &nvis); if (vi) { *vinfo = *vi; XFree(vi); return 0; } } depth = DefaultDepth(display, screen); if ((X11_UseDirectColorVisuals() && XMatchVisualInfo(display, screen, depth, DirectColor, vinfo)) || XMatchVisualInfo(display, screen, depth, TrueColor, vinfo) || XMatchVisualInfo(display, screen, depth, PseudoColor, vinfo) || XMatchVisualInfo(display, screen, depth, StaticColor, vinfo)) { return 0; } return -1; } int X11_GetVisualInfoFromVisual(Display * display, Visual * visual, XVisualInfo * vinfo) { XVisualInfo *vi; int nvis; vinfo->visualid = XVisualIDFromVisual(visual); vi = XGetVisualInfo(display, VisualIDMask, vinfo, &nvis); if (vi) { *vinfo = *vi; XFree(vi); return 0; } return -1; } Uint32 X11_GetPixelFormatFromVisualInfo(Display * display, XVisualInfo * vinfo) { if (vinfo->class == DirectColor || vinfo->class == TrueColor) { int bpp; Uint32 Rmask, Gmask, Bmask, Amask; Rmask = vinfo->visual->red_mask; Gmask = vinfo->visual->green_mask; Bmask = vinfo->visual->blue_mask; if (vinfo->depth == 32) { Amask = (0xFFFFFFFF & ~(Rmask | Gmask | Bmask)); } else { Amask = 0; } bpp = vinfo->depth; if (bpp == 24) { int i, n; XPixmapFormatValues *p = XListPixmapFormats(display, &n); if (p) { for (i = 0; i < n; ++i) { if (p[i].depth == 24) { bpp = p[i].bits_per_pixel; break; } } XFree(p); } } return SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask); } if (vinfo->class == PseudoColor || vinfo->class == StaticColor) { switch (vinfo->depth) { case 8: return SDL_PIXELTYPE_INDEX8; case 4: if (BitmapBitOrder(display) == LSBFirst) { return SDL_PIXELFORMAT_INDEX4LSB; } else { return SDL_PIXELFORMAT_INDEX4MSB; } break; case 1: if (BitmapBitOrder(display) == LSBFirst) { return SDL_PIXELFORMAT_INDEX1LSB; } else { return SDL_PIXELFORMAT_INDEX1MSB; } break; } } return SDL_PIXELFORMAT_UNKNOWN; } #if SDL_VIDEO_DRIVER_X11_XINERAMA static SDL_bool CheckXinerama(Display * display, int *major, int *minor); #endif int X11_InitModes(_THIS) { SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; int screen, screencount; #if SDL_VIDEO_DRIVER_X11_XINERAMA int xinerama_major, xinerama_minor; XineramaScreenInfo * xinerama = NULL; /* Query Xinerama extention * NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012) * or newer of the Nvidia binary drivers */ if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) { xinerama = XineramaQueryScreens(data->display, &screencount); } if (!xinerama) { screencount = ScreenCount(data->display); } #else screencount = ScreenCount(data->display); #endif for (screen = 0; screen < screencount; ++screen) { XVisualInfo vinfo; SDL_VideoDisplay display; SDL_DisplayData *displaydata; SDL_DisplayMode mode; XPixmapFormatValues *pixmapFormats; int i, n; #if SDL_VIDEO_DRIVER_X11_XINERAMA if (xinerama) { if (get_visualinfo(data->display, 0, &vinfo) < 0) { continue; } } else { if (get_visualinfo(data->display, screen, &vinfo) < 0) { continue; } } #else if (get_visualinfo(data->display, screen, &vinfo) < 0) { continue; } #endif mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo); if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) { /* We don't support palettized modes now */ continue; } #if SDL_VIDEO_DRIVER_X11_XINERAMA if (xinerama) { mode.w = xinerama[screen].width; mode.h = xinerama[screen].height; } else { mode.w = DisplayWidth(data->display, screen); mode.h = DisplayHeight(data->display, screen); } #else mode.w = DisplayWidth(data->display, screen); mode.h = DisplayHeight(data->display, screen); #endif mode.refresh_rate = 0; mode.driverdata = NULL; displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata)); if (!displaydata) { continue; } #if SDL_VIDEO_DRIVER_X11_XINERAMA /* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active, * there's only one screen available. So we force the screen number to zero and * let Xinerama specific code handle specific functionality using displaydata->xinerama_info */ if (xinerama) { displaydata->screen = 0; displaydata->use_xinerama = xinerama_major * 100 + xinerama_minor; displaydata->xinerama_info = xinerama[screen]; displaydata->xinerama_screen = screen; } else displaydata->screen = screen; #else displaydata->screen = screen; #endif displaydata->visual = vinfo.visual; displaydata->depth = vinfo.depth; displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8; pixmapFormats = XListPixmapFormats(data->display, &n); if (pixmapFormats) { for (i = 0; i < n; ++i) { if (pixmapFormats[i].depth == displaydata->depth) { displaydata->scanline_pad = pixmapFormats[i].scanline_pad; break; } } XFree(pixmapFormats); } SDL_zero(display); display.desktop_mode = mode; display.current_mode = mode; display.driverdata = displaydata; SDL_AddVideoDisplay(&display); } #if SDL_VIDEO_DRIVER_X11_XINERAMA if (xinerama) XFree(xinerama); #endif if (_this->num_displays == 0) { SDL_SetError("No available displays"); return -1; } return 0; } /* Global for the error handler */ int vm_event, vm_error = -1; #if SDL_VIDEO_DRIVER_X11_XINERAMA static SDL_bool CheckXinerama(Display * display, int *major, int *minor) { int event_base = 0; int error_base = 0; const char *env; /* Default the extension not available */ *major = *minor = 0; /* Allow environment override */ env = SDL_GetHint(SDL_HINT_VIDEO_X11_XINERAMA); if (env && !SDL_atoi(env)) { #ifdef X11MODES_DEBUG printf("Xinerama disabled due to hint\n"); #endif return SDL_FALSE; } if (!SDL_X11_HAVE_XINERAMA) { #ifdef X11MODES_DEBUG printf("Xinerama support not available\n"); #endif return SDL_FALSE; } /* Query the extension version */ if (!XineramaQueryExtension(display, &event_base, &error_base) || !XineramaQueryVersion(display, major, minor) || !XineramaIsActive(display)) { #ifdef X11MODES_DEBUG printf("Xinerama not active on the display\n"); #endif return SDL_FALSE; } #ifdef X11MODES_DEBUG printf("Xinerama available!\n"); #endif return SDL_TRUE; } #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ #if SDL_VIDEO_DRIVER_X11_XRANDR static SDL_bool CheckXRandR(Display * display, int *major, int *minor) { const char *env; /* Default the extension not available */ *major = *minor = 0; /* Allow environment override */ env = SDL_GetHint(SDL_HINT_VIDEO_X11_XRANDR); if (env && !SDL_atoi(env)) { #ifdef X11MODES_DEBUG printf("XRandR disabled due to hint\n"); #endif return SDL_FALSE; } if (!SDL_X11_HAVE_XRANDR) { #ifdef X11MODES_DEBUG printf("XRandR support not available\n"); #endif return SDL_FALSE; } /* Query the extension version */ if (!XRRQueryVersion(display, major, minor)) { #ifdef X11MODES_DEBUG printf("XRandR not active on the display\n"); #endif return SDL_FALSE; } #ifdef X11MODES_DEBUG printf("XRandR available!\n"); #endif return SDL_TRUE; } #define XRANDR_ROTATION_LEFT (1 << 1) #define XRANDR_ROTATION_RIGHT (1 << 3) static void get_xrandr_mode_size(XRRModeInfo *mode, Rotation rotation, int *w, int *h) { if (rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) { *w = mode->height; *h = mode->width; } else { *w = mode->width; *h = mode->height; } } #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ #if SDL_VIDEO_DRIVER_X11_XVIDMODE static SDL_bool CheckVidMode(Display * display, int *major, int *minor) { const char *env; /* Default the extension not available */ *major = *minor = 0; /* Allow environment override */ env = SDL_GetHint(SDL_HINT_VIDEO_X11_XVIDMODE); if (env && !SDL_atoi(env)) { #ifdef X11MODES_DEBUG printf("XVidMode disabled due to hint\n"); #endif return SDL_FALSE; } if (!SDL_X11_HAVE_XVIDMODE) { #ifdef X11MODES_DEBUG printf("XVidMode support not available\n"); #endif return SDL_FALSE; } /* Query the extension version */ vm_error = -1; if (!XF86VidModeQueryExtension(display, &vm_event, &vm_error) || !XF86VidModeQueryVersion(display, major, minor)) { #ifdef X11MODES_DEBUG printf("XVidMode not active on the display\n"); #endif return SDL_FALSE; } #ifdef X11MODES_DEBUG printf("XVidMode available!\n"); #endif return SDL_TRUE; } static Bool XF86VidModeGetModeInfo(Display * dpy, int scr, XF86VidModeModeInfo* info) { Bool retval; int dotclock; XF86VidModeModeLine l; SDL_zerop(info); SDL_zero(l); retval = XF86VidModeGetModeLine(dpy, scr, &dotclock, &l); info->dotclock = dotclock; info->hdisplay = l.hdisplay; info->hsyncstart = l.hsyncstart; info->hsyncend = l.hsyncend; info->htotal = l.htotal; info->hskew = l.hskew; info->vdisplay = l.vdisplay; info->vsyncstart = l.vsyncstart; info->vsyncend = l.vsyncend; info->vtotal = l.vtotal; info->flags = l.flags; info->privsize = l.privsize; info->private = l.private; return retval; } static int calculate_rate(XF86VidModeModeInfo * info) { return (info->htotal && info->vtotal) ? (1000 * info->dotclock / (info->htotal * info->vtotal)) : 0; } static void save_mode(Display * display, SDL_DisplayData * data) { XF86VidModeGetModeInfo(display, data->screen, &data->saved_mode); XF86VidModeGetViewPort(display, data->screen, &data->saved_view.x, &data->saved_view.y); } /* static void restore_mode(Display * display, SDL_DisplayData * data) { XF86VidModeModeInfo mode; if (XF86VidModeGetModeInfo(display, data->screen, &mode)) { if (SDL_memcmp(&mode, &data->saved_mode, sizeof(mode)) != 0) { XF86VidModeSwitchToMode(display, data->screen, &data->saved_mode); } } if ((data->saved_view.x != 0) || (data->saved_view.y != 0)) { XF86VidModeSetViewPort(display, data->screen, data->saved_view.x, data->saved_view.y); } } */ #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */ void X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display) { Display *display = ((SDL_VideoData *) _this->driverdata)->display; SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata; #if SDL_VIDEO_DRIVER_X11_XRANDR int xrandr_major, xrandr_minor; int nsizes, nrates; XRRScreenSize *sizes; short *rates; #endif #if SDL_VIDEO_DRIVER_X11_XVIDMODE int vm_major, vm_minor; int nmodes; XF86VidModeModeInfo ** modes; #endif int screen_w; int screen_h; SDL_DisplayMode mode; /* Unfortunately X11 requires the window to be created with the correct * visual and depth ahead of time, but the SDL API allows you to create * a window before setting the fullscreen display mode. This means that * we have to use the same format for all windows and all display modes. * (or support recreating the window with a new visual behind the scenes) */ mode.format = sdl_display->current_mode.format; mode.driverdata = NULL; screen_w = DisplayWidth(display, data->screen); screen_h = DisplayHeight(display, data->screen); #if SDL_VIDEO_DRIVER_X11_XINERAMA if (data->use_xinerama) { /* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0 */ if (!data->xinerama_info.x_org && !data->xinerama_info.y_org && (screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) { mode.w = screen_w; mode.h = screen_h; mode.refresh_rate = 0; SDL_AddDisplayMode(sdl_display, &mode); } /* Add the head xinerama mode */ mode.w = data->xinerama_info.width; mode.h = data->xinerama_info.height; mode.refresh_rate = 0; SDL_AddDisplayMode(sdl_display, &mode); } #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ #if SDL_VIDEO_DRIVER_X11_XRANDR /* XRandR */ /* require at least XRandR v1.0 (arbitrary) */ if (CheckXRandR(display, &xrandr_major, &xrandr_minor) && xrandr_major >= 1) { #ifdef X11MODES_DEBUG fprintf(stderr, "XRANDR: XRRQueryVersion: V%d.%d\n", xrandr_major, xrandr_minor); #endif /* save the screen configuration since we must reference it each time we toggle modes. */ data->screen_config = XRRGetScreenInfo(display, RootWindow(display, data->screen)); /* retrieve the list of resolution */ sizes = XRRConfigSizes(data->screen_config, &nsizes); if (nsizes > 0) { int i, j; for (i = 0; i < nsizes; i++) { get_xrandr_mode_size(XRRModeInfo *mode, Rotation rotation, int *w, int *h) mode.w = sizes[i].width; mode.h = sizes[i].height; rates = XRRConfigRates(data->screen_config, i, &nrates); for (j = 0; j < nrates; ++j) { mode.refresh_rate = rates[j]; #ifdef X11MODES_DEBUG fprintf(stderr, "XRANDR: mode = %4d[%d], w = %4d, h = %4d, rate = %4d\n", i, j, mode.w, mode.h, mode.refresh_rate); #endif SDL_AddDisplayMode(sdl_display, &mode); } } data->use_xrandr = xrandr_major * 100 + xrandr_minor; data->saved_size = XRRConfigCurrentConfiguration(data->screen_config, &data->saved_rotation); data->saved_rate = XRRConfigCurrentRate(data->screen_config); } } #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ #if SDL_VIDEO_DRIVER_X11_XVIDMODE /* XVidMode */ if (!data->use_xrandr && #if SDL_VIDEO_DRIVER_X11_XINERAMA (!data->use_xinerama || data->xinerama_info.screen_number == 0) && #endif CheckVidMode(display, &vm_major, &vm_minor) && XF86VidModeGetAllModeLines(display, data->screen, &nmodes, &modes)) { int i; #ifdef X11MODES_DEBUG printf("VidMode modes: (unsorted)\n"); for (i = 0; i < nmodes; ++i) { printf("Mode %d: %d x %d @ %d\n", i, modes[i]->hdisplay, modes[i]->vdisplay, calculate_rate(modes[i])); } #endif for (i = 0; i < nmodes; ++i) { mode.w = modes[i]->hdisplay; mode.h = modes[i]->vdisplay; mode.refresh_rate = calculate_rate(modes[i]); SDL_AddDisplayMode(sdl_display, &mode); } XFree(modes); data->use_vidmode = vm_major * 100 + vm_minor; save_mode(display, data); } #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */ if (!data->use_xrandr && !data->use_vidmode) { mode.w = screen_w; mode.h = screen_h; mode.refresh_rate = 0; SDL_AddDisplayMode(sdl_display, &mode); } #ifdef X11MODES_DEBUG if (data->use_xinerama) { printf("Xinerama is enabled\n"); } if (data->use_xrandr) { printf("XRandR is enabled\n"); } if (data->use_vidmode) { printf("VidMode is enabled\n"); } #endif /* X11MODES_DEBUG */ } static void get_real_resolution(Display * display, SDL_DisplayData * data, int *w, int *h, int *rate) { #if SDL_VIDEO_DRIVER_X11_XRANDR if (data->use_xrandr) { int nsizes; XRRScreenSize *sizes; sizes = XRRConfigSizes(data->screen_config, &nsizes); if (nsizes > 0) { int cur_size; Rotation cur_rotation; cur_size = XRRConfigCurrentConfiguration(data->screen_config, &cur_rotation); *w = sizes[cur_size].width; *h = sizes[cur_size].height; *rate = XRRConfigCurrentRate(data->screen_config); #ifdef X11MODES_DEBUG fprintf(stderr, "XRANDR: get_real_resolution: w = %d, h = %d, rate = %d\n", *w, *h, *rate); #endif return; } } #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ #if SDL_VIDEO_DRIVER_X11_XVIDMODE if (data->use_vidmode) { XF86VidModeModeInfo mode; if (XF86VidModeGetModeInfo(display, data->screen, &mode)) { *w = mode.hdisplay; *h = mode.vdisplay; *rate = calculate_rate(&mode); return; } } #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */ #if SDL_VIDEO_DRIVER_X11_XINERAMA if (data->use_xinerama) { int screencount; XineramaScreenInfo *xinerama; /* Update the current screen layout information */ xinerama = XineramaQueryScreens(display, &screencount); if (xinerama && data->xinerama_screen < screencount) { data->xinerama_info = xinerama[data->xinerama_screen]; } if (xinerama) XFree(xinerama); *w = data->xinerama_info.width; *h = data->xinerama_info.height; *rate = 0; return; } #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ *w = DisplayWidth(display, data->screen); *h = DisplayHeight(display, data->screen); *rate = 0; } static void set_best_resolution(Display * display, SDL_DisplayData * data, int w, int h, int rate) { int real_w, real_h, real_rate; /* check current mode so we can avoid uneccessary mode changes */ get_real_resolution(display, data, &real_w, &real_h, &real_rate); if (w == real_w && h == real_h && (!rate || !real_rate || rate == real_rate)) { return; } #if SDL_VIDEO_DRIVER_X11_XRANDR if (data->use_xrandr) { #ifdef X11MODES_DEBUG fprintf(stderr, "XRANDR: set_best_resolution(): w = %d, h = %d\n", w, h); #endif int i, nsizes, nrates; int best; int best_rate; XRRScreenSize *sizes; short *rates; #if SDL_VIDEO_DRIVER_X11_XINERAMA if (data->use_xrandr >= 102 && data->use_xinerama) { /* See http://cgit.freedesktop.org/xorg/app/xrandr/tree/xrandr.c for the rationale behind this */ /* Note by Gabriel: the refresh rate is ignored in this code, and seeing that both xrandr * and nvidia-settings don't provide a way to set it when Xinerama is enabled, it may not be possible to set it */ int screencount; XineramaScreenInfo * xinerama = NULL; XRRScreenResources *res; /* Update the current screen layout information */ xinerama = XineramaQueryScreens(display, &screencount); if (xinerama && data->xinerama_screen < screencount) { data->xinerama_info = xinerama[data->xinerama_screen]; } if (xinerama) XFree(xinerama); res = XRRGetScreenResources (display, RootWindow(display, data->screen)); if (res) { XRROutputInfo *output_info = NULL; XRRCrtcInfo *crtc = NULL; XRRModeInfo *mode_info, *best_mode_info = NULL; int mode_index = 0, output_mode_index = 0, output; int mode_w, mode_h, best_w = 0, best_h = 0; for ( output = 0; output < res->noutput; output++) { output_info = XRRGetOutputInfo (display, res, res->outputs[output]); if (!output_info || !output_info->crtc) { XRRFreeOutputInfo(output_info); continue; } crtc = XRRGetCrtcInfo (display, res, output_info->crtc); if (!crtc || data->xinerama_info.x_org != crtc->x || data->xinerama_info.y_org != crtc->y) { XRRFreeCrtcInfo(crtc); continue; } /* The CRT offset matches the Xinerama mode, let's hope it's the right one! */ #ifdef X11MODES_DEBUG fprintf(stderr, "XRANDR: set_best_resolution, matched Xinerama screen %d to CRT %d at %d,%d\n", data->xinerama_info.screen_number, output_info->crtc, crtc->x, crtc->y); #endif /* Find out the best mode we can use */ for (mode_index = 0; mode_index < res->nmode; mode_index++) { mode_info = &res->modes[mode_index]; get_xrandr_mode_size(mode_info, crtc->rotation, &mode_w, &mode_h); if (mode_w >= w && mode_h >= h) { /* This may be a useful mode, check out if it belongs to the correct output */ #ifdef X11MODES_DEBUG fprintf(stderr, "Evaluating valid mode %d, w: %d, h: %d\n", mode_index, mode_info->width, mode_info->height); #endif for ( output_mode_index = 0; output_mode_index < output_info->nmode; output_mode_index++) { if (output_info->modes[output_mode_index] == mode_info->id) { break; } } if (output_mode_index < output_info->nmode) { #ifdef X11MODES_DEBUG fprintf(stderr, "Mode belongs to the desired output %d w: %d, h: %d, rotation: %x\n", mode_index, mode_info->width, mode_info->height, crtc->rotation); #endif /* We have a mode that belongs to the right output and that can contain the w,h required, see if it's smaller than the current one */ if ( !best_mode_info || mode_w < best_w || (mode_w == best_w && mode_h < best_h) ) { best_mode_info = mode_info; best_w = mode_w; best_h = mode_h; } } #ifdef X11MODES_DEBUG else { fprintf(stderr, "Discarding mode because it does not belong to the desired output %d, w: %d, h: %d, rotation: %d\n", mode_index, mode_info->width, mode_info->height, crtc->rotation); } #endif } } if (best_mode_info) { #ifdef X11MODES_DEBUG fprintf(stderr, "XRANDR: set_best_resolution, setting mode w = %d, h = %d on output: %d, CRT with offsets: %d,%d for Xinerama screen: %d\n", best_mode_info->width, best_mode_info->height, output, crtc->x, crtc->y, data->xinerama_info.screen_number); #endif XGrabServer (display); XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime, crtc->x, crtc->y, best_mode_info->id, crtc->rotation, &res->outputs[output], 1); /* TODO: Handle screen rotations, should we call XRRSetCrtcTransform if Xrandr >=1.3 ? */ XUngrabServer (display); } else { /* If we reach here, we have found the right screen but no valid best mode */ SDL_SetError("The selected screen can't support a resolution of the size desired"); } XRRFreeCrtcInfo(crtc); XRRFreeOutputInfo(output_info); break; } XRRFreeScreenResources(res); } } else #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ { /* Use older xrandr functions that don't play along very nicely with multi monitors setups */ /* find the smallest resolution that is at least as big as the user requested */ best = -1; sizes = XRRConfigSizes(data->screen_config, &nsizes); for (i = 0; i < nsizes; ++i) { if (sizes[i].width < w || sizes[i].height < h) { continue; } if (sizes[i].width == w && sizes[i].height == h) { best = i; break; } if (best == -1 || (sizes[i].width < sizes[best].width) || (sizes[i].width == sizes[best].width && sizes[i].height < sizes[best].height)) { best = i; } } if (best >= 0) { best_rate = 0; rates = XRRConfigRates(data->screen_config, best, &nrates); for (i = 0; i < nrates; ++i) { if (rates[i] == rate) { best_rate = rate; break; } if (!rate) { /* Higher is better, right? */ if (rates[i] > best_rate) { best_rate = rates[i]; } } else { if (SDL_abs(rates[i] - rate) < SDL_abs(best_rate - rate)) { best_rate = rates[i]; } } } XRRSetScreenConfigAndRate(display, data->screen_config, RootWindow(display, data->screen), best, data->saved_rotation, best_rate, CurrentTime); } } return; } #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ #if SDL_VIDEO_DRIVER_X11_XVIDMODE if (data->use_vidmode) { XF86VidModeModeInfo ** modes; int i, nmodes; int best; if (XF86VidModeGetAllModeLines(display, data->screen, &nmodes, &modes)) { best = -1; for (i = 0; i < nmodes; ++i) { if (modes[i]->hdisplay < w || modes[i]->vdisplay < h) { continue; } if (best == -1 || (modes[i]->hdisplay < modes[best]->hdisplay) || (modes[i]->hdisplay == modes[best]->hdisplay && modes[i]->vdisplay < modes[best]->vdisplay)) { best = i; continue; } if ((modes[i]->hdisplay == modes[best]->hdisplay) && (modes[i]->vdisplay == modes[best]->vdisplay)) { if (!rate) { /* Higher is better, right? */ if (calculate_rate(modes[i]) > calculate_rate(modes[best])) { best = i; } } else { if (SDL_abs(calculate_rate(modes[i]) - rate) < SDL_abs(calculate_rate(modes[best]) - rate)) { best = i; } } } } if (best >= 0) { #ifdef X11MODES_DEBUG printf("Best Mode %d: %d x %d @ %d\n", best, modes[best]->hdisplay, modes[best]->vdisplay, calculate_rate(modes[best])); #endif XF86VidModeSwitchToMode(display, data->screen, modes[best]); } XFree(modes); } return; } #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */ } int X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode) { Display *display = ((SDL_VideoData *) _this->driverdata)->display; SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata; set_best_resolution(display, data, mode->w, mode->h, mode->refresh_rate); return 0; } void X11_QuitModes(_THIS) { } int X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect) { Display *display = ((SDL_VideoData *) _this->driverdata)->display; SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata; int real_rate; rect->x = 0; rect->y = 0; get_real_resolution(display, data, &rect->w, &rect->h, &real_rate); #if SDL_VIDEO_DRIVER_X11_XINERAMA if (data->use_xinerama) { rect->x = data->xinerama_info.x_org; rect->y = data->xinerama_info.y_org; } #endif return 0; } #endif /* SDL_VIDEO_DRIVER_X11 */ /* vi: set ts=4 sw=4 expandtab: */