Implementing John Tsiombikas' game mode patch per e-mail dated 3/15/11 8:04 PM
[freeglut] / src / freeglut_gamemode.c
index 29a2947..137f1ea 100644 (file)
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#define  G_LOG_DOMAIN  "freeglut-gamemode"
-
-#include "../include/GL/freeglut.h"
+#include <GL/freeglut.h>
 #include "freeglut_internal.h"
 
 /*
 
 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
 
+static int xrandr_resize(int xsz, int ysz, int just_checking)
+{
+    int res = -1;
+
+#ifdef HAVE_X11_EXTENSIONS_XRANDR_H
+    int event_base, error_base;
+    Status st;
+    XRRScreenConfiguration *xrr_config;
+    XRRScreenSize *ssizes;
+    Rotation rot;
+    int i, ssizes_count, curr;
+    Time timestamp, cfg_timestamp;
+
+    /* must check at runtime for the availability of the extension */
+    if(!XRRQueryExtension(fgDisplay.Display, &event_base, &error_base)) {
+        return -1;
+    }
+
+    if(!(xrr_config = XRRGetScreenInfo(fgDisplay.Display, fgDisplay.RootWindow))) {
+        fgWarning("XRRGetScreenInfo failed");
+        return -1;
+    }
+    ssizes = XRRConfigSizes(xrr_config, &ssizes_count);
+    curr = XRRConfigCurrentConfiguration(xrr_config, &rot);
+    timestamp = XRRConfigTimes(xrr_config, &cfg_timestamp);
+
+    if(xsz == ssizes[curr].width && ysz == ssizes[curr].height) {
+        /* no need to switch, we're already in the requested mode */
+        res = 0;
+        goto done;
+    }
+
+    for(i=0; i<ssizes_count; i++) {
+        if(ssizes[i].width == xsz && ssizes[i].height == ysz) {
+            break;  /* found it */
+        }
+    }
+    if(i == ssizes_count)
+        goto done;
+
+    if(just_checking) {
+        res = 0;
+        goto done;
+    }
+
+    if((st = XRRSetScreenConfig(fgDisplay.Display, xrr_config, fgDisplay.RootWindow,
+                    i, rot, timestamp)) != 0) {
+        fgWarning("XRRSetScreenConfig failed");
+        goto done;
+    }
+    res = 0;
+
+done:
+    XRRFreeScreenConfigInfo(xrr_config);
+#endif
+    return res;
+}
+
+
 /*
  * Remembers the current visual settings, so that
  * we can change them and restore later...
  */
