Fixing multitouch for Windows per e-mail from Florian Echtler dated 5/3/11 10:33 AM
[freeglut] / src / freeglut_gamemode.c
index b30b46f..e590385 100644 (file)
 
 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
 
+#if TARGET_HOST_POSIX_X11
+static int xrandr_resize(int xsz, int ysz, int rate, int just_checking)
+{
+#ifdef HAVE_X11_EXTENSIONS_XRANDR_H
+    int event_base, error_base, ver_major, ver_minor, use_rate;
+    XRRScreenConfiguration *xrr_config = 0;
+    Status result = -1;
+
+    /* must check at runtime for the availability of the extension */
+    if(!XRRQueryExtension(fgDisplay.Display, &event_base, &error_base)) {
+        return -1;
+    }
+
+    XRRQueryVersion(fgDisplay.Display, &ver_major, &ver_minor);
+
+    /* we only heed the rate if we CAN actually use it (Xrandr >= 1.1) and
+     * the user actually cares about it (rate > 0)
+     */
+    use_rate = rate > 0 && ver_major >= 1 && ver_minor >= 1;
+
+    /* this loop is only so that the whole thing will be repeated if someone
+     * else changes video mode between our query the current information and
+     * the attempt to change it.
+     */
+    do {
+        XRRScreenSize *ssizes;
+        short *rates;
+        Rotation rot;
+        int i, ssizes_count, rates_count, curr, res_idx = -1;
+        Time timestamp, cfg_timestamp;
+
+        if(xrr_config) {
+            XRRFreeScreenConfigInfo(xrr_config);
+        }
+
+        if(!(xrr_config = XRRGetScreenInfo(fgDisplay.Display, fgDisplay.RootWindow))) {
+            fgWarning("XRRGetScreenInfo failed");
+            break;
+        }
+        ssizes = XRRConfigSizes(xrr_config, &ssizes_count);
+        curr = XRRConfigCurrentConfiguration(xrr_config, &rot);
+        timestamp = XRRConfigTimes(xrr_config, &cfg_timestamp);
+
+        /* if either of xsz or ysz are unspecified, use the current values */
+        if(xsz <= 0)
+            xsz = fgState.GameModeSize.X = ssizes[curr].width;
+        if(ysz <= 0)
+            ysz = fgState.GameModeSize.Y = ssizes[curr].height;
+
+
+        if(xsz == ssizes[curr].width && ysz == ssizes[curr].height) {
+            /* no need to switch, we're already in the requested resolution */
+            res_idx = curr;
+        } else {
+            for(i=0; i<ssizes_count; i++) {
+                if(ssizes[i].width == xsz && ssizes[i].height == ysz) {
+                    res_idx = i;
+                    break;  /* found it */
+                }
+            }
+        }
+        if(res_idx == -1)
+            break;  /* no matching resolution */
+
+#if RANDR_MAJOR >= 1 && RANDR_MINOR >= 1
+        if(rate <= 0) {
+            fgState.GameModeRefresh = XRRConfigCurrentRate(xrr_config);
+        }
+
+        if(use_rate) {
+            rate = fgState.GameModeRefresh;
+
+            /* for the selected resolution, let's find out if there is
+             * a matching refresh rate available.
+             */
+            rates = XRRConfigRates(xrr_config, res_idx, &rates_count);
+
+            for(i=0; i<rates_count; i++) {
+                if(rates[i] == rate) {
+                    break;
+                }
+            }
+            if(i == rates_count) {
+                break; /* no matching rate */
+            }
+        }
+#endif
+
+        if(just_checking) {
+            result = 0;
+            break;
+        }
+
+#if RANDR_MAJOR >= 1 && RANDR_MINOR >= 1
+        if(use_rate)
+            result = XRRSetScreenConfigAndRate(fgDisplay.Display, xrr_config,
+                    fgDisplay.RootWindow, res_idx, rot, rate, timestamp);
+        else
+#endif
+            result = XRRSetScreenConfig(fgDisplay.Display, xrr_config,
+                    fgDisplay.RootWindow, res_idx, rot, timestamp);
+
+    } while(result == RRSetConfigInvalidTime);
+
+    if(xrr_config) {
+        XRRFreeScreenConfigInfo(xrr_config);
+    }
+
+    if(result == 0) {
+        return 0;
+    }
+
+#endif  /* HAVE_X11_EXTENSIONS_XRANDR_H */
+    return -1;
+}
+#endif  /* TARGET_HOST_POSIX_X11 */
+
 /*
  * Remembers the current visual settings, so that
  * we can change them and restore later...
  */
 static void fghRememberState( void )
 {
-#if TARGET_HOST_UNIX_X11
+#if TARGET_HOST_POSIX_X11
+    int event_base, error_base;
+
+    /*
+     * Remember the current pointer location before going fullscreen
+     * for restoring it later:
+     */
+    Window junk_window;
+    unsigned int junk_mask;
+
+    XQueryPointer(fgDisplay.Display, fgDisplay.RootWindow,
+            &junk_window, &junk_window,
+            &fgDisplay.DisplayPointerX, &fgDisplay.DisplayPointerY,
+            &fgDisplay.DisplayPointerX, &fgDisplay.DisplayPointerY, &junk_mask);
+
+#   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_refresh = -1;
+
+#       if RANDR_MAJOR >= 1 && RANDR_MINOR >= 1
+            if(fgState.GameModeRefresh != -1) {
+                fgDisplay.prev_refresh = XRRConfigCurrentRate(xrr_config);
+            }
+#       endif
+
+            fgDisplay.prev_size_valid = 1;
+
+            XRRFreeScreenConfigInfo(xrr_config);
+        }
+    }
+#   endif
 
     /*
      * 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
@@ -66,21 +226,6 @@ static void fghRememberState( void )
              &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
-        );
-    }
 
     /* Query the current display settings: */
     fgDisplay.DisplayModeValid =
