Xrandr support in the X11 target.
Fixes Bugzilla #109, and as a bonus, Bugzilla #145, too!
--- a/configure.in Wed Mar 22 09:18:10 2006 +0000
+++ b/configure.in Wed Mar 22 11:13:58 2006 +0000
@@ -789,9 +789,11 @@
, enable_x11_shared=yes)
case "$host" in
- *-*-darwin*)
+ *-*-darwin*) # Latest Mac OS X actually ships with Xrandr/Xrender libs...
x11_lib='/usr/X11R6/lib/libX11.6.dylib'
x11ext_lib='/usr/X11R6/lib/libXext.6.dylib'
+ xrandr_lib='/usr/X11R6/lib/libXrandr.2.dylib'
+ xrender_lib='/usr/X11R6/lib/libXrender.1.dylib'
;;
*-*-osf*)
x11_lib='libX11.so'
@@ -810,6 +812,12 @@
if test "x$x11ext_lib" = "x"; then
x11ext_lib=[`ls $path/libXext.so.[0-9] 2>/dev/null | sort -r | sed 's/.*\/\(.*\)/\1/; q'`]
fi
+ if test "x$xrender_lib" = "x"; then
+ xrender_lib=[`ls $path/libXrender.so.[0-9] 2>/dev/null | sort -r | sed 's/.*\/\(.*\)/\1/; q'`]
+ fi
+ if test "x$xrandr_lib" = "x"; then
+ xrandr_lib=[`ls $path/libXrandr.so.[0-9] 2>/dev/null | sort -r | sed 's/.*\/\(.*\)/\1/; q'`]
+ fi
done
;;
esac
@@ -833,6 +841,7 @@
AC_DEFINE_UNQUOTED(SDL_VIDEO_DRIVER_X11_DYNAMIC, "$x11_lib")
AC_DEFINE_UNQUOTED(SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT, "$x11ext_lib")
else
+ enable_x11_shared=no
EXTRA_LDFLAGS="$EXTRA_LDFLAGS $X_LIBS -lX11 -lXext"
fi
have_video=yes
@@ -884,6 +893,37 @@
AC_DEFINE(SDL_VIDEO_DRIVER_X11_XME)
SOURCES="$SOURCES $srcdir/src/video/Xext/XME/*.c"
fi
+ AC_ARG_ENABLE(video-x11-xrandr,
+AC_HELP_STRING([--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
+ definitely_enable_video_x11_xrandr=no
+ AC_CHECK_HEADER(X11/extensions/Xrandr.h,
+ have_xrandr_h_hdr=yes,
+ have_xrandr_h_hdr=no,
+ [#include <X11/Xlib.h>
+ ])
+ if test x$have_xrandr_h_hdr = xyes; then
+ if test x$enable_x11_shared = xyes && test x$xrandr_lib != x ; then
+ echo "-- dynamic libXrender -> $xrender_lib"
+ echo "-- dynamic libXrandr -> $xrandr_lib"
+ AC_DEFINE_UNQUOTED(SDL_VIDEO_DRIVER_X11_DYNAMIC_XRENDER, "$xrender_lib")
+ AC_DEFINE_UNQUOTED(SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR, "$xrandr_lib")
+ definitely_enable_video_x11_xrandr=yes
+ else
+ AC_CHECK_LIB(Xrender, XRenderQueryExtension, have_xrender_lib=yes)
+ AC_CHECK_LIB(Xrandr, XRRQueryExtension, have_xrandr_lib=yes)
+ if test x$have_xrender_lib = xyes && test x$have_xrandr_lib = xyes ; then
+ EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lXrandr -lXrender"
+ definitely_enable_video_x11_xrandr=yes
+ fi
+ fi
+ fi
+ fi
+
+ if test x$definitely_enable_video_x11_xrandr = xyes; then
+ AC_DEFINE(SDL_VIDEO_DRIVER_X11_XRANDR)
+ fi
fi
fi
}
--- a/docs/html/sdlenvvars.html Wed Mar 22 09:18:10 2006 +0000
+++ b/docs/html/sdlenvvars.html Wed Mar 22 11:13:58 2006 +0000
@@ -576,6 +576,18 @@
><DT
><TT
CLASS="LITERAL"
+>SDL_VIDEO_X11_NO_XRANDR</TT
+></DT
+><DD
+><P
+>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.</P
+></DD
+><DT
+><TT
+CLASS="LITERAL"
>SDL_VIDEO_YUV_DIRECT</TT
></DT
><DD
@@ -1209,4 +1221,4 @@
></DIV
></BODY
></HTML
->
\ No newline at end of file
+>
--- a/include/SDL_config.h.in Wed Mar 22 09:18:10 2006 +0000
+++ b/include/SDL_config.h.in Wed Mar 22 11:13:58 2006 +0000
@@ -278,9 +278,12 @@
#undef SDL_VIDEO_DRIVER_X11_DGAMOUSE
#undef SDL_VIDEO_DRIVER_X11_DYNAMIC
#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT
+#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR
+#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XRENDER
#undef SDL_VIDEO_DRIVER_X11_VIDMODE
#undef SDL_VIDEO_DRIVER_X11_XINERAMA
#undef SDL_VIDEO_DRIVER_X11_XME
+#undef SDL_VIDEO_DRIVER_X11_XRANDR
#undef SDL_VIDEO_DRIVER_X11_XV
#undef SDL_VIDEO_DRIVER_XBIOS
--- a/src/video/x11/SDL_x11dyn.c Wed Mar 22 09:18:10 2006 +0000
+++ b/src/video/x11/SDL_x11dyn.c Wed Mar 22 11:13:58 2006 +0000
@@ -21,13 +21,11 @@
*/
#include "SDL_config.h"
-#if 0
-#define DEBUG_DYNAMIC_X11 1
-#endif
+#define DEBUG_DYNAMIC_X11 0
#include "SDL_x11dyn.h"
-#ifdef DEBUG_DYNAMIC_X11
+#if DEBUG_DYNAMIC_X11
#include <stdio.h>
#endif
@@ -39,6 +37,10 @@
static void *x11_handle = NULL;
static const char *x11ext_library = SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT;
static void *x11ext_handle = NULL;
+static const char *xrender_library = SDL_VIDEO_DRIVER_X11_DYNAMIC_XRENDER;
+static void *xrender_handle = NULL;
+static const char *xrandr_library = SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR;
+static void *xrandr_handle = NULL;
typedef struct
{
@@ -54,6 +56,8 @@
{
{ x11_handle, "libX11" },
{ x11ext_handle, "libX11ext" },
+ { xrender_handle, "libXrender" },
+ { xrandr_handle, "libXrandr" },
};
for (i = 0; i < (sizeof (libs) / sizeof (libs[0])); i++)
@@ -130,6 +134,14 @@
SDL_UnloadObject(x11ext_handle);
x11ext_handle = NULL;
}
+ if (xrender_handle != NULL) {
+ SDL_UnloadObject(xrender_handle);
+ xrender_handle = NULL;
+ }
+ if (xrandr_handle != NULL) {
+ SDL_UnloadObject(xrandr_handle);
+ xrandr_handle = NULL;
+ }
}
}
#endif
@@ -146,6 +158,8 @@
int *thismod = NULL;
x11_handle = SDL_LoadObject(x11_library);
x11ext_handle = SDL_LoadObject(x11ext_library);
+ xrender_handle = SDL_LoadObject(xrender_library);
+ xrandr_handle = SDL_LoadObject(xrandr_library);
#define SDL_X11_MODULE(modname) thismod = &SDL_X11_HAVE_##modname;
#define SDL_X11_SYM(a,fn,x,y,z) p##fn = X11_GetSym(#fn,thismod);
#include "SDL_x11sym.h"
--- a/src/video/x11/SDL_x11dyn.h Wed Mar 22 09:18:10 2006 +0000
+++ b/src/video/x11/SDL_x11dyn.h Wed Mar 22 11:13:58 2006 +0000
@@ -38,6 +38,10 @@
#include <X11/extensions/XShm.h>
#endif
+#if SDL_VIDEO_DRIVER_X11_XRANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+
/*
* When using the "dynamic X11" functionality, we duplicate all the Xlib
* symbols that would be referenced by SDL inside of SDL itself.
--- a/src/video/x11/SDL_x11modes.c Wed Mar 22 09:18:10 2006 +0000
+++ b/src/video/x11/SDL_x11modes.c Wed Mar 22 11:13:58 2006 +0000
@@ -86,6 +86,18 @@
}
#endif
+#if SDL_VIDEO_DRIVER_X11_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)
@@ -180,6 +192,55 @@
}
#endif /* SDL_VIDEO_DRIVER_X11_XME */
+#if SDL_VIDEO_DRIVER_X11_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 /* SDL_VIDEO_DRIVER_X11_XRANDR */
+
}
static void get_real_resolution(_THIS, int* w, int* h)
@@ -195,7 +256,7 @@
return;
}
}
-#endif
+#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
#if SDL_VIDEO_DRIVER_X11_XME
if ( use_xme ) {
@@ -213,7 +274,30 @@
XFree(modelist);
return;
}
-#endif /* XIG_XME */
+#endif /* SDL_VIDEO_DRIVER_X11_XME */
+
+#if SDL_VIDEO_DRIVER_X11_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 /* SDL_VIDEO_DRIVER_X11_XRANDR */
*w = DisplayWidth(SDL_Display, SDL_Screen);
*h = DisplayHeight(SDL_Display, SDL_Screen);
@@ -289,15 +373,69 @@
int ractive, nummodes;
XiGMiscResolutionInfo *modelist;
#endif
+#if SDL_VIDEO_DRIVER_X11_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 */
+#if SDL_VIDEO_DRIVER_X11_XRANDR
+ /* require at least XRandR v1.0 (arbitrary) */
+ if ( ( SDL_X11_HAVE_XRANDR ) &&
+ ( 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 /* SDL_VIDEO_DRIVER_X11_XRANDR */
+
#if SDL_VIDEO_DRIVER_X11_VIDMODE
/* Metro-X 4.3.0 and earlier has a broken implementation of
XF86VidModeGetAllModeLines() - it hangs the client.
@@ -345,7 +483,7 @@
buggy_X11 = 1;
}
}
- if ( ! buggy_X11 &&
+ if ( ! buggy_X11 && ! use_xrandr &&
SDL_NAME(XF86VidModeGetAllModeLines)(SDL_Display, SDL_Screen,&nmodes,&modes) ) {
#ifdef XFREE86_DEBUG
@@ -426,7 +564,7 @@
*/
fprintf(stderr,
"XME: If you are using Xi Graphics CDE and a Summit server, you need to\n"
-"XME: get the libXext update from our ftp site before fullscreen switching\n"
+"XME: get the libXext update from Xi's ftp site before fullscreen switching\n"
"XME: will work. Fullscreen switching is only supported on Summit Servers\n");
}
} else {
@@ -635,6 +773,14 @@
SDL_free(SDL_modelist);
SDL_modelist = NULL;
}
+
+#if SDL_VIDEO_DRIVER_X11_XRANDR
+ /* Free the Xrandr screen configuration */
+ if ( screen_config ) {
+ XRRFreeScreenConfigInfo(screen_config);
+ screen_config = NULL;
+ }
+#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
}
int X11_ResizeFullScreen(_THIS)
@@ -804,6 +950,13 @@
}
#endif
+#if SDL_VIDEO_DRIVER_X11_XRANDR
+ if ( use_xrandr ) {
+ XRRSetScreenConfig(SDL_Display, screen_config, SDL_Root,
+ saved_size_id, saved_rotation, CurrentTime);
+ }
+#endif
+
XUnmapWindow(SDL_Display, FSwindow);
X11_WaitUnmapped(this, FSwindow);
XSync(SDL_Display, True); /* Flush spurious mode change events */
--- a/src/video/x11/SDL_x11sym.h Wed Mar 22 09:18:10 2006 +0000
+++ b/src/video/x11/SDL_x11sym.h Wed Mar 22 11:13:58 2006 +0000
@@ -176,5 +176,16 @@
SDL_X11_SYM(int,ipUnallocateAndSendData,(ChannelPtr a, IPCard b),(a,b),return)
#endif
+/* Xrandr support. */
+#if SDL_VIDEO_DRIVER_X11_XRANDR
+SDL_X11_MODULE(XRANDR)
+SDL_X11_SYM(Status,XRRQueryVersion,(Display *dpy,int *major_versionp,int *minor_versionp),(dpy,major_versionp,minor_versionp),return)
+SDL_X11_SYM(XRRScreenConfiguration *,XRRGetScreenInfo,(Display *dpy,Drawable draw),(dpy,draw),return)
+SDL_X11_SYM(SizeID,XRRConfigCurrentConfiguration,(XRRScreenConfiguration *config,Rotation *rotation),(config,rotation),return)
+SDL_X11_SYM(XRRScreenSize *,XRRConfigSizes,(XRRScreenConfiguration *config, int *nsizes),(config,nsizes),return)
+SDL_X11_SYM(Status,XRRSetScreenConfig,(Display *dpy, XRRScreenConfiguration *config, Drawable draw, int size_index, Rotation rotation, Time timestamp),(dpy,config,draw,size_index,rotation,timestamp),return)
+SDL_X11_SYM(void,XRRFreeScreenConfigInfo,(XRRScreenConfiguration *config),(config),)
+#endif
+
/* end of SDL_x11sym.h ... */
--- a/src/video/x11/SDL_x11video.h Wed Mar 22 09:18:10 2006 +0000
+++ b/src/video/x11/SDL_x11video.h Wed Mar 22 11:13:58 2006 +0000
@@ -40,6 +40,9 @@
#if SDL_VIDEO_DRIVER_X11_XME
#include "../Xext/extensions/xme.h"
#endif
+#if SDL_VIDEO_DRIVER_X11_XRANDR
+#include <X11/extensions/Xrandr.h>
+#endif
#include "SDL_x11dyn.h"
@@ -116,10 +119,16 @@
int use_xme;
XiGMiscResolutionInfo saved_res;
#endif
+#if SDL_VIDEO_DRIVER_X11_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) */
@@ -169,6 +178,10 @@
#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)