-void fghRememberState( void )
+static void fghRememberState( void )
 {
-#if TARGET_HOST_UNIX_X11
+#if TARGET_HOST_POSIX_X11
+    int event_base, error_base;
+
+#   ifdef HAVE_X11_EXTENSIONS_XRANDR_H
+    if(XRRQueryExtension(fgDisplay.Display, &event_base, &error_base)) {
+        XRRScreenConfiguration *xrr_config;
+        XRRScreenSize *ssizes;
+        Rotation rot;
+        int ssize_count, curr;
+
+        if((xrr_config = XRRGetScreenInfo(fgDisplay.Display, fgDisplay.RootWindow))) {
+            ssizes = XRRConfigSizes(xrr_config, &ssize_count);
+            curr = XRRConfigCurrentConfiguration(xrr_config, &rot);
+
+            fgDisplay.prev_xsz = ssizes[curr].width;
+            fgDisplay.prev_ysz = ssizes[curr].height;
+            fgDisplay.prev_size_valid = 1;
+            XRRFreeScreenConfigInfo(xrr_config);
+            return;
+        }
+    }
+#   endif
 
     /*
-     * 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
-
+#   ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
+    if(!XF86VidModeQueryExtension(fgDisplay.Display, &event_base, &error_base)) {
+        return;
+    }
 
     /*
      * 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
-    );
+    if( !XF86VidModeGetViewPort(
+             fgDisplay.Display,
+             fgDisplay.Screen,
+             &fgDisplay.DisplayViewPortX,
+             &fgDisplay.DisplayViewPortY ) )
+        fgWarning( "XF86VidModeGetViewPort failed" );
 
     /*
      * 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
-       );
+        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:
-     */
-    fgDisplay.DisplayModeValid = 
+    /* Query the current display settings: */
+    fgDisplay.DisplayModeValid =
       XF86VidModeGetModeLine(
         fgDisplay.Display,
         fgDisplay.Screen,
@@ -98,30 +173,25 @@ void fghRememberState( void )
         &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
+    if( !fgDisplay.DisplayModeValid )
+            fgWarning( "XF86VidModeGetModeLine failed" );
 #   endif
 
-#elif TARGET_HOST_WIN32
+#elif TARGET_HOST_MS_WINDOWS
 
 /*    DEVMODE devMode; */
 
-    /*
-     * Grab the current desktop settings...
-     */
+    /* Grab the current desktop settings... */
 
 /* hack to get around my stupid cross-gcc headers */
 #define FREEGLUT_ENUM_CURRENT_SETTINGS -1
 
-    EnumDisplaySettings( NULL, FREEGLUT_ENUM_CURRENT_SETTINGS, &fgDisplay.DisplayMode );
+    EnumDisplaySettings( fgDisplay.DisplayName, 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;
+    /* Make sure we will be restoring all settings needed */
+    fgDisplay.DisplayMode.dmFields |=
+        DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
 
 #endif
 }
@@ -129,270 +199,290 @@ void fghRememberState( void )
 /*
  * Restores the previously remembered visual settings
  */
-void fghRestoreState( void )
+static void fghRestoreState( void )
 {
-#if TARGET_HOST_UNIX_X11
-    /*
-     * Restore the remembered pointer position:
-     */
+#if TARGET_HOST_POSIX_X11
+
+#   ifdef HAVE_X11_EXTENSIONS_XRANDR_H
+    if(fgDisplay.prev_size_valid) {
+        if(xrandr_resize(fgDisplay.prev_xsz, fgDisplay.prev_ysz, 0) != -1) {
+            fgDisplay.prev_size_valid = 0;
+            return;
+        }
+    }
+#   endif
+
+
+#   ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
+    /* Restore the remembered pointer position: */
     XWarpPointer(
-       fgDisplay.Display, None, fgDisplay.RootWindow, 0, 0, 0, 0,
-       fgDisplay.DisplayPointerX, fgDisplay.DisplayPointerY
+        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
+     * This highly depends on the XFree86 extensions,
+     * not approved as X Consortium standards
      */
-#   ifdef X_XF86VidModeGetAllModeLines
 
-    if (fgDisplay.DisplayModeValid)
+    if( fgDisplay.DisplayModeValid )
     {
         XF86VidModeModeInfo** displayModes;
         int i, displayModesCount;
 
-        /*
-         * Query for all the display available...
-         */
-        XF86VidModeGetAllModeLines(
-            fgDisplay.Display,
-            fgDisplay.Screen,
-            &displayModesCount,
-            &displayModes
-        );
+        if( !XF86VidModeGetAllModeLines(
+                 fgDisplay.Display,
+                 fgDisplay.Screen,
+                 &displayModesCount,
+                 &displayModes ) )
+        {
+            fgWarning( "XF86VidModeGetAllModeLines failed" );
+            return;
+        }
+
 
         /*
-         * Check every of the modes looking for one that matches our demands
+         * 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++ )
+        for( i = 0; i < displayModesCount; i++ )
         {
-            if( displayModes[ i ]->hdisplay == fgDisplay.DisplayMode.hdisplay &&
-                displayModes[ i ]->vdisplay == fgDisplay.DisplayMode.vdisplay &&
-                displayModes[ i ]->dotclock == fgDisplay.DisplayModeClock )
+            if(displayModes[ i ]->hdisplay == fgDisplay.DisplayMode.hdisplay &&
+               displayModes[ i ]->vdisplay == fgDisplay.DisplayMode.vdisplay &&
+               displayModes[ i ]->dotclock == fgDisplay.DisplayModeClock )
             {
+                if( !XF86VidModeSwitchToMode(
+                         fgDisplay.Display,
+                         fgDisplay.Screen,
+                         displayModes[ i ] ) )
+                {
+                    fgWarning( "XF86VidModeSwitchToMode failed" );
+                    break;
+                }
+
+                if( !XF86VidModeSetViewPort(
+                         fgDisplay.Display,
+                         fgDisplay.Screen,
+                         fgDisplay.DisplayViewPortX,
+                         fgDisplay.DisplayViewPortY ) )
+                    fgWarning( "HAVE_X11_EXTENSIONS_XF86VMODE_H failed" );
+
+
                 /*
-                 * OK, this is the display mode we have been looking for...
+                 * 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.
                  */
-                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;
+                XFlush( fgDisplay.Display );
+
+                break;
             }
         }
+        XFree( displayModes );
     }
 
-#   else
-#       warning fghRestoreState: missing XFree86 video mode extensions, game mode will not change screen resolution when activated
 #   endif
 
-#elif TARGET_HOST_WIN32
+#elif TARGET_HOST_MS_WINDOWS
 
-    /*
-     * Restore the previously rememebered desktop display settings
-     */
-    ChangeDisplaySettings( &fgDisplay.DisplayMode, 0 );
+    /* Restore the previously remembered desktop display settings */
+    ChangeDisplaySettingsEx( fgDisplay.DisplayName,&fgDisplay.DisplayMode, 0,0,0 );
 
 #endif
 }
 
+#if TARGET_HOST_POSIX_X11
+#ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
+
 /*
- * Checks the display mode settings against user's preferences
+ * Checks a single display mode settings against user's preferences.
  */
-GLboolean fghCheckDisplayMode( int width, int height, int depth, int refresh )
+static 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) );
+    /* The desired values should be stored in fgState structure... */
+    return ( width == fgState.GameModeSize.X ) &&
+           ( height == fgState.GameModeSize.Y ) &&
+           ( depth == fgState.GameModeDepth ) &&
+           ( refresh == fgState.GameModeRefresh );
+}
+
+/*
+ * Checks all display modes settings against user's preferences.
+ * Returns the mode number found or -1 if none could be found.
+ */
+static int fghCheckDisplayModes( GLboolean exactMatch, int displayModesCount, XF86VidModeModeInfo** displayModes )
+{
+    int i;
+    for( i = 0; i < displayModesCount; i++ )
+    {
+        /* Compute the displays refresh rate, dotclock comes in kHz. */
+        int refresh = ( displayModes[ i ]->dotclock * 1000 ) /
+                      ( displayModes[ i ]->htotal * displayModes[ i ]->vtotal );
+
+        if( fghCheckDisplayMode( displayModes[ i ]->hdisplay,
+                                 displayModes[ i ]->vdisplay,
+                                 fgState.GameModeDepth,
+                                 ( exactMatch ? refresh : fgState.GameModeRefresh ) ) ) {
+            if (!exactMatch)
+            {
+                /* Update the chosen refresh rate, otherwise a
+                 * glutGameModeGet(GLUT_GAME_MODE_REFRESH_RATE) would not
+                 * return the right values
+                 */
+                fgState.GameModeRefresh = refresh;
+            }
+
+            return i;
+        }
+    }
+    return -1;
 }
 