@@ -92,16 +237,10 @@ static void fghRememberState( void )
     );
 
     if( !fgDisplay.DisplayModeValid )
-            fgWarning( "XF86VidModeGetModeLine failed" );
-
-#   else
-    /*
-     * XXX warning fghRememberState: missing XFree86 video mode extensions,
-     * XXX game mode will not change screen resolution when activated
-     */
+        fgWarning( "XF86VidModeGetModeLine failed" );
 #   endif
 
-#elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
+#elif TARGET_HOST_MS_WINDOWS
 
 /*    DEVMODE devMode; */
 
@@ -110,7 +249,7 @@ static void fghRememberState( void )
 /* hack to get around my stupid cross-gcc headers */
 #define FREEGLUT_ENUM_CURRENT_SETTINGS -1
 
-    EnumDisplaySettings( NULL, FREEGLUT_ENUM_CURRENT_SETTINGS,
+    EnumDisplaySettings( fgDisplay.DisplayName, FREEGLUT_ENUM_CURRENT_SETTINGS,
                          &fgDisplay.DisplayMode );
 
     /* Make sure we will be restoring all settings needed */
@@ -125,15 +264,29 @@ static void fghRememberState( void )
  */
 static void fghRestoreState( void )
 {
-#if TARGET_HOST_UNIX_X11
-
-#   ifdef X_XF86VidModeGetAllModeLines
+#if TARGET_HOST_POSIX_X11
     /* Restore the remembered pointer position: */
     XWarpPointer(
         fgDisplay.Display, None, fgDisplay.RootWindow, 0, 0, 0, 0,
         fgDisplay.DisplayPointerX, fgDisplay.DisplayPointerY
     );
 
+
+#   ifdef HAVE_X11_EXTENSIONS_XRANDR_H
+    if(fgDisplay.prev_size_valid) {
+        if(xrandr_resize(fgDisplay.prev_xsz, fgDisplay.prev_ysz, fgDisplay.prev_refresh, 0) != -1) {
+            fgDisplay.prev_size_valid = 0;
+#       ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
+            fgDisplay.DisplayModeValid = 0;
+#       endif
+            return;
+        }
+    }
+#   endif
+
+
+
+#   ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
     /*
      * This highly depends on the XFree86 extensions,
      * not approved as X Consortium standards
@@ -189,29 +342,32 @@ static void fghRestoreState( void )
                  */
                 XFlush( fgDisplay.Display );
 
+                fgDisplay.DisplayModeValid = 0;
+#       ifdef HAVE_X11_EXTENSIONS_XRANDR_H
+                fgDisplay.prev_size_valid = 0;
+#       endif
+
                 break;
             }
         }
         XFree( displayModes );
     }
 
-#   else
-    /*
-     * XXX warning fghRestoreState: missing XFree86 video mode extensions,
-     * XXX game mode will not change screen resolution when activated
-     */
 #   endif
 
