Stripped out tabs and end-of-line whitespace
[freeglut] / src / freeglut_gamemode.c
index d6c6a25..703005d 100644 (file)
@@ -29,9 +29,7 @@
 #include "config.h"
 #endif
 
-#define  G_LOG_DOMAIN  "freeglut-gamemode"
-
-#include "../include/GL/freeglut.h"
+#include <GL/freeglut.h>
 #include "freeglut_internal.h"
 
 /*
@@ -55,22 +53,58 @@ void fghRememberState( void )
 #if TARGET_HOST_UNIX_X11
 
     /*
-     * This highly depends on the XFree86 extensions, not approved as X Consortium standards
+     * This highly depends on the XFree86 extensions,
+     * not approved as X Consortium standards
      */
 #   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
+    /*
+     * XXX warning fghRememberState: missing XFree86 video mode extensions,
+     * XXX game mode will not change screen resolution when activated
+     */
 #   endif
 
 #elif TARGET_HOST_WIN32
@@ -84,12 +118,14 @@ void fghRememberState( void )
 /* hack to get around my stupid cross-gcc headers */
 #define FREEGLUT_ENUM_CURRENT_SETTINGS -1
 
-    EnumDisplaySettings( NULL, FREEGLUT_ENUM_CURRENT_SETTINGS, &fgDisplay.DisplayMode );
+    EnumDisplaySettings( NULL, FREEGLUT_ENUM_CURRENT_SETTINGS,
+                         &fgDisplay.DisplayMode );
 
     /*
      * Make sure we will be restoring all settings needed
      */
-    fgDisplay.DisplayMode.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
+    fgDisplay.DisplayMode.dmFields |=
+        DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
 
 #endif
 }
@@ -101,57 +137,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;
+
+        XF86VidModeGetAllModeLines(
+            fgDisplay.Display,
+            fgDisplay.Screen,
+            &displayModesCount,
+            &displayModes
+        );
+
+        /*
+         * Check every of the modes looking for one that matches our demands.
+         * If we find one, switch to it and restore the remembered viewport.
+         */
+        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 )
+            {
+                XF86VidModeSwitchToMode(
+                    fgDisplay.Display,
+                    fgDisplay.Screen,
+                    displayModes[ i ]
+                );
+                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 exits.
+                 */
+                XFlush( fgDisplay.Display );
+
+                return;
+            }
         }
     }
 
 #   else
-#       warning fghRestoreState: missing XFree86 video mode extensions, game mode will not change screen resolution when activated
+    /*
+     * XXX warning fghRestoreState: missing XFree86 video mode extensions,
+     * XXX game mode will not change screen resolution when activated
+     */
 #   endif
 
 #elif TARGET_HOST_WIN32
@@ -172,8 +222,10 @@ GLboolean fghCheckDisplayMode( int width, int height, int depth, int refresh )
     /*
      * The desired values should be stored in fgState structure...
      */
-    return( (width == fgState.GameModeSize.X) && (height == fgState.GameModeSize.Y) &&
-            (depth == fgState.GameModeDepth)  && (refresh == fgState.GameModeRefresh) );
+    return ( width == fgState.GameModeSize.X ) &&
+           ( height == fgState.GameModeSize.Y ) &&
+           ( depth == fgState.GameModeDepth ) &&
+           (refresh == fgState.GameModeRefresh );
 }
 
 /*
@@ -184,127 +236,111 @@ GLboolean fghChangeDisplayMode( GLboolean haveToTest )
 #if TARGET_HOST_UNIX_X11
 
     /*
-     * This highly depends on the XFree86 extensions, not approved as X Consortium standards
+     * 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...
-     */
-    XF86VidModeGetAllModeLines(
-        fgDisplay.Display,
-        fgDisplay.Screen,
-        &displayModesCount,
-        &displayModes
-    );
-
     /*
-     * Check every of the modes looking for one that matches our demands
+     * This is also used by applcations which check modes by calling
+     * glutGameModeGet(GLUT_GAME_MODE_POSSIBLE), so allow the check:
      */