+#endif
+#endif
+
 /*
  * Changes the current display mode to match user's settings
  */
-GLboolean fghChangeDisplayMode( GLboolean haveToTest )
+static GLboolean fghChangeDisplayMode( GLboolean haveToTest )
 {
-#if TARGET_HOST_UNIX_X11
+    GLboolean success = GL_FALSE;
+#if TARGET_HOST_POSIX_X11
+
+    /* first try to use XRandR, then fallback to XF86VidMode */
+#   ifdef HAVE_X11_EXTENSIONS_XRANDR_H
+    if(xrandr_resize(fgState.GameModeSize.X, fgState.GameModeSize.Y, haveToTest) != -1) {
+        return GL_TRUE;
+    }
+#   endif
+
 
     /*
-     * 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
+#   ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
 
     /*
      * This is also used by applcations which check modes by calling
      * glutGameModeGet(GLUT_GAME_MODE_POSSIBLE), so allow the check:
      */
-    if (haveToTest || fgDisplay.DisplayModeValid)
+    if( haveToTest || fgDisplay.DisplayModeValid )
     {
         XF86VidModeModeInfo** displayModes;
         int i, displayModesCount;
 
-        /*
-         * Query for all the display available...
-         */
-        XF86VidModeGetAllModeLines(
-            fgDisplay.Display,
-            fgDisplay.Screen,
-            &displayModesCount,
-            &displayModes
-        );
+        if( !XF86VidModeGetAllModeLines(
+                 fgDisplay.Display,
+                 fgDisplay.Screen,
+                 &displayModesCount,
+                 &displayModes ) )
+        {
+            fgWarning( "XF86VidModeGetAllModeLines failed" );
+            return success;
+        }
+
 
         /*
-         * Check every of the modes looking for one that matches our demands
+         * Check every of the modes looking for one that matches our demands,
+         * ignoring the refresh rate if no exact match could be found.
          */
-        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 );
-            }
+        i = fghCheckDisplayModes( GL_TRUE, displayModesCount, displayModes );
+        if( i < 0 ) {
+            i = fghCheckDisplayModes( GL_FALSE, displayModesCount, displayModes );
+        }
+        success = ( i < 0 ) ? GL_FALSE : GL_TRUE;
+
+        if( !haveToTest && success ) {
+            if( !XF86VidModeSwitchToMode(
+                     fgDisplay.Display,
+                     fgDisplay.Screen,
+                     displayModes[ i ] ) )
+                fgWarning( "XF86VidModeSwitchToMode failed" );
         }