-#elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
+#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.
  */
 static GLboolean fghCheckDisplayMode( int width, int height, int depth, int refresh )
 {
@@ -219,32 +375,112 @@ static GLboolean fghCheckDisplayMode( int width, int height, int depth, int refr
     return ( width == fgState.GameModeSize.X ) &&
            ( height == fgState.GameModeSize.Y ) &&
            ( depth == fgState.GameModeDepth ) &&
-           (refresh == fgState.GameModeRefresh );
+           ( 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
  */
 static GLboolean fghChangeDisplayMode( GLboolean haveToTest )
 {
     GLboolean success = GL_FALSE;
-#if TARGET_HOST_UNIX_X11
+#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,
+                fgState.GameModeRefresh, haveToTest) != -1) {
+        return GL_TRUE;
+    }
+#   endif
+
 
     /*
      * 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
+     * This is also used by applications which check modes by calling
      * glutGameModeGet(GLUT_GAME_MODE_POSSIBLE), so allow the check:
      */
     if( haveToTest || fgDisplay.DisplayModeValid )
     {
         XF86VidModeModeInfo** displayModes;
-        int i, ignoreRefreshRate, displayModesCount;
+        int i, displayModesCount;
 
+        /* If we don't have a valid modeline in the display structure, which
+         * can happen if this is called from glutGameModeGet instead of
+         * glutEnterGameMode, then we need to query the current mode, to make
+         * unspecified settings to default to their current values.
+         */
+        if(!fgDisplay.DisplayModeValid) {
+            if(!XF86VidModeGetModeLine(fgDisplay.Display, fgDisplay.Screen,
+                    &fgDisplay.DisplayModeClock, &fgDisplay.DisplayMode)) {
+                return success;
+            }
+        }
+
+        if (fgState.GameModeSize.X == -1)
+        {
+            fgState.GameModeSize.X = fgDisplay.DisplayMode.hdisplay;
+        }
+        if (fgState.GameModeSize.Y == -1)
+        {
+            fgState.GameModeSize.Y = fgDisplay.DisplayMode.vdisplay;
+        }
+        if (fgState.GameModeDepth == -1)
+        {
+            /* can't get color depth from this, nor can we change it, do nothing
+             * TODO: get with XGetVisualInfo()? but then how to set?
+             */
+        }
+        if (fgState.GameModeRefresh == -1)
+        {
+            /* Compute the displays refresh rate, dotclock comes in kHz. */
+            int refresh = ( fgDisplay.DisplayModeClock * 1000 ) /
+                ( fgDisplay.DisplayMode.htotal * fgDisplay.DisplayMode.vtotal );
+
+            fgState.GameModeRefresh = refresh;
+        }
+
+        /* query all possible display modes */
         if( !XF86VidModeGetAllModeLines(
                  fgDisplay.Display,
                  fgDisplay.Screen,
@@ -260,24 +496,11 @@ static GLboolean fghChangeDisplayMode( GLboolean haveToTest )
          * Check every of the modes looking for one that matches our demands,
          * ignoring the refresh rate if no exact match could be found.
          */
-        for( ignoreRefreshRate = 0;
-             !success && ( ignoreRefreshRate <= 1 );
-             ignoreRefreshRate++)
-        {
-            for( i = 0;
-                 !success && ( i < displayModesCount );
-                 i++ )
-            {
-                /* Compute the displays refresh rate, dotclock comes in kHz. */
-                int refresh = ( displayModes[ i ]->dotclock * 1000 ) /
-                              ( displayModes[ i ]->htotal * displayModes[ i ]->vtotal );
-
-                success = fghCheckDisplayMode( displayModes[ i ]->hdisplay,
-                                               displayModes[ i ]->vdisplay,
-                                               fgState.GameModeDepth,
-                                               ( ignoreRefreshRate ? fgState.GameModeRefresh : refresh ) );
-            }
+        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(
@@ -290,81 +513,85 @@ static GLboolean fghChangeDisplayMode( GLboolean haveToTest )
         XFree( displayModes );
     }
 
-#   else
-    /*
-     * XXX warning fghChangeDisplayMode: missing XFree86 video mode extensions,
-     * XXX game mode will not change screen resolution when activated
-     */
 #   endif
 
-#elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
 
-    unsigned int    displayModes = 0, mode = 0xffffffff;
-    /* HDC      desktopDC; */
+#elif TARGET_HOST_MS_WINDOWS
+
     DEVMODE  devMode;
+    char *fggmstr = NULL;
+    char displayMode[300];
 
-    /*
-     * Enumerate the available display modes
-     * Try to get a complete match
-     */
-    while( EnumDisplaySettings( NULL, displayModes, &devMode ) )
+    success = GL_FALSE;
+
+    EnumDisplaySettings( fgDisplay.DisplayName, -1, &devMode ); 
+    devMode.dmFields = 0;
+
+    if (fgState.GameModeSize.X!=-1)
     {
-        /* Does the enumerated display mode match the user's preferences? */
-        if( fghCheckDisplayMode( devMode.dmPelsWidth,  devMode.dmPelsHeight,
-                                 devMode.dmBitsPerPel,
-                                 devMode.dmDisplayFrequency ) )
-        {
-            mode = displayModes;
-            break;
-        }
-        displayModes++;
+        devMode.dmPelsWidth  = fgState.GameModeSize.X;
+        devMode.dmFields |= DM_PELSWIDTH;
     }
-
-    if( mode == 0xffffffff )
+    if (fgState.GameModeSize.Y!=-1)
     {
-        /* then try without Display Frequency */
-        displayModes = 0;
-
-        /* Enumerate the available display modes */
-        while( EnumDisplaySettings( NULL, displayModes, &devMode ) )
-        {
-            /* then try without Display Frequency */
-            if( fghCheckDisplayMode( devMode.dmPelsWidth,
-                                     devMode.dmPelsHeight,
-                                     devMode.dmBitsPerPel,
-                                     fgState.GameModeRefresh ) )
-            {
-                mode = displayModes;
-                break;
-            }
-            displayModes++;
-        }
+        devMode.dmPelsHeight  = fgState.GameModeSize.Y;
+        devMode.dmFields |= DM_PELSHEIGHT;
     }
-
-    /* Did we find a matching display mode? */
-    if( mode != 0xffffffff )
+    if (fgState.GameModeDepth!=-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;
-
-        retVal = ChangeDisplaySettings( &devMode, haveToTest ? CDS_TEST : 0 );
+        devMode.dmBitsPerPel  = fgState.GameModeDepth;
+        devMode.dmFields |= DM_BITSPERPEL;
+    }
+    if (fgState.GameModeRefresh!=-1)
+    {
+        devMode.dmDisplayFrequency  = fgState.GameModeRefresh;
+        devMode.dmFields |= DM_DISPLAYFREQUENCY;
+    }
 
-        /* I don't know if it's really needed, but looks nice: */
-        success = (retVal == DISP_CHANGE_SUCCESSFUL) ||
-            (retVal == DISP_CHANGE_NOTUPDATED);
+    switch ( ChangeDisplaySettingsEx(fgDisplay.DisplayName, &devMode, NULL, haveToTest ? CDS_TEST : CDS_FULLSCREEN , NULL) )
+    {
+    case DISP_CHANGE_SUCCESSFUL:
+        success = GL_TRUE;
 
-        if( !haveToTest && success )
+        if (!haveToTest)
         {
-            fgState.GameModeSize.X  = devMode.dmPelsWidth;
+            /* 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 )
+    {
+        /* 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 ;) */
+        
+        /* append display mode to error to make things more informative */
+        sprintf(displayMode,"%s Problem with requested mode: %ix%i:%i@%i", fggmstr, devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel, devMode.dmDisplayFrequency);
+        fgWarning(displayMode);
+    }
 #endif
 
     return success;
@@ -378,7 +605,7 @@ static 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" );
 
@@ -401,13 +628,18 @@ void FGAPIENTRY glutGameModeString( const char* string )
                                     string
                                 );
 
-    /* Hopefully it worked, and if not, we still have the default values */
+    /* All values not specified are now set to -1, which means those
+     * aspects of the current display mode are not changed in
+     * fghChangeDisplayMode() above.
+     */
     fgState.GameModeSize.X  = width;
     fgState.GameModeSize.Y  = height;
     fgState.GameModeDepth   = depth;
     fgState.GameModeRefresh = refresh;
 }
 
+
+
 /*
  * Enters the game mode
  */
@@ -415,44 +647,34 @@ int FGAPIENTRY glutEnterGameMode( void )
 {
     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutEnterGameMode" );
 
-    if( fgStructure.GameMode )
-        fgAddToWindowDestroyList( fgStructure.GameMode );
+    if( fgStructure.GameModeWindow )
+        fgAddToWindowDestroyList( fgStructure.GameModeWindow );
     else
         fghRememberState( );
 
     if( ! fghChangeDisplayMode( GL_FALSE ) )
     {
         fgWarning( "failed to change screen settings" );
-        return FALSE;
+        return 0;
     }
 
-    fgStructure.GameMode = fgCreateWindow(
-        NULL, "FREEGLUT", 0, 0,
-        fgState.GameModeSize.X, fgState.GameModeSize.Y, GL_TRUE, GL_FALSE
+    fgStructure.GameModeWindow = fgCreateWindow(
+        NULL, "FREEGLUT", GL_TRUE, 0, 0,
+        GL_TRUE, fgState.GameModeSize.X, fgState.GameModeSize.Y,
+        GL_TRUE, GL_FALSE
     );
 
-    fgStructure.GameMode->State.IsGameMode = GL_TRUE;
-
-#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
-    );
-
     /*
      * Grab the pointer to confine it into the window after the calls to
      * XWrapPointer() which ensure that the pointer really enters the window.
@@ -463,26 +685,34 @@ int FGAPIENTRY glutEnterGameMode( void )
      * the application which we have to aviod, so wait until it's viewable:
      */
     while( GrabSuccess != XGrabPointer(
-               fgDisplay.Display, fgStructure.GameMode->Window.Handle,
+               fgDisplay.Display, fgStructure.GameModeWindow->Window.Handle,
                TRUE,
                ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
                | PointerMotionMask,
                GrabModeAsync, GrabModeAsync,
-               fgStructure.GameMode->Window.Handle, None, CurrentTime) )
+               fgStructure.GameModeWindow->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,
+        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 )
     {
@@ -502,14 +732,14 @@ int FGAPIENTRY glutEnterGameMode( void )
         /* Get the current postion of the drawable area on screen */
         XTranslateCoordinates(
             fgDisplay.Display,
-            fgStructure.Window->Window.Handle,
+            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.Window->Window.Handle,
+        XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
                      -x, -y);
     }
 
@@ -518,7 +748,7 @@ int FGAPIENTRY glutEnterGameMode( void )
     /* Grab the keyboard, too */
     XGrabKeyboard(
         fgDisplay.Display,
-        fgStructure.GameMode->Window.Handle,
+        fgStructure.GameModeWindow->Window.Handle,
         FALSE,
         GrabModeAsync, GrabModeAsync,
         CurrentTime
@@ -526,7 +756,7 @@ int FGAPIENTRY glutEnterGameMode( void )
 
 #endif
 
-    return TRUE;
+    return fgStructure.GameModeWindow->ID;
 }
 
 /*
@@ -536,14 +766,12 @@ void FGAPIENTRY glutLeaveGameMode( void )
 {
     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLeaveGameMode" );
 
-    freeglut_return_if_fail( fgStructure.GameMode );
-
-    fgStructure.GameMode->State.IsGameMode = GL_FALSE;
+    freeglut_return_if_fail( fgStructure.GameModeWindow );
 
-    fgAddToWindowDestroyList( fgStructure.GameMode );
-    fgStructure.GameMode = NULL;
+    fgAddToWindowDestroyList( fgStructure.GameModeWindow );
+    fgStructure.GameModeWindow = NULL;
 
-#if TARGET_HOST_UNIX_X11
+#if TARGET_HOST_POSIX_X11
 
     XUngrabPointer( fgDisplay.Display, CurrentTime );
     XUngrabKeyboard( fgDisplay.Display, CurrentTime );
@@ -563,7 +791,7 @@ int FGAPIENTRY glutGameModeGet( GLenum eWhat )
     switch( eWhat )
     {
     case GLUT_GAME_MODE_ACTIVE:
-        return !!fgStructure.GameMode;
+        return !!fgStructure.GameModeWindow;
 
     case GLUT_GAME_MODE_POSSIBLE:
         return fghChangeDisplayMode( GL_TRUE );
@@ -584,7 +812,7 @@ int FGAPIENTRY glutGameModeGet( GLenum eWhat )
         /*
          * This is true if the game mode has been activated successfully..
          */
-        return !!fgStructure.GameMode;
+        return !!fgStructure.GameModeWindow;
     }
 
     fgWarning( "Unknown gamemode get: %d", eWhat );