-    for( i=0; i<displayModesCount; i++ )
+    if( haveToTest || fgDisplay.DisplayModeValid )
     {
-        if( fghCheckDisplayMode( displayModes[ i ]->hdisplay, displayModes[ i ]->vdisplay,
-                                 fgState.GameModeDepth, fgState.GameModeRefresh ) )
+        XF86VidModeModeInfo** displayModes;
+        int i, displayModesCount;
+
+        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 )
-               return( TRUE );
-            /*
-             * OKi, this is the display mode we have been looking for...
-             */
-            XF86VidModeSwitchToMode(
-                fgDisplay.Display,
-                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...
-             */
-            return( TRUE );
+            if( fghCheckDisplayMode( displayModes[ i ]->hdisplay,
+                                     displayModes[ i ]->vdisplay,
+                                     fgState.GameModeDepth,
+                                     fgState.GameModeRefresh ) )
+            {
+                if( haveToTest )
+                    return GL_TRUE;
+                /*
+                 * OKi, this is the display mode we have been looking for...
+                 */
+                XF86VidModeSwitchToMode(
+                    fgDisplay.Display,
+                    fgDisplay.Screen,
+                    displayModes[ i ]
+                );
+                return GL_TRUE;
+            }
         }
     }
 
     /*
      * Something must have went wrong
      */
-    return( FALSE );
+    return GL_FALSE;
 
 #   else
-#       warning fghChangeDisplayMode: missing XFree86 video mode extensions, game mode will not change screen resolution when activated
+    /*
+     * XXX warning fghChangeDisplayMode: missing XFree86 video mode extensions,
+     * XXX game mode will not change screen resolution when activated
+     */
 #   endif
 
 #elif TARGET_HOST_WIN32
 
     unsigned int    displayModes = 0, mode = 0xffffffff;
-    GLboolean success = FALSE;
-/*    HDC      desktopDC; */
+    GLboolean success = GL_FALSE;
+    /* HDC      desktopDC; */
     DEVMODE  devMode;
 
     /*
      * Enumerate the available display modes
      * Try to get a complete match
      */
-    while( EnumDisplaySettings( NULL, displayModes, &devMode ) == TRUE )
+    while( EnumDisplaySettings( NULL, displayModes, &devMode ) )
     {
         /*
          * Does the enumerated display mode match the user's preferences?
          */
         if( fghCheckDisplayMode( devMode.dmPelsWidth,  devMode.dmPelsHeight,
-                                 devMode.dmBitsPerPel, devMode.dmDisplayFrequency ) )
+                                 devMode.dmBitsPerPel,
+                                 devMode.dmDisplayFrequency ) )
         {
-            /*
-             * OKi, we've found a matching display mode, remember its number and break
-             */
             mode = displayModes;
             break;
         }
-
-        /*
-         * Switch to the next display mode, if any
-         */
         displayModes++;
     }
 
-    if ( mode == 0xffffffff )
+    if( mode == 0xffffffff )
     {
-      /* then try without Display Frequency */
-      displayModes = 0;
-
-      /*
-       * Enumerate the available display modes
-       */
-      while( EnumDisplaySettings( NULL, displayModes, &devMode ) == TRUE )
-      {
         /* then try without Display Frequency */
+        displayModes = 0;
 
-        if( fghCheckDisplayMode( devMode.dmPelsWidth,  devMode.dmPelsHeight,
-                                 devMode.dmBitsPerPel, fgState.GameModeRefresh))
-        {
-          /*
-           * OKi, we've found a matching display mode, remember its number and break
-           */
-          mode = displayModes;
-          break;
-        }
-       
         /*
-         * Switch to the next display mode, if any
+         * Enumerate the available display modes
          */
-        displayModes++;
-      }
+        while( EnumDisplaySettings( NULL, displayModes, &devMode ) )
+        {
+            /* then try without Display Frequency */
+            if( fghCheckDisplayMode( devMode.dmPelsWidth,
+                                     devMode.dmPelsHeight,
+                                     devMode.dmBitsPerPel,
+                                     fgState.GameModeRefresh ) )
+            {
+                mode = displayModes;
+                break;
+            }
+            displayModes++;
+        }
     }
 
     /*
@@ -317,21 +353,17 @@ GLboolean fghChangeDisplayMode( GLboolean haveToTest )
         /*
          * Mark the values we want to modify in the display change call
          */
