X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Ffreeglut_gamemode.c;h=a50cdae740b7937201bb5c74e1b2d7f4a08d1f19;hb=2e5dc871b7c1df472978af9811d0e97b6684707c;hp=de6cbb42ccc69424b87368c9dfaea9c90d134cf4;hpb=ed9109c3406ceb4339444506d2a0d9128b0476a0;p=freeglut diff --git a/src/freeglut_gamemode.c b/src/freeglut_gamemode.c index de6cbb4..a50cdae 100644 --- a/src/freeglut_gamemode.c +++ b/src/freeglut_gamemode.c @@ -29,8 +29,6 @@ #include "config.h" #endif -#define G_LOG_DOMAIN "freeglut-gamemode" - #include "../include/GL/freeglut.h" #include "freeglut_internal.h" @@ -59,6 +57,34 @@ void fghRememberState( void ) */ # 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: */ @@ -71,7 +97,7 @@ void fghRememberState( void ) ); if (!fgDisplay.DisplayModeValid) - fgWarning( "Runtime use of XF86VidModeGetModeLine failed.\n" ); + fgWarning( "Runtime use of XF86VidModeGetModeLine failed.\n" ); # else # warning fghRememberState: missing XFree86 video mode extensions, game mode will not change screen resolution when activated @@ -105,10 +131,18 @@ void fghRestoreState( void ) { #if TARGET_HOST_UNIX_X11 +# ifdef X_XF86VidModeGetAllModeLines + /* + * Restore the remembered pointer position: + */ + XWarpPointer( + fgDisplay.Display, None, fgDisplay.RootWindow, 0, 0, 0, 0, + fgDisplay.DisplayPointerX, fgDisplay.DisplayPointerY + ); + /* * This highly depends on the XFree86 extensions, not approved as X Consortium standards */ -# ifdef X_XF86VidModeGetAllModeLines if (fgDisplay.DisplayModeValid) { @@ -135,7 +169,7 @@ void fghRestoreState( void ) 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( fgDisplay.Display, @@ -143,14 +177,22 @@ void fghRestoreState( void ) displayModes[ i ] ); - /* - * In case this will be the last X11 call we do before exit, - * we've to flush the X11 output queue to be sure the command - * is really brought onto it's way to the X server. - * The application should not do this because it - * would not be platform independent then. - */ - XFlush(fgDisplay.Display); + /* + * Now we can restore the remembered ViewPort: + */ + XF86VidModeSetViewPort( + fgDisplay.Display, + 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); return; } @@ -195,7 +237,11 @@ GLboolean fghChangeDisplayMode( GLboolean haveToTest ) */ # 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; int i, displayModesCount; @@ -218,8 +264,8 @@ GLboolean fghChangeDisplayMode( GLboolean haveToTest ) if( fghCheckDisplayMode( displayModes[ i ]->hdisplay, displayModes[ i ]->vdisplay, fgState.GameModeDepth, fgState.GameModeRefresh ) ) { - if( haveToTest ) - return( TRUE ); + if( haveToTest ) + return( TRUE ); /* * OKi, this is the display mode we have been looking for... */ @@ -228,17 +274,6 @@ GLboolean fghChangeDisplayMode( GLboolean haveToTest ) fgDisplay.Screen, 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... */ @@ -309,7 +344,7 @@ GLboolean fghChangeDisplayMode( GLboolean haveToTest ) mode = displayModes; break; } - + /* * Switch to the next display mode, if any */ @@ -421,7 +456,7 @@ int FGAPIENTRY glutEnterGameMode( void ) */ if( fghChangeDisplayMode( FALSE ) == FALSE ) { - fgWarning( "failed to change screen settings" ); + fgWarning( "failed to change screen settings" ); return( FALSE ); } @@ -434,30 +469,85 @@ int FGAPIENTRY glutEnterGameMode( void ) #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: */ - XSetInputFocus( + XSync(fgDisplay.Display, False); + + /* Move the Pointer to the middle of the fullscreen window */ + XWarpPointer( fgDisplay.Display, - fgStructure.GameMode->Window.Handle, - RevertToNone, - CurrentTime + None, + fgDisplay.RootWindow, + 0, 0, 0, 0, + fgState.GameModeSize.X/2, fgState.GameModeSize.Y/2 ); /* - * Confine the mouse pointer to the window's client area + * 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. */ - XGrabPointer( + XSetInputFocus( fgDisplay.Display, fgStructure.GameMode->Window.Handle, - TRUE, - ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|PointerMotionMask, - GrabModeAsync, GrabModeAsync, - fgStructure.GameMode->Window.Handle, - None, + RevertToNone, CurrentTime ); +# ifdef X_XF86VidModeSetViewPort + + if (fgDisplay.DisplayModeValid) { + int x, y; + Window child; + + /* + * Change to viewport to the window topleft edge: + */ + 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, + fgStructure.Window->Window.Handle, + fgDisplay.RootWindow, + 0, 0, &x, &y, + &child + ); + + /* 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 */