+
+        XFree( displayModes );
     }
 
+#   else
+
     /*
-     * Something must have went wrong
+     * XXX warning fghChangeDisplayMode: missing XFree86 video mode extensions,
+     * XXX game mode will not change screen resolution when activated
      */
-    return( FALSE );
+    success = GL_TRUE;
 
-#   else
-#       warning fghChangeDisplayMode: missing XFree86 video mode extensions, game mode will not change screen resolution when activated
 #   endif
 
-#elif TARGET_HOST_WIN32
+#elif TARGET_HOST_MS_WINDOWS
 
-    unsigned int    displayModes = 0, mode = 0xffffffff;
-    GLboolean success = FALSE;
-/*    HDC      desktopDC; */
     DEVMODE  devMode;
+    char *fggmstr = NULL;
 
-    /*
-     * Enumerate the available display modes
-     * Try to get a complete match
-     */
-    while( EnumDisplaySettings( NULL, displayModes, &devMode ) == TRUE )
-    {
-        /*
-         * Does the enumerated display mode match the user's preferences?
-         */
-        if( fghCheckDisplayMode( devMode.dmPelsWidth,  devMode.dmPelsHeight,
-                                 devMode.dmBitsPerPel, devMode.dmDisplayFrequency ) )
-        {
-            /*
-             * OKi, we've found a matching display mode, remember its number and break
-             */
-            mode = displayModes;
-            break;
-        }
+    success = GL_FALSE;
 
-        /*
-         * Switch to the next display mode, if any
-         */
-        displayModes++;
-    }
+    EnumDisplaySettings( fgDisplay.DisplayName, -1, &devMode ); 
+    devMode.dmFields = 0;
 
-    if ( mode == 0xffffffff )
+    if (fgState.GameModeSize.X!=-1)
     {
-      /* then try without Display Frequency */
-      displayModes = 0;
-
-      /*
-       * Enumerate the available display modes
-       */
-      while( EnumDisplaySettings( NULL, displayModes, &devMode ) == TRUE )
-      {
-        /* then try without Display Frequency */
-
-        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
-         */
-        displayModes++;
-      }
+        devMode.dmPelsWidth  = fgState.GameModeSize.X;
+        devMode.dmFields |= DM_PELSWIDTH;
     }
-
-    /*
-     * Did we find a matching display mode?
-     */
-    if( mode != 0xffffffff )
+    if (fgState.GameModeSize.Y!=-1)
     {
-        int retVal = DISP_CHANGE_SUCCESSFUL;
-
-        /*
-         * Mark the values we want to modify in the display change call
-         */
-        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);
-
-        /*
-         * If it was not a test, remember the current screen settings
-         */
-        if( !haveToTest && success )
-        {
-            fgState.GameModeSize.X  = devMode.dmPelsWidth;
-            fgState.GameModeSize.Y  = devMode.dmPelsHeight;
-            fgState.GameModeDepth   = devMode.dmBitsPerPel;
-            fgState.GameModeRefresh = devMode.dmDisplayFrequency;
-        }
+        devMode.dmPelsHeight  = fgState.GameModeSize.Y;
+        devMode.dmFields |= DM_PELSHEIGHT;
+    }
+    if (fgState.GameModeDepth!=-1)
+    {
+        devMode.dmBitsPerPel  = fgState.GameModeDepth;
+        devMode.dmFields |= DM_BITSPERPEL;
+    }
+    if (fgState.GameModeRefresh!=-1)
+    {
+        devMode.dmDisplayFrequency  = fgState.GameModeRefresh;
+        devMode.dmFields |= DM_DISPLAYFREQUENCY;
     }
 
