Game mode fixes from Bernhard Kaindl and Eric Espie.

git-svn-id: https://svn.code.sf.net/p/freeglut/code/trunk@163 7f0cb862-5218-0410-a997-914c9d46530a
This commit is contained in:
cjp 2003-08-17 17:02:42 +00:00
parent 53988cfb1a
commit 9f2e97a2cc
4 changed files with 157 additions and 66 deletions

View File

@ -268,3 +268,28 @@ October 24, 2002:
(99) src/freeglut_window.c:67 Removed #included "mwmborder.c" (99) src/freeglut_window.c:67 Removed #included "mwmborder.c"
*******************************************************************************************
* Changes on 10 August 2003
*******************************************************************************************
(100) GameMode fixes: src/freeglut_gamemode.c src/freeglut_internal.h src/freeglut_window.c
src/freeglut_gamemode.c:
fghRememberState(): remember original XFree86 ViewPort
fghRememberState(): remember original pointer position
fghRestoreState(): restore original pointer position
fghRestoreState(): restore original XFree86 ViewPort
fghChangeDisplayMode(): fix glutGameModeGet(GLUT_GAME_MODE_POSSIBLE)
fghChangeDisplayMode(): remove superflous attempt to change ViewPort
glutEnterGameMode(): move special XMoveWindow() from generic code here
glutEnterGameMode(): call XSync() to avoid races with XPointer calls
glutEnterGameMode(): call to XWrapPointer() to ensure that the pointer is grabbed
glutEnterGameMode(): wait until window is viewable to avoid exit on XSetInputFocus
glutEnterGameMode(): move decorations away to fix fullscreen w/ max resolution
src/freeglut_internal.h:
struct tagSFG_Display: add fields for saving viewport and pointer position
src/freeglut_window.c:
fgOpenWindow(): remove obsolete special case for GameModeEnter()

View File