-        devMode.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
+        devMode.dmFields |=
+            DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
 
-        /*
-         * Change the current display mode (possibly in test mode only)
-         */
         retVal = ChangeDisplaySettings( &devMode, haveToTest ? CDS_TEST : 0 );
 
         /*
          * I don't know if it's really needed, but looks nice:
          */
-        success = (retVal == DISP_CHANGE_SUCCESSFUL) || (retVal == DISP_CHANGE_NOTUPDATED);
+        success = (retVal == DISP_CHANGE_SUCCESSFUL) ||
+            (retVal == DISP_CHANGE_NOTUPDATED);
 
-        /*
-         * If it was not a test, remember the current screen settings
-         */
         if( !haveToTest && success )
         {
             fgState.GameModeSize.X  = devMode.dmPelsWidth;
@@ -341,10 +373,7 @@ GLboolean fghChangeDisplayMode( GLboolean haveToTest )
         }
     }
 
-    /*
-     * Otherwise we must have failed somewhere
-     */
-    return( success );
+    return success;
 
 #endif
 }
@@ -365,14 +394,18 @@ void FGAPIENTRY glutGameModeString( const char* string )
      * that I assumed it is: "[width]x[height]:[depth]@[refresh rate]", which
      * appears in all GLUT game mode programs I have seen to date.
      */
-    if( sscanf( string, "%ix%i:%i@%i", &width, &height, &depth, &refresh ) != 4 )
+    if( sscanf( string, "%ix%i:%i@%i", &width, &height, &depth, &refresh ) !=
+        4 )
         if( sscanf( string, "%ix%i:%i", &width, &height, &depth ) != 3 )
             if( sscanf( string, "%ix%i@%i", &width, &height, &refresh ) != 3 )
                 if( sscanf( string, "%ix%i", &width, &height ) != 2 )
                     if( sscanf( string, ":%i@%i", &depth, &refresh ) != 2 )
                         if( sscanf( string, ":%i", &depth ) != 1 )
                             if( sscanf( string, "@%i", &refresh ) != 1 )
