changed the X11 gamemode code policy. Falling back to xf86vm when xrandr fails

was problematic when passing invalid modes. Now instead, if xrandr is
available, we use that, and only that. XF86VM is now only used when XR&R is not
supported at all.

I also added a set of env vars to artificially disable one or the other, or
both. If FREEGLUT_NO_XRANDR is set we completely ignore XR&R, and if
FREEGLUT_NO_XF86VM is set, we completely ignore XF86VidMode. Obviously if both
are defined or missing, game mode can't switch resolutions at all any more, but
that's a nice debugging aid, and may be useful to allow the user to pick which
extension he'd rather use for mode switching.



git-svn-id: https://svn.code.sf.net/p/freeglut/code/trunk@1695 7f0cb862-5218-0410-a997-914c9d46530a
This commit is contained in:
jtsiomb 2014-08-18 00:52:53 +00:00
parent c12f6173db
commit 2ed4ed5b52

View File

@ -29,17 +29,53 @@
#include <GL/freeglut.h> #include <GL/freeglut.h>
#include "../fg_internal.h" #include "../fg_internal.h"
/* we'll try to use XR&R if it's available at compile-time, and at runtime, and the user
* hasn't explicitly disabled it by setting the FREEGLUT_NO_XRANDR env-var.
*/
static int use_xrandr(void)
{
#ifdef HAVE_X11_EXTENSIONS_XRANDR_H
int event_base, error_base;
if(!XRRQueryExtension(fgDisplay.pDisplay.Display, &event_base, &error_base)) {
return 0;
}
if(getenv("FREEGLUT_NO_XRANDR")) {
return 0;
}
return 1;
#else
return 0; /* no compile-time support */
#endif
}
/* we'll try to use XF86VidMode if it's available at compile-time, and at runtime, and the
* user hasn't explicitly disabled it by setting the FREEGLUT_NO_XF86VM env-var.
*/
static int use_xf86vm(void)
{
#ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
int event_base, error_base;
if(!XF86VidModeQueryExtension(fgDisplay.pDisplay.Display, &event_base, &error_base)) {
return 0;
}
if(getenv("FREEGLUT_NO_XF86VM")) {
return 0;
}
return 1;
#else
return 0; /* no compile-time support */
#endif
}
#ifdef HAVE_X11_EXTENSIONS_XRANDR_H #ifdef HAVE_X11_EXTENSIONS_XRANDR_H
static int xrandr_resize(int xsz, int ysz, int rate, int just_checking) static int xrandr_resize(int xsz, int ysz, int rate, int just_checking)
{ {
int event_base, error_base, ver_major, ver_minor, use_rate; int ver_major, ver_minor, use_rate;
XRRScreenConfiguration *xrr_config = 0; XRRScreenConfiguration *xrr_config = 0;
Status result = -1; Status result = -1;
/* must check at runtime for the availability of the extension */ /* NOTE: we have already determined that XR&R is availble and enabled before calling this */
if(!XRRQueryExtension(fgDisplay.pDisplay.Display, &event_base, &error_base)) {
return -1;
}
XRRQueryVersion(fgDisplay.pDisplay.Display, &ver_major, &ver_minor); XRRQueryVersion(fgDisplay.pDisplay.Display, &ver_major, &ver_minor);
@ -147,10 +183,6 @@ static int xrandr_resize(int xsz, int ysz, int rate, int just_checking)
*/ */
void fgPlatformRememberState( void ) void fgPlatformRememberState( void )
{ {
# if defined(HAVE_X11_EXTENSIONS_XRANDR_H) | defined(HAVE_X11_EXTENSIONS_XF86VMODE_H)
int event_base, error_base;
# endif
/* /*
* Remember the current pointer location before going fullscreen * Remember the current pointer location before going fullscreen
* for restoring it later: * for restoring it later:
@ -164,7 +196,7 @@ void fgPlatformRememberState( void )
&fgDisplay.pDisplay.DisplayPointerX, &fgDisplay.pDisplay.DisplayPointerY, &junk_mask); &fgDisplay.pDisplay.DisplayPointerX, &fgDisplay.pDisplay.DisplayPointerY, &junk_mask);
# ifdef HAVE_X11_EXTENSIONS_XRANDR_H # ifdef HAVE_X11_EXTENSIONS_XRANDR_H
if(XRRQueryExtension(fgDisplay.pDisplay.Display, &event_base, &error_base)) { if(use_xrandr()) {
XRRScreenConfiguration *xrr_config; XRRScreenConfiguration *xrr_config;
XRRScreenSize *ssizes; XRRScreenSize *ssizes;
Rotation rot; Rotation rot;
@ -189,40 +221,38 @@ void fgPlatformRememberState( void )
XRRFreeScreenConfigInfo(xrr_config); XRRFreeScreenConfigInfo(xrr_config);
} }
} }
# endif # endif /* HAVE_X11_EXTENSIONS_XRANDR_H */
/* /*
* This highly depends on the XFree86 extensions, * This highly depends on the XFree86 extensions,
* not approved as X Consortium standards * not approved as X Consortium standards
*/ */
# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H # ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
if(!XF86VidModeQueryExtension(fgDisplay.pDisplay.Display, &event_base, &error_base)) { if(use_xf86vm()) {
return; /*
} * Remember the current ViewPort location of the screen to be able to
* restore the ViewPort on LeaveGameMode():
/* */
* Remember the current ViewPort location of the screen to be able to if( !XF86VidModeGetViewPort(
* restore the ViewPort on LeaveGameMode(): fgDisplay.pDisplay.Display,
*/ fgDisplay.pDisplay.Screen,
if( !XF86VidModeGetViewPort( &fgDisplay.pDisplay.DisplayViewPortX,
fgDisplay.pDisplay.Display, &fgDisplay.pDisplay.DisplayViewPortY ) )
fgDisplay.pDisplay.Screen, fgWarning( "XF86VidModeGetViewPort failed" );
&fgDisplay.pDisplay.DisplayViewPortX,
&fgDisplay.pDisplay.DisplayViewPortY ) )
fgWarning( "XF86VidModeGetViewPort failed" );
/* Query the current display settings: */ /* Query the current display settings: */
fgDisplay.pDisplay.DisplayModeValid = fgDisplay.pDisplay.DisplayModeValid =
XF86VidModeGetModeLine( XF86VidModeGetModeLine(
fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Display,
fgDisplay.pDisplay.Screen, fgDisplay.pDisplay.Screen,
&fgDisplay.pDisplay.DisplayModeClock, &fgDisplay.pDisplay.DisplayModeClock,
&fgDisplay.pDisplay.DisplayMode &fgDisplay.pDisplay.DisplayMode
); );
if( !fgDisplay.pDisplay.DisplayModeValid ) if( !fgDisplay.pDisplay.DisplayModeValid )
fgWarning( "XF86VidModeGetModeLine failed" ); fgWarning( "XF86VidModeGetModeLine failed" );
}
# endif # endif
} }
@ -238,90 +268,90 @@ void fgPlatformRestoreState( void )
fgDisplay.pDisplay.DisplayPointerX, fgDisplay.pDisplay.DisplayPointerY fgDisplay.pDisplay.DisplayPointerX, fgDisplay.pDisplay.DisplayPointerY
); );
#ifdef HAVE_X11_EXTENSIONS_XRANDR_H
# ifdef HAVE_X11_EXTENSIONS_XRANDR_H if(use_xrandr()) {
if(fgDisplay.pDisplay.prev_size_valid) { if(fgDisplay.pDisplay.prev_size_valid) {
if(xrandr_resize(fgDisplay.pDisplay.prev_xsz, fgDisplay.pDisplay.prev_ysz, fgDisplay.pDisplay.prev_refresh, 0) != -1) { if(xrandr_resize(fgDisplay.pDisplay.prev_xsz, fgDisplay.pDisplay.prev_ysz, fgDisplay.pDisplay.prev_refresh, 0) != -1) {
fgDisplay.pDisplay.prev_size_valid = 0; fgDisplay.pDisplay.prev_size_valid = 0;
# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H #ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
fgDisplay.pDisplay.DisplayModeValid = 0; fgDisplay.pDisplay.DisplayModeValid = 0;
# endif #endif
return; }
} }
return; /* don't fall back to XF86VidMode if we have XR&R */
} }
# endif #endif /* HAVE_X11_EXTENSIONS_XRANDR_H */
# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H #ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
/* /*
* This highly depends on the XFree86 extensions, * This highly depends on the XFree86 extensions,
* not approved as X Consortium standards * not approved as X Consortium standards
*/ */
if(use_xf86vm()) {
if( fgDisplay.pDisplay.DisplayModeValid ) if( fgDisplay.pDisplay.DisplayModeValid )
{ {
XF86VidModeModeInfo** displayModes; XF86VidModeModeInfo** displayModes;
int i, displayModesCount; int i, displayModesCount;
if( !XF86VidModeGetAllModeLines( if( !XF86VidModeGetAllModeLines(
fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Display,
fgDisplay.pDisplay.Screen, fgDisplay.pDisplay.Screen,
&displayModesCount, &displayModesCount,
&displayModes ) ) &displayModes ) )
{ {
fgWarning( "XF86VidModeGetAllModeLines failed" ); fgWarning( "XF86VidModeGetAllModeLines failed" );
return; return;
} }
/* /*
* Check every of the modes looking for one that matches our demands. * Check every of the modes looking for one that matches our demands.
* If we find one, switch to it and restore the remembered viewport. * If we find one, switch to it and restore the remembered viewport.
*/ */
for( i = 0; i < displayModesCount; i++ ) for( i = 0; i < displayModesCount; i++ )
{ {
if(displayModes[ i ]->hdisplay == fgDisplay.pDisplay.DisplayMode.hdisplay && if(displayModes[ i ]->hdisplay == fgDisplay.pDisplay.DisplayMode.hdisplay &&
displayModes[ i ]->vdisplay == fgDisplay.pDisplay.DisplayMode.vdisplay && displayModes[ i ]->vdisplay == fgDisplay.pDisplay.DisplayMode.vdisplay &&
displayModes[ i ]->dotclock == fgDisplay.pDisplay.DisplayModeClock ) displayModes[ i ]->dotclock == fgDisplay.pDisplay.DisplayModeClock )
{ {
if( !XF86VidModeSwitchToMode( if( !XF86VidModeSwitchToMode(
fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Display,
fgDisplay.pDisplay.Screen, fgDisplay.pDisplay.Screen,
displayModes[ i ] ) ) displayModes[ i ] ) )
{ {
fgWarning( "XF86VidModeSwitchToMode failed" ); fgWarning( "XF86VidModeSwitchToMode failed" );
break; break;
} }
if( !XF86VidModeSetViewPort( if( !XF86VidModeSetViewPort(
fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Display,
fgDisplay.pDisplay.Screen, fgDisplay.pDisplay.Screen,
fgDisplay.pDisplay.DisplayViewPortX, fgDisplay.pDisplay.DisplayViewPortX,
fgDisplay.pDisplay.DisplayViewPortY ) ) fgDisplay.pDisplay.DisplayViewPortY ) )
fgWarning( "XF86VidModeSetViewPort failed" ); fgWarning( "XF86VidModeSetViewPort failed" );
/* /*
* For the case this would be the last X11 call the application * For the case this would be the last X11 call the application
* calls exit() we've to flush the X11 output queue to have the * calls exit() we've to flush the X11 output queue to have the
* commands sent to the X server before the application exits. * commands sent to the X server before the application exits.
*/ */
XFlush( fgDisplay.pDisplay.Display ); XFlush( fgDisplay.pDisplay.Display );
fgDisplay.pDisplay.DisplayModeValid = 0; fgDisplay.pDisplay.DisplayModeValid = 0;
# ifdef HAVE_X11_EXTENSIONS_XRANDR_H #ifdef HAVE_X11_EXTENSIONS_XRANDR_H
fgDisplay.pDisplay.prev_size_valid = 0; fgDisplay.pDisplay.prev_size_valid = 0;
# endif #endif
break;
break; }
} }
} XFree( displayModes );
XFree( displayModes ); }
} }
#endif /* HAVE_X11_EXTENSIONS_XF86VMODE_H */
# endif
} }
#ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H #ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
@ -378,105 +408,108 @@ static int fghCheckDisplayModes( GLboolean exactMatch, int displayModesCount, XF
GLboolean fgPlatformChangeDisplayMode( GLboolean haveToTest ) GLboolean fgPlatformChangeDisplayMode( GLboolean haveToTest )
{ {
GLboolean success = GL_FALSE; GLboolean success = GL_FALSE;
/* first try to use XRandR, then fallback to XF86VidMode */ #ifdef HAVE_X11_EXTENSIONS_XRANDR_H
# ifdef HAVE_X11_EXTENSIONS_XRANDR_H if(use_xrandr()) {
if(xrandr_resize(fgState.GameModeSize.X, fgState.GameModeSize.Y, if(xrandr_resize(fgState.GameModeSize.X, fgState.GameModeSize.Y,
fgState.GameModeRefresh, haveToTest) != -1) { fgState.GameModeRefresh, haveToTest) != -1) {
return GL_TRUE; return GL_TRUE;
} }
# endif return GL_FALSE; /* don't fall back to XF86VidMode */
}
#endif /* HAVE_X11_EXTENSIONS_XRANDR_H */
/* /*
* This highly depends on the XFree86 extensions, * This highly depends on the XFree86 extensions,
* not approved as X Consortium standards * not approved as X Consortium standards
*/ */
# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H #ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
if(use_xf86vm()) {
/*
* This is also used by applications which check modes by calling
* glutGameModeGet(GLUT_GAME_MODE_POSSIBLE), so allow the check:
*/
if( haveToTest || fgDisplay.pDisplay.DisplayModeValid )
{
XF86VidModeModeInfo** displayModes;
int i, displayModesCount;
/* /* If we don't have a valid modeline in the display structure, which
* This is also used by applications which check modes by calling * can happen if this is called from glutGameModeGet instead of
* glutGameModeGet(GLUT_GAME_MODE_POSSIBLE), so allow the check: * glutEnterGameMode, then we need to query the current mode, to make
*/ * unspecified settings to default to their current values.
if( haveToTest || fgDisplay.pDisplay.DisplayModeValid ) */
{ if(!fgDisplay.pDisplay.DisplayModeValid) {
XF86VidModeModeInfo** displayModes; if(!XF86VidModeGetModeLine(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Screen,
int i, displayModesCount; &fgDisplay.pDisplay.DisplayModeClock, &fgDisplay.pDisplay.DisplayMode)) {
return success;
}
}
/* If we don't have a valid modeline in the display structure, which if (fgState.GameModeSize.X == -1)
* can happen if this is called from glutGameModeGet instead of {
* glutEnterGameMode, then we need to query the current mode, to make fgState.GameModeSize.X = fgDisplay.pDisplay.DisplayMode.hdisplay;
* unspecified settings to default to their current values. }
*/ if (fgState.GameModeSize.Y == -1)
if(!fgDisplay.pDisplay.DisplayModeValid) { {
if(!XF86VidModeGetModeLine(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Screen, fgState.GameModeSize.Y = fgDisplay.pDisplay.DisplayMode.vdisplay;
&fgDisplay.pDisplay.DisplayModeClock, &fgDisplay.pDisplay.DisplayMode)) { }
return success; if (fgState.GameModeDepth == -1)
} {
} /* can't get color depth from this, nor can we change it, do nothing
* TODO: get with XGetVisualInfo()? but then how to set?
*/
}
if (fgState.GameModeRefresh == -1)
{
/* Compute the displays refresh rate, dotclock comes in kHz. */
int refresh = ( fgDisplay.pDisplay.DisplayModeClock * 1000 ) /
( fgDisplay.pDisplay.DisplayMode.htotal * fgDisplay.pDisplay.DisplayMode.vtotal );
if (fgState.GameModeSize.X == -1) fgState.GameModeRefresh = refresh;
{ }
fgState.GameModeSize.X = fgDisplay.pDisplay.DisplayMode.hdisplay;
}
if (fgState.GameModeSize.Y == -1)
{
fgState.GameModeSize.Y = fgDisplay.pDisplay.DisplayMode.vdisplay;
}
if (fgState.GameModeDepth == -1)
{
/* can't get color depth from this, nor can we change it, do nothing
* TODO: get with XGetVisualInfo()? but then how to set?
*/
}
if (fgState.GameModeRefresh == -1)
{
/* Compute the displays refresh rate, dotclock comes in kHz. */
int refresh = ( fgDisplay.pDisplay.DisplayModeClock * 1000 ) /
( fgDisplay.pDisplay.DisplayMode.htotal * fgDisplay.pDisplay.DisplayMode.vtotal );
fgState.GameModeRefresh = refresh; /* query all possible display modes */
} if( !XF86VidModeGetAllModeLines(
fgDisplay.pDisplay.Display,
/* query all possible display modes */ fgDisplay.pDisplay.Screen,
if( !XF86VidModeGetAllModeLines( &displayModesCount,
fgDisplay.pDisplay.Display, &displayModes ) )
fgDisplay.pDisplay.Screen, {
&displayModesCount, fgWarning( "XF86VidModeGetAllModeLines failed" );
&displayModes ) ) return success;
{ }
fgWarning( "XF86VidModeGetAllModeLines failed" );
return success;
}
/* /*
* Check every of the modes looking for one that matches our demands, * Check every of the modes looking for one that matches our demands,
* ignoring the refresh rate if no exact match could be found. * ignoring the refresh rate if no exact match could be found.
*/ */
i = fghCheckDisplayModes( GL_TRUE, displayModesCount, displayModes ); i = fghCheckDisplayModes( GL_TRUE, displayModesCount, displayModes );
if( i < 0 ) { if( i < 0 ) {
i = fghCheckDisplayModes( GL_FALSE, displayModesCount, displayModes ); i = fghCheckDisplayModes( GL_FALSE, displayModesCount, displayModes );
} }
success = ( i < 0 ) ? GL_FALSE : GL_TRUE; success = ( i < 0 ) ? GL_FALSE : GL_TRUE;
if( !haveToTest && success ) { if( !haveToTest && success ) {
if( !XF86VidModeSwitchToMode( if( !XF86VidModeSwitchToMode(
fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Display,
fgDisplay.pDisplay.Screen, fgDisplay.pDisplay.Screen,
displayModes[ i ] ) ) displayModes[ i ] ) )
fgWarning( "XF86VidModeSwitchToMode failed" ); fgWarning( "XF86VidModeSwitchToMode failed" );
} }
XFree( displayModes ); XFree( displayModes );
} }
}
# endif #endif /* HAVE_X11_EXTENSIONS_XF86VMODE_H */
return success; return success;
} }
void fgPlatformEnterGameMode( void ) void fgPlatformEnterGameMode( void )
{ {
/* /*
@ -521,38 +554,40 @@ void fgPlatformEnterGameMode( void )
fgState.GameModeSize.X/2, fgState.GameModeSize.Y/2 fgState.GameModeSize.X/2, fgState.GameModeSize.Y/2
); );
# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H #ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
if(use_xf86vm()) {
if( fgDisplay.pDisplay.DisplayModeValid ) if( fgDisplay.pDisplay.DisplayModeValid )
{ {
int x, y; int x, y;
Window child; Window child;
/* Change to viewport to the window topleft edge: */ /* Change to viewport to the window topleft edge: */
if( !XF86VidModeSetViewPort( fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Screen, 0, 0 ) ) if( !XF86VidModeSetViewPort( fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Screen, 0, 0 ) )
fgWarning( "XF86VidModeSetViewPort failed" ); fgWarning( "XF86VidModeSetViewPort failed" );
/* /*
* Final window repositioning: It could be avoided using an undecorated * Final window repositioning: It could be avoided using an undecorated
* window using override_redirect, but this * would possily require * window using override_redirect, but this * would possily require
* more changes and investigation. * more changes and investigation.
*/ */
/* Get the current postion of the drawable area on screen */ /* Get the current postion of the drawable area on screen */
XTranslateCoordinates( XTranslateCoordinates(
fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Display,
fgStructure.CurrentWindow->Window.Handle, fgStructure.CurrentWindow->Window.Handle,
fgDisplay.pDisplay.RootWindow, fgDisplay.pDisplay.RootWindow,
0, 0, &x, &y, 0, 0, &x, &y,
&child &child
); );
/* Move the decorataions out of the topleft corner of the display */ /* Move the decorataions out of the topleft corner of the display */
XMoveWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle, XMoveWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
-x, -y); -x, -y);
} }
}
#endif #endif /* HAVE_X11_EXTENSIONS_XF86VMODE_H */
/* Grab the keyboard, too */ /* Grab the keyboard, too */
XGrabKeyboard( XGrabKeyboard(
@ -565,7 +600,7 @@ void fgPlatformEnterGameMode( void )
} }
void fgPlatformLeaveGameMode( void ) void fgPlatformLeaveGameMode( void )
{ {
XUngrabPointer( fgDisplay.pDisplay.Display, CurrentTime ); XUngrabPointer( fgDisplay.pDisplay.Display, CurrentTime );
XUngrabKeyboard( fgDisplay.pDisplay.Display, CurrentTime ); XUngrabKeyboard( fgDisplay.pDisplay.Display, CurrentTime );