@ -59,6 +59,34 @@ void fghRememberState( void )
*/ */
# ifdef X_XF86VidModeGetModeLine # ifdef X_XF86VidModeGetModeLine
/*
* Remember the current ViewPort location of the screen to be able to
* restore the ViewPort on LeaveGameMode():
*/
XF86VidModeGetViewPort(
fgDisplay.Display,
fgDisplay.Screen,
&fgDisplay.DisplayViewPortX,
&fgDisplay.DisplayViewPortY
);
/*
* Remember the current pointer location before going fullscreen
* for restoring it later:
*/
{
Window junk_window;
unsigned int mask;
XQueryPointer(
fgDisplay.Display, fgDisplay.RootWindow,
&junk_window, &junk_window,
&fgDisplay.DisplayPointerX, &fgDisplay.DisplayPointerY,
&fgDisplay.DisplayPointerX, &fgDisplay.DisplayPointerY, &mask
);
}
/* /*
* Query the current display settings: * Query the current display settings:
*/ */
@ -103,6 +131,14 @@ void fghRememberState( void )
*/ */
void fghRestoreState( void ) void fghRestoreState( void )
{ {
/*
* Restore the remembered pointer position:
*/
XWarpPointer(
fgDisplay.Display, None, fgDisplay.RootWindow, 0, 0, 0, 0,
fgDisplay.DisplayPointerX, fgDisplay.DisplayPointerY
);
#if TARGET_HOST_UNIX_X11 #if TARGET_HOST_UNIX_X11
/* /*
@ -135,7 +171,7 @@ void fghRestoreState( void )
displayModes[ i ]->dotclock == fgDisplay.DisplayModeClock ) displayModes[ i ]->dotclock == fgDisplay.DisplayModeClock )
{ {
/* /*
* OKi, this is the display mode we have been looking for... * OK, this is the display mode we have been looking for...
*/ */
XF86VidModeSwitchToMode( XF86VidModeSwitchToMode(
fgDisplay.Display, fgDisplay.Display,
@ -144,11 +180,19 @@ void fghRestoreState( void )
); );
/* /*
* In case this will be the last X11 call we do before exit, * Now we can restore the remembered ViewPort:
* we've to flush the X11 output queue to be sure the command */
* is really brought onto it's way to the X server. XF86VidModeSetViewPort(
* The application should not do this because it fgDisplay.Display,
* would not be platform independent then. fgDisplay.Screen,
fgDisplay.DisplayViewPortX,
fgDisplay.DisplayViewPortY
);
/*
* 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
* commands sent to the X server before the application exists.
*/ */
XFlush(fgDisplay.Display); XFlush(fgDisplay.Display);
@ -195,7 +239,11 @@ GLboolean fghChangeDisplayMode( GLboolean haveToTest )
*/ */
# ifdef X_XF86VidModeGetAllModeLines # ifdef X_XF86VidModeGetAllModeLines
if (fgDisplay.DisplayModeValid) /*
* This is also used by applcations which check modes by calling
* glutGameModeGet(GLUT_GAME_MODE_POSSIBLE), so allow the check:
*/
if (haveToTest || fgDisplay.DisplayModeValid)
{ {
XF86VidModeModeInfo** displayModes; XF86VidModeModeInfo** displayModes;
int i, displayModesCount; int i, displayModesCount;
@ -228,17 +276,6 @@ GLboolean fghChangeDisplayMode( GLboolean haveToTest )
fgDisplay.Screen, fgDisplay.Screen,
displayModes[ i ] displayModes[ i ]
); );
/*
* Set the viewport's origin to (0,0) (the game mode window's top-left corner)
*/
XF86VidModeSetViewPort(
fgDisplay.Display,
fgDisplay.Screen,
0,
0
);
/* /*
* Return successfull... * Return successfull...
*/ */
@ -434,8 +471,45 @@ int FGAPIENTRY glutEnterGameMode( void )
#if TARGET_HOST_UNIX_X11 #if TARGET_HOST_UNIX_X11
/* Move the window up to the topleft corner */
XMoveWindow(fgDisplay.Display, fgStructure.Window->Window.Handle, 0, 0);
/* /*
* Move the mouse pointer over the game mode window * Sync needed to avoid a real race, the Xserver must have really created
* the window before we can grab the pointer into it:
*/
XSync(fgDisplay.Display, False);
/* Move the Pointer to the middle of the fullscreen window */
XWarpPointer(
fgDisplay.Display,
None,
fgDisplay.RootWindow,
0, 0, 0, 0,
fgState.GameModeSize.X/2, fgState.GameModeSize.Y/2
);
/*
* Grab the pointer to confine it into the window after the calls to
* XWrapPointer() which ensure that the pointer really enters the window.
*
* We also need to wait here until XGrabPointer() returns GrabSuccess,
* otherwise the new window is not viewable yet and if the next function
* (XSetInputFocus) is called with a not yet viewable window, it will exit
* the application which we have to aviod, so wait until it's viewable:
*/
while (GrabSuccess =! XGrabPointer(
fgDisplay.Display, fgStructure.GameMode->Window.Handle,
TRUE, ButtonPressMask|ButtonReleaseMask|ButtonMotionMask
|PointerMotionMask,
GrabModeAsync, GrabModeAsync,
fgStructure.GameMode->Window.Handle, None, CurrentTime)) {
usleep (100);
}
/*
* Change input focus to the new window. This will exit the application
* if the new window is not viewable yet, see the XGrabPointer loop above.
*/ */
XSetInputFocus( XSetInputFocus(
fgDisplay.Display, fgDisplay.Display,
@ -444,20 +518,38 @@ int FGAPIENTRY glutEnterGameMode( void )
CurrentTime CurrentTime
); );
# ifdef X_XF86VidModeSetViewPort
if (fgDisplay.DisplayModeValid) {
int x, y;
Window child;
/* /*
* Confine the mouse pointer to the window's client area * Change to viewport to the window topleft edge:
*/ */
XGrabPointer( XF86VidModeSetViewPort(fgDisplay.Display, fgDisplay.Screen, 0, 0);
/*
* Final window repositioning: It could be avoided using an undecorated
* window using override_redirect, but this * would possily require more
* changes and investigation.
*/
/* Get the current postion of the drawable area on screen */
XTranslateCoordinates(
fgDisplay.Display, fgDisplay.Display,
fgStructure.GameMode->Window.Handle, fgStructure.Window->Window.Handle,
TRUE, fgDisplay.RootWindow,
ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|PointerMotionMask, 0, 0, &x, &y,
GrabModeAsync, GrabModeAsync, &child
fgStructure.GameMode->Window.Handle,
None,
CurrentTime
); );
/* Move the decorataions out of the topleft corner of the display */
XMoveWindow(fgDisplay.Display, fgStructure.Window->Window.Handle, -x, -y);
}
#endif
/* /*
* Grab the keyboard, too * Grab the keyboard, too
*/ */

View File

@ -269,6 +269,11 @@ struct tagSFG_Display
int DisplayModeValid; /* Flag that indicates runtime status*/ int DisplayModeValid; /* Flag that indicates runtime status*/
XF86VidModeModeLine DisplayMode; /* Current screen's display settings */ XF86VidModeModeLine DisplayMode; /* Current screen's display settings */
int DisplayModeClock; /* The display mode's refresh rate */ int DisplayModeClock; /* The display mode's refresh rate */
int DisplayViewPortX; /* saved X location of the viewport */
int DisplayViewPortY; /* saved Y location of the viewport */
int DisplayPointerX; /* saved X location of the pointer */
int DisplayPointerY; /* saved Y location of the pointer */
#endif #endif
#elif TARGET_HOST_WIN32 #elif TARGET_HOST_WIN32

View File

@ -565,37 +565,6 @@ void fgOpenWindow( SFG_Window* window, const char* title, int x, int y, int w, i
*/ */
XMapWindow( fgDisplay.Display, window->Window.Handle ); XMapWindow( fgDisplay.Display, window->Window.Handle );
/*
* In game mode, move the viewport a bit to hide the decorations.
* This code depends on the XFree86 video mode extensions.
*/
if( gameMode == TRUE )
{
/*
* This somehow fixes the glutGet() GLUT_WINDOW_X and GLUT_WINDOW_Y problem...
*/
XMoveWindow( fgDisplay.Display, window->Window.Handle, x, y );
# ifdef X_XF86VidModeSetViewPort
/*
* Set the newly created window as the current one...
*/
fgSetWindow( window );
/*
* Move the viewport a bit down and right from top-left corner to hide the decorations
*/
XF86VidModeSetViewPort(
fgDisplay.Display,
fgDisplay.Screen,
glutGet( GLUT_WINDOW_X ),
glutGet( GLUT_WINDOW_Y )
);
# endif
}
#elif TARGET_HOST_WIN32 #elif TARGET_HOST_WIN32
WNDCLASS wc; WNDCLASS wc;