-                                fgWarning( "unable to parse game mode string `%s'", string );
+                                fgWarning(
+                                    "unable to parse game mode string `%s'",
+                                    string
+                                );
 
     /*
      * Hopefully it worked, and if not, we still have the default values
@@ -388,66 +421,107 @@ void FGAPIENTRY glutGameModeString( const char* string )
  */
 int FGAPIENTRY glutEnterGameMode( void )
 {
-    /*
-     * Check if a game mode window already exists...
-     */
-    if( fgStructure.GameMode != NULL )
-    {
-        /*
-         * ...if so, delete it before proceeding...
-         */
-        fgAddToWindowDestroyList( fgStructure.GameMode, TRUE );
-    }
+    if( fgStructure.GameMode )
+        fgAddToWindowDestroyList( fgStructure.GameMode );
     else
-    {
-        /*
-         * ...otherwise remember the current resolution, etc.
-         */
-        fghRememberState();
-    }
+        fghRememberState( );
 
-    /*
-     * We are ready to change the current screen's resolution now
-     */
-    if( fghChangeDisplayMode( FALSE ) == FALSE )
+    if( ! fghChangeDisplayMode( GL_FALSE ) )
     {
-             fgWarning( "failed to change screen settings" );
-        return( FALSE );
+        fgWarning( "failed to change screen settings" );
+        return FALSE;
     }
 
-    /*
-     * Finally, have the game mode window created
-     */
-    fgStructure.GameMode = fgCreateWindow( 
-        NULL, "FREEGLUT", 0, 0, fgState.GameModeSize.X, fgState.GameModeSize.Y, TRUE 
+    fgStructure.GameMode = fgCreateWindow(
+        NULL, "FREEGLUT", 0, 0,
+        fgState.GameModeSize.X, fgState.GameModeSize.Y, GL_TRUE, GL_FALSE
     );
 
+    fgStructure.GameMode->State.IsGameMode = GL_TRUE;
+
 #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
      */
@@ -461,10 +535,7 @@ int FGAPIENTRY glutEnterGameMode( void )
 
 #endif
 
-    /*
-     * Return successfull
-     */
-    return( TRUE );
+    return TRUE;
 }
 
 /*
@@ -472,26 +543,19 @@ int FGAPIENTRY glutEnterGameMode( void )
  */
 void FGAPIENTRY glutLeaveGameMode( void )
 {
-    freeglut_return_if_fail( fgStructure.GameMode != NULL );
+    freeglut_return_if_fail( fgStructure.GameMode );
 
-    /*
-     * First of all, have the game mode window destroyed
-     */
-    fgAddToWindowDestroyList( fgStructure.GameMode, TRUE );
+    fgStructure.GameMode->State.IsGameMode = GL_FALSE;
+
+    fgAddToWindowDestroyList( fgStructure.GameMode );
 
 #if TARGET_HOST_UNIX_X11
 
-    /*
-     * Ungrab the mouse and keyboard
-     */
     XUngrabPointer( fgDisplay.Display, CurrentTime );
     XUngrabKeyboard( fgDisplay.Display, CurrentTime );
 
 #endif
 
-    /*
-     * Then, have the desktop visual settings restored
-     */
     fghRestoreState();
 }
 
@@ -500,59 +564,34 @@ void FGAPIENTRY glutLeaveGameMode( void )
  */
 int FGAPIENTRY glutGameModeGet( GLenum eWhat )
 {
-    /*
-     * See why are we bothered
-     */
     switch( eWhat )
     {
     case GLUT_GAME_MODE_ACTIVE:
-        /*
-         * Check if the game mode is currently active
-         */
-        return( fgStructure.GameMode != NULL );
+        return !!fgStructure.GameMode;
 
     case GLUT_GAME_MODE_POSSIBLE:
-        /*
-         * Check if the current game mode settings are valid
-         */
-        return( fghChangeDisplayMode( TRUE ) );
+        return fghChangeDisplayMode( GL_TRUE );
 
     case GLUT_GAME_MODE_WIDTH:
-        /*
-         * The game mode screen width
-         */
-        return( fgState.GameModeSize.X );
+        return fgState.GameModeSize.X;
 
     case GLUT_GAME_MODE_HEIGHT:
-        /*
-         * The game mode screen height
-         */
-        return( fgState.GameModeSize.Y );
+        return fgState.GameModeSize.Y;
 
     case GLUT_GAME_MODE_PIXEL_DEPTH:
-        /*
-         * The game mode pixel depth
-         */
-        return( fgState.GameModeDepth );
+        return fgState.GameModeDepth;
 
     case GLUT_GAME_MODE_REFRESH_RATE:
-        /*
-         * The game mode refresh rate
-         */
-        return( fgState.GameModeRefresh );
+        return fgState.GameModeRefresh;
 
     case GLUT_GAME_MODE_DISPLAY_CHANGED:
         /*
          * This is true if the game mode has been activated successfully..
          */
-        return( fgStructure.GameMode != NULL );
+        return !!fgStructure.GameMode;
     }
 
-    return( -1 );
+    return -1;
 }
 
 /*** END OF FILE ***/
-
-
-
-