-    /*
-     * Otherwise we must have failed somewhere
-     */
-    return( success );
+    switch ( ChangeDisplaySettingsEx(fgDisplay.DisplayName, &devMode, NULL, haveToTest ? CDS_TEST : CDS_FULLSCREEN , NULL) )
+    {
+    case DISP_CHANGE_SUCCESSFUL:
+        success = GL_TRUE;
+
+        /* update vars in case if windows switched to proper mode */
+        EnumDisplaySettings( fgDisplay.DisplayName, FREEGLUT_ENUM_CURRENT_SETTINGS, &devMode );
+        fgState.GameModeSize.X  = devMode.dmPelsWidth;        
+        fgState.GameModeSize.Y  = devMode.dmPelsHeight;
+        fgState.GameModeDepth   = devMode.dmBitsPerPel;
+        fgState.GameModeRefresh = devMode.dmDisplayFrequency;
+               break;
+    case DISP_CHANGE_RESTART:
+        fggmstr = "The computer must be restarted for the graphics mode to work.";
+        break;
+    case DISP_CHANGE_BADFLAGS:
+        fggmstr = "An invalid set of flags was passed in.";
+        break;
+    case DISP_CHANGE_BADPARAM:
+        fggmstr = "An invalid parameter was passed in. This can include an invalid flag or combination of flags.";
+        break;
+    case DISP_CHANGE_FAILED:
+        fggmstr = "The display driver failed the specified graphics mode.";
+        break;
+    case DISP_CHANGE_BADMODE:
+        fggmstr = "The graphics mode is not supported.";
+        break;
+    default:
+        fggmstr = "Unknown error in graphics mode???"; /* dunno if it is possible,MSDN does not mention any other error */
+        break;
+    }
 
+    if ( !success )
+        fgWarning(fggmstr); /* I'd rather get info whats going on in my program than wonder about */
+                            /* magic happenings behind my back, its lib for devels at last ;) */
 #endif
+
+    return success;
 }
 
 
@@ -403,7 +493,9 @@ GLboolean fghChangeDisplayMode( GLboolean haveToTest )
  */
 void FGAPIENTRY glutGameModeString( const char* string )
 {
-    int width = 640, height = 480, depth = 16, refresh = 72;
+    int width = -1, height = -1, depth = -1, refresh = -1;
+
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGameModeString" );
 
     /*
      * This one seems a bit easier than glutInitDisplayString. The bad thing
@@ -411,82 +503,63 @@ 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 );
-
-    /*
-     * Hopefully it worked, and if not, we still have the default values
-     */
-    fgState.GameModeSize.X  = width;
-    fgState.GameModeSize.Y  = height;
-    fgState.GameModeDepth   = depth;
-    fgState.GameModeRefresh = refresh;
+                                fgWarning(
+                                    "unable to parse game mode string `%s'",
+                                    string
+                                );
+
+    /* Hopefully it worked, and if not, we still have the default values */
+    if ( width   > 0 ) fgState.GameModeSize.X  = width;
+    if ( height  > 0 ) fgState.GameModeSize.Y  = height;
+    if ( depth   > 0 ) fgState.GameModeDepth   = depth;
+    if ( refresh > 0 ) fgState.GameModeRefresh = refresh;
 }
 
+
+
 /*
  * Enters the game mode
  */
 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 );
-    }
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutEnterGameMode" );
+
+    if( fgStructure.GameModeWindow )
+        fgAddToWindowDestroyList( fgStructure.GameModeWindow );
     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 0;
     }
 
