Caught a few more little style issues.
[freeglut] / src / freeglut_gamemode.c
index d6c6a25..abee9c6 100644 (file)
@@ -59,16 +59,48 @@ 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:
      */
-    XF86VidModeGetModeLine(
+    fgDisplay.DisplayModeValid = 
+      XF86VidModeGetModeLine(
         fgDisplay.Display,
         fgDisplay.Screen,
         &fgDisplay.DisplayModeClock,
         &fgDisplay.DisplayMode
     );
 
+    if (!fgDisplay.DisplayModeValid)
+            fgWarning( "Runtime use of XF86VidModeGetModeLine failed.\n" );
+
 #   else
 #       warning fghRememberState: missing XFree86 video mode extensions, game mode will not change screen resolution when activated
 #   endif
@@ -101,52 +133,71 @@ void fghRestoreState( void )
 {
 #if TARGET_HOST_UNIX_X11
 
-    /*
-     * This highly depends on the XFree86 extensions, not approved as X Consortium standards
-     */
 #   ifdef X_XF86VidModeGetAllModeLines
-
-    XF86VidModeModeInfo** displayModes;
-    int i, displayModesCount;
-
     /*
-     * Query for all the display available...
+     * Restore the remembered pointer position:
      */
-    XF86VidModeGetAllModeLines(
-        fgDisplay.Display,
-        fgDisplay.Screen,
-        &displayModesCount,
-        &displayModes
+    XWarpPointer(
+        fgDisplay.Display, None, fgDisplay.RootWindow, 0, 0, 0, 0,
+        fgDisplay.DisplayPointerX, fgDisplay.DisplayPointerY
     );
 
     /*
-     * Check every of the modes looking for one that matches our demands
+     * This highly depends on the XFree86 extensions, not approved as X Consortium standards
      */
-    for( i=0; i<displayModesCount; i++ )
+
+    if (fgDisplay.DisplayModeValid)
     {
-        if( displayModes[ i ]->hdisplay == fgDisplay.DisplayMode.hdisplay &&
-            displayModes[ i ]->vdisplay == fgDisplay.DisplayMode.vdisplay &&
-            displayModes[ i ]->dotclock == fgDisplay.DisplayModeClock )
+        XF86VidModeModeInfo** displayModes;
+        int i, displayModesCount;
+
+        /*
+         * Query for all the display available...
+         */
+        XF86VidModeGetAllModeLines(
+            fgDisplay.Display,
+            fgDisplay.Screen,
+            &displayModesCount,
+            &displayModes
+        );
+
+        /*
+         * Check every of the modes looking for one that matches our demands
+         */
+        for( i=0; i<displayModesCount; i++ )
         {
-            /*
-             * OKi, this is the display mode we have been looking for...
-             */
-            XF86VidModeSwitchToMode(
-                fgDisplay.Display,
-                fgDisplay.Screen,
-                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);
-
-            return;
+            if( displayModes[ i ]->hdisplay == fgDisplay.DisplayMode.hdisplay &&
+                displayModes[ i ]->vdisplay == fgDisplay.DisplayMode.vdisplay &&
+                displayModes[ i ]->dotclock == fgDisplay.DisplayModeClock )
+            {
+                /*
+                 * OK, this is the display mode we have been looking for...
+                 */
+                XF86VidModeSwitchToMode(
+                    fgDisplay.Display,
+                    fgDisplay.Screen,
+                    displayModes[ i ]
+                );
+
+                /*
+                 * 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;
+            }
         }
     }
 
@@ -188,52 +239,48 @@ GLboolean fghChangeDisplayMode( GLboolean haveToTest )
      */
 #   ifdef X_XF86VidModeGetAllModeLines
 
-    XF86VidModeModeInfo** displayModes;
-    int i, displayModesCount;
-
     /*
-     * Query for all the display available...
+     * This is also used by applcations which check modes by calling
+     * glutGameModeGet(GLUT_GAME_MODE_POSSIBLE), so allow the check:
      */
-    XF86VidModeGetAllModeLines(
-        fgDisplay.Display,
-        fgDisplay.Screen,
-        &displayModesCount,
-        &displayModes
-    );
-
-    /*
-     * Check every of the modes looking for one that matches our demands
-     */
-    for( i=0; i<displayModesCount; i++ )
+    if (haveToTest || fgDisplay.DisplayModeValid)
     {
-        if( fghCheckDisplayMode( displayModes[ i ]->hdisplay, displayModes[ i ]->vdisplay,
-                                 fgState.GameModeDepth, fgState.GameModeRefresh ) )
-        {
-           if( haveToTest )
-               return( TRUE );
-            /*
-             * OKi, this is the display mode we have been looking for...
-             */
-            XF86VidModeSwitchToMode(
-                fgDisplay.Display,
-                fgDisplay.Screen,
-                displayModes[ i ]
-            );
+        XF86VidModeModeInfo** displayModes;
+        int i, displayModesCount;
 
-            /*
-             * Set the viewport's origin to (0,0) (the game mode window's top-left corner)
-             */
-            XF86VidModeSetViewPort(
-                fgDisplay.Display,
-                fgDisplay.Screen,
-                0,
-                0
-            );
+        /*
+         * Query for all the display available...
+         */
+        XF86VidModeGetAllModeLines(
+            fgDisplay.Display,
+            fgDisplay.Screen,
+            &displayModesCount,
+            &displayModes
+        );
 
-            /*
-             * Return successfull...
-             */
-            return( TRUE );
+        /*
+         * Check every of the modes looking for one that matches our demands
+         */
+        for( i=0; i<displayModesCount; i++ )
+        {
+            if( fghCheckDisplayMode( displayModes[ i ]->hdisplay, displayModes[ i ]->vdisplay,
+                                     fgState.GameModeDepth, fgState.GameModeRefresh ) )
+            {
+                      if( haveToTest )
+                                return( TRUE );
+                /*
+                 * OKi, this is the display mode we have been looking for...
+                 */
+                XF86VidModeSwitchToMode(
+                    fgDisplay.Display,
+                    fgDisplay.Screen,
+                    displayModes[ i ]
+                );
+                /*
+                 * Return successfull...
+                 */
+                return( TRUE );
+            }
         }
     }
 
@@ -299,7 +346,7 @@ GLboolean fghChangeDisplayMode( GLboolean haveToTest )
           mode = displayModes;
           break;
         }
-       
+        
         /*
          * Switch to the next display mode, if any
          */
@@ -411,7 +458,7 @@ int FGAPIENTRY glutEnterGameMode( void )
      */
     if( fghChangeDisplayMode( FALSE ) == FALSE )
     {
-             fgWarning( "failed to change screen settings" );
+              fgWarning( "failed to change screen settings" );
         return( FALSE );
     }
 
@@ -424,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(
+    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:
      */
-    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
      */