Game mode fixes from Bernhard Kaindl and Eric Espie.
authorChristopher John Purnell <cjp@lost.org.uk>
Sun, 17 Aug 2003 17:02:42 +0000 (17:02 +0000)
committerChristopher John Purnell <cjp@lost.org.uk>
Sun, 17 Aug 2003 17:02:42 +0000 (17:02 +0000)
git-svn-id: svn+ssh://svn.code.sf.net/p/freeglut/code/trunk/freeglut/freeglut@163 7f0cb862-5218-0410-a997-914c9d46530a

ChangeLog
src/freeglut_gamemode.c
src/freeglut_internal.h
src/freeglut_window.c

index 995b58e..d81b586 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -268,3 +268,28 @@ October 24, 2002:
 
 (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()
+
index de6cbb4..0813d41 100644 (file)
@@ -59,6 +59,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:
      */
@@ -103,6 +131,14 @@ void fghRememberState( 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
 
     /*
@@ -135,7 +171,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 +179,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 +239,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;
@@ -228,17 +276,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...
                  */
@@ -434,30 +471,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(
-        fgDisplay.Display,
-        fgStructure.GameMode->Window.Handle,
-        RevertToNone,
-        CurrentTime
+    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
     );
 
     /*
-     * 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:
      */
-    XGrabPointer(
+    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(
         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
      */
index b8b8882..4e23f32 100644 (file)
@@ -269,6 +269,11 @@ struct tagSFG_Display
     int             DisplayModeValid;   /* Flag that indicates runtime status*/
     XF86VidModeModeLine DisplayMode;    /* Current screen's display settings */
     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
 
 #elif TARGET_HOST_WIN32
index 4cc38aa..21b3006 100644 (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 );
 
-    /*
-     * 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
 
        WNDCLASS wc;