-    /*
-     * Finally, have the game mode window created
-     */
-    fgStructure.GameMode = fgCreateWindow( 
-        NULL, "FREEGLUT", 0, 0, fgState.GameModeSize.X, fgState.GameModeSize.Y, TRUE 
+    fgStructure.GameModeWindow = fgCreateWindow(
+        NULL, "FREEGLUT", GL_TRUE, 0, 0,
+        GL_TRUE, fgState.GameModeSize.X, fgState.GameModeSize.Y,
+        GL_TRUE, GL_FALSE
     );
 
-#if TARGET_HOST_UNIX_X11
+    fgStructure.GameModeWindow->State.Width  = fgState.GameModeSize.X;
+    fgStructure.GameModeWindow->State.Height = fgState.GameModeSize.Y;
+    fgStructure.GameModeWindow->State.NeedToResize = GL_TRUE;
 
-    /* Move the window up to the topleft corner */
-    XMoveWindow(fgDisplay.Display, fgStructure.Window->Window.Handle, 0, 0);
+#if TARGET_HOST_POSIX_X11
 
     /*
      * 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
-    );
+    XSync( fgDisplay.Display, False );
 
     /*
      * Grab the pointer to confine it into the window after the calls to
@@ -497,14 +570,14 @@ int FGAPIENTRY glutEnterGameMode( void )
      * (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);
-    }
+    while( GrabSuccess != XGrabPointer(
+               fgDisplay.Display, fgStructure.GameModeWindow->Window.Handle,
+               TRUE,
+               ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
+               | PointerMotionMask,
+               GrabModeAsync, GrabModeAsync,
+               fgStructure.GameModeWindow->Window.Handle, None, CurrentTime) )
+        usleep( 100 );
 
     /*
      * Change input focus to the new window. This will exit the application
@@ -512,49 +585,57 @@ int FGAPIENTRY glutEnterGameMode( void )
      */
     XSetInputFocus(
         fgDisplay.Display,
-        fgStructure.GameMode->Window.Handle,
+        fgStructure.GameModeWindow->Window.Handle,
         RevertToNone,
         CurrentTime
     );
 
-#   ifdef X_XF86VidModeSetViewPort
+    /* 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
+    );
+
+#   ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
 
-    if (fgDisplay.DisplayModeValid) {
-       int x, y;
-       Window child;
+    if( fgDisplay.DisplayModeValid )
+    {
+        int x, y;
+        Window child;
 
-       /*
-        * Change to viewport to the window topleft edge:
-        */
-       XF86VidModeSetViewPort(fgDisplay.Display, fgDisplay.Screen, 0, 0);
+        /* Change to viewport to the window topleft edge: */
+        if( !XF86VidModeSetViewPort( fgDisplay.Display, fgDisplay.Screen, 0, 0 ) )
+            fgWarning( "XF86VidModeSetViewPort failed" );
 
-       /*
-        * Final window repositioning: It could be avoided using an undecorated
-        * window using override_redirect, but this * would possily require more
-        * changes and investigation.
-        */
+        /*
+         * 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);
+        XTranslateCoordinates(
+            fgDisplay.Display,
+            fgStructure.CurrentWindow->Window.Handle,
+            fgDisplay.RootWindow,
+            0, 0, &x, &y,
+            &child
+        );
+
+        /* Move the decorataions out of the topleft corner of the display */
+        XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
+                     -x, -y);
     }
 
 #endif
 
-    /*
-     * Grab the keyboard, too
-     */
+    /* Grab the keyboard, too */
     XGrabKeyboard(
         fgDisplay.Display,
-        fgStructure.GameMode->Window.Handle,
+        fgStructure.GameModeWindow->Window.Handle,
         FALSE,
         GrabModeAsync, GrabModeAsync,
         CurrentTime
@@ -562,10 +643,7 @@ int FGAPIENTRY glutEnterGameMode( void )
 
 #endif
 
-    /*
-     * Return successfull
-     */
-    return( TRUE );
+    return fgStructure.GameModeWindow->ID;
 }
 
 /*
@@ -573,26 +651,20 @@ int FGAPIENTRY glutEnterGameMode( void )
  */
 void FGAPIENTRY glutLeaveGameMode( void )
 {
-    freeglut_return_if_fail( fgStructure.GameMode != NULL );
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLeaveGameMode" );
 
-    /*
-     * First of all, have the game mode window destroyed
-     */
-    fgAddToWindowDestroyList( fgStructure.GameMode, TRUE );
+    freeglut_return_if_fail( fgStructure.GameModeWindow );
 
-#if TARGET_HOST_UNIX_X11
+    fgAddToWindowDestroyList( fgStructure.GameModeWindow );
+    fgStructure.GameModeWindow = NULL;
+
+#if TARGET_HOST_POSIX_X11
 
-    /*
-     * Ungrab the mouse and keyboard
-     */
     XUngrabPointer( fgDisplay.Display, CurrentTime );
     XUngrabKeyboard( fgDisplay.Display, CurrentTime );
 
 #endif
 
-    /*
-     * Then, have the desktop visual settings restored
-     */
     fghRestoreState();
 }
 
@@ -601,59 +673,37 @@ void FGAPIENTRY glutLeaveGameMode( void )
  */
 int FGAPIENTRY glutGameModeGet( GLenum eWhat )
 {
-    /*
-     * See why are we bothered
-     */
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGameModeGet" );
+
     switch( eWhat )
     {
     case GLUT_GAME_MODE_ACTIVE:
-        /*
-         * Check if the game mode is currently active
-         */
-        return( fgStructure.GameMode != NULL );
+        return !!fgStructure.GameModeWindow;
 
     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.GameModeWindow;
     }
 
-    return( -1 );
+    fgWarning( "Unknown gamemode get: %d", eWhat );
+    return -1;
 }
 
 /*** END OF FILE ***/
-
-
-
-