Date: Tue, 22 Feb 2005 19:18:05 +0900 From: Aric Cyr To: sdl@libsdl.org Subject: Re: [SDL] [PATCH] XRandR video mode support Index: configure.in =================================================================== RCS file: /home/sdlweb/libsdl.org/cvs/SDL12/configure.in,v retrieving revision 1.163 diff -u -5 -r1.163 configure.in --- configure.in 12 Feb 2005 18:01:29 -0000 1.163 +++ configure.in 22 Feb 2005 10:05:01 -0000 @@ -716,10 +716,30 @@ CFLAGS="$CFLAGS -DHAVE_XINERAMA" VIDEO_SUBDIRS="$VIDEO_SUBDIRS XFree86/Xinerama" VIDEO_DRIVERS="$VIDEO_DRIVERS XFree86/Xinerama/libXFree86_Xinerama.la" fi fi + AC_ARG_ENABLE(video-x11-xrandr, +[ --enable-video-x11-xrandr enable X11 Xrandr extension for fullscreen [default=yes]], + , enable_video_x11_xrandr=yes) + if test x$enable_video_x11_xrandr = xyes; then + AC_MSG_CHECKING(for X11 Xrandr support) + video_x11_xrandr=no + AC_TRY_COMPILE([ + #include + #include + ],[ + XRRScreenConfiguration *config; + ],[ + video_x11_xrandr=yes + ]) + AC_MSG_RESULT($video_x11_xrandr) + if test x$video_x11_xrandr = xyes; then + CFLAGS="$CFLAGS -DHAVE_XRANDR" + SYSTEM_LIBS="$SYSTEM_LIBS -lXrandr -lXrender" + fi + fi AC_ARG_ENABLE(video-x11-xme, [ --enable-video-x11-xme enable Xi Graphics XME for fullscreen [default=yes]], , enable_video_x11_xme=yes) if test x$enable_video_x11_xme = xyes; then AC_MSG_CHECKING(for Xi Graphics XiGMiscExtension support) Index: docs/html/sdlenvvars.html =================================================================== RCS file: /home/sdlweb/libsdl.org/cvs/SDL12/docs/html/sdlenvvars.html,v retrieving revision 1.1 diff -u -5 -r1.1 sdlenvvars.html --- docs/html/sdlenvvars.html 10 Feb 2004 15:15:39 -0000 1.1 +++ docs/html/sdlenvvars.html 22 Feb 2005 10:05:01 -0000 @@ -574,10 +574,22 @@ algorithm. It can be in decimal or in hex (prefixed by 0x).

SDL_VIDEO_X11_NO_XRANDR

If set, don't attempt to use the Xrandr extension for resolution mode +switching. Normally Xrandr takes precedence over the XF86VidMode +extension, so setting this environment variable will cause the +XF86VidMode extension to be used if it is available.

SDL_VIDEO_YUV_DIRECT

If set, display YUV overlay directly on the video surface if possible, @@ -1207,6 +1219,6 @@ > \ No newline at end of file +> Index: src/video/x11/SDL_x11modes.c =================================================================== RCS file: /home/sdlweb/libsdl.org/cvs/SDL12/src/video/x11/SDL_x11modes.c,v retrieving revision 1.22 diff -u -5 -r1.22 SDL_x11modes.c --- src/video/x11/SDL_x11modes.c 12 Nov 2004 21:25:42 -0000 1.22 +++ src/video/x11/SDL_x11modes.c 22 Feb 2005 10:05:01 -0000 @@ -90,10 +90,22 @@ else return b->hdisplay - a->hdisplay; } #endif +#ifdef HAVE_XRANDR +static int cmpmodelist(const void *va, const void *vb) +{ + const SDL_Rect *a = *(const SDL_Rect **)va; + const SDL_Rect *b = *(const SDL_Rect **)vb; + if ( a->w == b->w ) + return b->h - a->h; + else + return b->w - a->w; +} +#endif + static void get_real_resolution(_THIS, int* w, int* h); static void set_best_resolution(_THIS, int width, int height) { #ifdef XFREE86_VM @@ -184,10 +196,59 @@ } } } #endif /* HAVE_XIGXME */ +#ifdef HAVE_XRANDR + if ( use_xrandr ) { +#ifdef XRANDR_DEBUG + fprintf(stderr, "XRANDR: set_best_resolution(): w = %d, h = %d\n", + width, height); +#endif + if ( SDL_modelist ) { + int i, nsizes; + XRRScreenSize *sizes; + + /* find the smallest resolution that is at least as big as the user requested */ + sizes = XRRConfigSizes(screen_config, &nsizes); + for ( i = (nsizes-1); i >= 0; i-- ) { + if ( (SDL_modelist[i]->w >= width) && + (SDL_modelist[i]->h >= height) ) { + break; + } + } + + if ( i >= 0 && SDL_modelist[i] ) { /* found one, lets try it */ + int w, h; + + /* check current mode so we can avoid uneccessary mode changes */ + get_real_resolution(this, &w, &h); + + if ( (SDL_modelist[i]->w != w) || (SDL_modelist[i]->h != h) ) { + int size_id; + +#ifdef XRANDR_DEBUG + fprintf(stderr, "XRANDR: set_best_resolution: " + "XXRSetScreenConfig: %d %d\n", + SDL_modelist[i]->w, SDL_modelist[i]->h); +#endif + + /* find the matching size entry index */ + for ( size_id = 0; size_id < nsizes; ++size_id ) { + if ( (sizes[size_id].width == SDL_modelist[i]->w) && + (sizes[size_id].height == SDL_modelist[i]->h) ) + break; + } + + XRRSetScreenConfig(SDL_Display, screen_config, SDL_Root, + size_id, saved_rotation, CurrentTime); + } + } + } + } +#endif /* HAVE_XRANDR */ + } static void get_real_resolution(_THIS, int* w, int* h) { #ifdef XFREE86_VM @@ -219,10 +280,33 @@ XFree(modelist); return; } #endif /* XIG_XME */ +#ifdef HAVE_XRANDR + if ( use_xrandr ) { + int nsizes; + XRRScreenSize* sizes; + + sizes = XRRConfigSizes(screen_config, &nsizes); + if ( nsizes > 0 ) { + int cur_size; + Rotation cur_rotation; + + cur_size = XRRConfigCurrentConfiguration(screen_config, &cur_rotation); + if ( cur_size >= 0 && cur_size < nsizes ) { + *w = sizes[cur_size].width; + *h = sizes[cur_size].height; + } +#ifdef XRANDR_DEBUG + fprintf(stderr, "XRANDR: get_real_resolution: w = %d h = %d\n", *w, *h); +#endif + return; + } + } +#endif + *w = DisplayWidth(SDL_Display, SDL_Screen); *h = DisplayHeight(SDL_Display, SDL_Screen); } /* Called after mapping a window - waits until the window is mapped */ @@ -293,19 +377,72 @@ #ifdef HAVE_XIGXME int xme_major, xme_minor; int ractive, nummodes; XiGMiscResolutionInfo *modelist; #endif +#ifdef HAVE_XRANDR + int xrandr_major, xrandr_minor; + int nsizes; + XRRScreenSize *sizes; +#endif int i, n; int screen_w; int screen_h; vm_error = -1; use_vidmode = 0; + use_xrandr = 0; screen_w = DisplayWidth(SDL_Display, SDL_Screen); screen_h = DisplayHeight(SDL_Display, SDL_Screen); + /* XRandR */ +#ifdef HAVE_XRANDR + /* require at least XRandR v1.0 (arbitrary) */ + if ( ( getenv("SDL_VIDEO_X11_NO_XRANDR") == NULL ) && + ( XRRQueryVersion(SDL_Display, &xrandr_major, &xrandr_minor) ) && + ( xrandr_major >= 1 ) ) { + +#ifdef XRANDR_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. + */ + screen_config = XRRGetScreenInfo(SDL_Display, SDL_Root); + + /* retrieve the list of resolution */ + sizes = XRRConfigSizes(screen_config, &nsizes); + if (nsizes > 0) { + SDL_modelist = (SDL_Rect **)malloc((nsizes+1)*sizeof(SDL_Rect *)); + if (SDL_modelist) { + for ( i=0; i < nsizes; i++ ) { + if ((SDL_modelist[i] = + (SDL_Rect *)malloc(sizeof(SDL_Rect))) == NULL) + break; +#ifdef XRANDR_DEBUG + fprintf(stderr, "XRANDR: mode = %4d, w = %4d, h = %4d\n", + i, sizes[i].width, sizes[i].height); +#endif + + SDL_modelist[i]->x = 0; + SDL_modelist[i]->y = 0; + SDL_modelist[i]->w = sizes[i].width; + SDL_modelist[i]->h = sizes[i].height; + + } + /* sort the mode list descending as SDL expects */ + qsort(SDL_modelist, nsizes, sizeof *SDL_modelist, cmpmodelist); + SDL_modelist[i] = NULL; /* terminator */ + } + use_xrandr = xrandr_major * 100 + xrandr_minor; + saved_size_id = XRRConfigCurrentConfiguration(screen_config, &saved_rotation); + } + } +#endif + #ifdef XFREE86_VM /* Metro-X 4.3.0 and earlier has a broken implementation of XF86VidModeGetAllModeLines() - it hangs the client. */ buggy_X11 = 0; @@ -347,11 +484,11 @@ #endif /* XFree86 4.02 and newer are fixed wrt backwards compatibility */ } else { buggy_X11 = 1; } } - if ( ! buggy_X11 && + if ( ! buggy_X11 && ! use_xrandr && SDL_NAME(XF86VidModeGetAllModeLines)(SDL_Display, SDL_Screen,&nmodes,&modes) ) { #ifdef XFREE86_DEBUG printf("Available modes: (sorted)\n"); for ( i = 0; i < nmodes; ++i ) { @@ -630,10 +767,16 @@ free(SDL_modelist[i]); } free(SDL_modelist); SDL_modelist = NULL; } + + /* Free the Xrandr screen configuration */ + if ( screen_config ) { + XRRFreeScreenConfigInfo(screen_config); + screen_config = NULL; + } } int X11_ResizeFullScreen(_THIS) { int x, y; @@ -779,10 +922,16 @@ if ( use_vidmode ) { restore_mode(this); SDL_NAME(XF86VidModeLockModeSwitch)(SDL_Display, SDL_Screen, False); } #endif +#ifdef HAVE_XRANDR + if ( use_xrandr ) { + XRRSetScreenConfig(SDL_Display, screen_config, SDL_Root, + saved_size_id, saved_rotation, CurrentTime); + } +#endif #ifdef HAVE_XIGXME if ( use_xme ) { int rw, rh; Index: src/video/x11/SDL_x11video.h =================================================================== RCS file: /home/sdlweb/libsdl.org/cvs/SDL12/src/video/x11/SDL_x11video.h,v retrieving revision 1.9 diff -u -5 -r1.9 SDL_x11video.h --- src/video/x11/SDL_x11video.h 4 Jan 2004 16:49:27 -0000 1.9 +++ src/video/x11/SDL_x11video.h 22 Feb 2005 10:05:01 -0000 @@ -43,10 +43,13 @@ #include #endif #ifdef HAVE_XIGXME #include #endif +#ifdef HAVE_XRANDR +#include +#endif #include #include "SDL_mouse.h" #include "SDL_sysvideo.h" @@ -120,14 +123,20 @@ #endif #ifdef HAVE_XIGXME /* XiG XME fullscreen */ int use_xme; XiGMiscResolutionInfo saved_res; #endif +#ifdef HAVE_XRANDR + XRRScreenConfiguration* screen_config; + int saved_size_id; + Rotation saved_rotation; +#endif int xinerama_x; int xinerama_y; int use_vidmode; + int use_xrandr; int currently_fullscreen; /* Automatic mode switching support (entering/leaving fullscreen) */ Uint32 switch_waiting; Uint32 switch_time; @@ -173,10 +182,14 @@ #define SDL_modelist (this->hidden->modelist) #define saved_mode (this->hidden->saved_mode) #define saved_view (this->hidden->saved_view) #define use_xme (this->hidden->use_xme) #define saved_res (this->hidden->saved_res) +#define use_xrandr (this->hidden->use_xrandr) +#define screen_config (this->hidden->screen_config) +#define saved_size_id (this->hidden->saved_size_id) +#define saved_rotation (this->hidden->saved_rotation) #define xinerama_x (this->hidden->xinerama_x) #define xinerama_y (this->hidden->xinerama_y) #define use_vidmode (this->hidden->use_vidmode) #define currently_fullscreen (this->hidden->currently_fullscreen) #define switch_waiting (this->hidden->switch_waiting)