Adding further comments to the removal of the "atexit" call from the Windows build...
[freeglut] / src / freeglut_init.c
index 5fabb61..5b5771b 100644 (file)
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "../include/GL/freeglut.h"
+#define FREEGLUT_BUILDING_LIB
+#include <GL/freeglut.h>
 #include "freeglut_internal.h"
 
+#if TARGET_HOST_POSIX_X11
+#include <limits.h>  /* LONG_MAX */
+#endif
+
 /*
  * TODO BEFORE THE STABLE RELEASE:
  *
@@ -58,25 +59,21 @@ SFG_Display fgDisplay;
 SFG_State fgState = { { -1, -1, GL_FALSE },  /* Position */
                       { 300, 300, GL_TRUE }, /* Size */
                       GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH,  /* DisplayMode */
-                      GL_FALSE,              /* Initalized */
-                      GL_FALSE,              /* ForceDirectContext */
-                      GL_TRUE,               /* TryDirectContext */
+                      GL_FALSE,              /* Initialised */
+                      GLUT_TRY_DIRECT_CONTEXT,  /* DirectContext */
                       GL_FALSE,              /* ForceIconic */
                       GL_FALSE,              /* UseCurrentContext */
                       GL_FALSE,              /* GLDebugSwitch */
                       GL_FALSE,              /* XSyncSwitch */
-                      GL_TRUE,               /* IgnoreKeyRepeat */
+                      GLUT_KEY_REPEAT_ON,    /* KeyRepeat */
+                      INVALID_MODIFIERS,     /* Modifiers */
                       0,                     /* FPSInterval */
                       0,                     /* SwapCount */
                       0,                     /* SwapTime */
-#if TARGET_HOST_WIN32
-                      { 0, GL_FALSE },       /* Time */
-#else
-                      { { 0, 0 }, GL_FALSE },
-#endif
+                      0,                     /* Time */
                       { NULL, NULL },         /* Timers */
+                      { NULL, NULL },         /* FreeTimers */
                       NULL,                   /* IdleCallback */
-                      GL_FALSE,               /* BuildingAMenu */
                       0,                      /* ActiveMenus */
                       NULL,                   /* MenuStateCallback */
                       NULL,                   /* MenuStatusCallback */
@@ -84,18 +81,169 @@ SFG_State fgState = { { -1, -1, GL_FALSE },  /* Position */
                       16,                     /* GameModeDepth */
                       72,                     /* GameModeRefresh */
                       GLUT_ACTION_EXIT,       /* ActionOnWindowClose */
-                      GLUT_EXEC_STATE_INIT    /* ExecState */
-} ;
+                      GLUT_EXEC_STATE_INIT,   /* ExecState */
+                      NULL,                   /* ProgramName */
+                      GL_FALSE,               /* JoysticksInitialised */
+                      0,                      /* NumActiveJoysticks */
+                      GL_FALSE,               /* InputDevsInitialised */
+                      0,                      /* MouseWheelTicks */
+                      1,                      /* AuxiliaryBufferNumber */
+                      4,                      /* SampleNumber */
+                      1,                      /* MajorVersion */
+                      0,                      /* MinorVersion */
+                      0,                      /* ContextFlags */
+                      0,                      /* ContextProfile */
+                      NULL,                   /* ErrorFunc */
+                      NULL                    /* WarningFunc */
+};
 
 
 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
 
+#if TARGET_HOST_POSIX_X11
+
+/* Return the atom associated with "name". */
+static Atom fghGetAtom(const char * name)
+{
+  return XInternAtom(fgDisplay.Display, name, False);
+}
+
+/*
+ * Check if "property" is set on "window".  The property's values are returned
+ * through "data".  If the property is set and is of type "type", return the
+ * number of elements in "data".  Return zero otherwise.  In both cases, use
+ * "Xfree()" to free "data".
+ */
+static int fghGetWindowProperty(Window window,
+                               Atom property,
+                               Atom type,
+                               unsigned char ** data)
+{
+  /*
+   * Caller always has to use "Xfree()" to free "data", since
+   * "XGetWindowProperty() always allocates one extra byte in prop_return
+   * [i.e. "data"] (even if the property is zero length) [..]".
+   */
+
+  int status;  /*  Returned by "XGetWindowProperty". */
+
+  Atom          type_returned;
+  int           temp_format;             /*  Not used. */
+  unsigned long number_of_elements;
+  unsigned long temp_bytes_after;        /*  Not used. */
+
+
+  status = XGetWindowProperty(fgDisplay.Display,
+                             window,
+                             property,
+                             0,
+                             LONG_MAX,
+                             False,
+                             type,
+                             &type_returned,
+                             &temp_format,
+                             &number_of_elements,
+                             &temp_bytes_after,
+                             data);
+
+  FREEGLUT_INTERNAL_ERROR_EXIT(status == Success,
+                              "XGetWindowProperty failled",
+                              "fghGetWindowProperty");
+
+  if (type_returned != type)
+    {
+      number_of_elements = 0;
+    }
+
+  return number_of_elements;
+}
+
+/*  Check if the window manager is NET WM compliant. */
+static int fghNetWMSupported(void)
+{
+  Atom wm_check;
+  Window ** window_ptr_1;
+
+  int number_of_windows;
+  int net_wm_supported;
+
+
+  net_wm_supported = 0;
+
+  wm_check = fghGetAtom("_NET_SUPPORTING_WM_CHECK");
+  window_ptr_1 = malloc(sizeof(Window *));
+
+  /*
+   * Check that the window manager has set this property on the root window.
+   * The property must be the ID of a child window.
+   */
+  number_of_windows = fghGetWindowProperty(fgDisplay.RootWindow,
+                                           wm_check,
+                                           XA_WINDOW,
+                                           (unsigned char **) window_ptr_1);
+  if (number_of_windows == 1)
+    {
+      Window ** window_ptr_2;
+
+      window_ptr_2 = malloc(sizeof(Window *));
+
+      /* Check that the window has the same property set to the same value. */
+      number_of_windows = fghGetWindowProperty(**window_ptr_1,
+                                               wm_check,
+                                               XA_WINDOW,
+                                               (unsigned char **) window_ptr_2);
+      if ((number_of_windows == 1) && (**window_ptr_1 == **window_ptr_2))
+      {
+        /* NET WM compliant */
+        net_wm_supported = 1;
+      }
+
+      XFree(*window_ptr_2);
+      free(window_ptr_2);
+    }
+
+        XFree(*window_ptr_1);
+        free(window_ptr_1);
+
+        return net_wm_supported;
+}
+
+/*  Check if "hint" is present in "property" for "window". */
+int fgHintPresent(Window window, Atom property, Atom hint)
+{
+  Atom *atoms;
+  int number_of_atoms;
+  int supported;
+  int i;
+
+  supported = 0;
+
+  number_of_atoms = fghGetWindowProperty(window,
+                                        property,
+                                        XA_ATOM,
+                                        (unsigned char **) &atoms);
+  for (i = 0; i < number_of_atoms; i++)
+  {
+      if (atoms[i] == hint)
+      {
+          supported = 1;
+          break;
+      }
+  }
+
+  XFree(atoms);
+  return supported;
+}
+
+#endif /*  TARGET_HOST_POSIX_X11  */
+
+
 /*
  * A call to this function should initialize all the display stuff...
  */
-void fgInitialize( const char* displayName )
+static void fghInitialize( const char* displayName )
 {
-#if TARGET_HOST_UNIX_X11
+#if TARGET_HOST_POSIX_X11
     fgDisplay.Display = XOpenDisplay( displayName );
 
     if( fgDisplay.Display == NULL )
@@ -131,57 +279,81 @@ void fgInitialize( const char* displayName )
 
     fgDisplay.Connection = ConnectionNumber( fgDisplay.Display );
 
-    /*
-     * Create the window deletion atom
-     */
-    fgDisplay.DeleteWindow = XInternAtom(
-        fgDisplay.Display,
-        "WM_DELETE_WINDOW",
-        FALSE
-    );
+    /* Create the window deletion atom */
+    fgDisplay.DeleteWindow = fghGetAtom("WM_DELETE_WINDOW");
+
+    /* Create the state and full screen atoms */
+    fgDisplay.State           = None;
+    fgDisplay.StateFullScreen = None;
+
+    if (fghNetWMSupported())
+    {
+      const Atom supported = fghGetAtom("_NET_SUPPORTED");
+      const Atom state     = fghGetAtom("_NET_WM_STATE");
+      
+      /* Check if the state hint is supported. */
+      if (fgHintPresent(fgDisplay.RootWindow, supported, state))
+      {
+        const Atom full_screen = fghGetAtom("_NET_WM_STATE_FULLSCREEN");
+        
+        fgDisplay.State = state;
+        
+        /* Check if the window manager supports full screen. */
+        /**  Check "_NET_WM_ALLOWED_ACTIONS" on our window instead? **/
+        if (fgHintPresent(fgDisplay.RootWindow, supported, full_screen))
+        {
+          fgDisplay.StateFullScreen = full_screen;
+        }
+      }
+    }
 
-#elif TARGET_HOST_WIN32
+#elif TARGET_HOST_MS_WINDOWS
 
     WNDCLASS wc;
     ATOM atom;
 
-    /*
-     * What we need to do is to initialize the fgDisplay global structure here...
-     */
+    /* What we need to do is to initialize the fgDisplay global structure here. */
     fgDisplay.Instance = GetModuleHandle( NULL );
+    fgDisplay.DisplayName= displayName ? strdup(displayName) : 0 ;
+    atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc );
 
-    atom = GetClassInfo( fgDisplay.Instance, "FREEGLUT", &wc );
     if( atom == 0 )
     {
         ZeroMemory( &wc, sizeof(WNDCLASS) );
 
         /*
-         * Each of the windows should have its own device context...
+         * Each of the windows should have its own device context, and we
+         * want redraw events during Vertical and Horizontal Resizes by
+         * the user.
+         *
+         * XXX Old code had "| CS_DBCLCKS" commented out.  Plans for the
+         * XXX future?  Dead-end idea?
          */
-        wc.style          = CS_OWNDC;
         wc.lpfnWndProc    = fgWindowProc;
         wc.cbClsExtra     = 0;
         wc.cbWndExtra     = 0;
         wc.hInstance      = fgDisplay.Instance;
-        wc.hIcon          = LoadIcon( fgDisplay.Instance, "GLUT_ICON" );
+        wc.hIcon          = LoadIcon( fgDisplay.Instance, _T("GLUT_ICON") );
+
+#if defined(_WIN32_WCE)
+        wc.style          = CS_HREDRAW | CS_VREDRAW;
+#else
+        wc.style          = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
         if (!wc.hIcon)
           wc.hIcon        = LoadIcon( NULL, IDI_WINLOGO );
+#endif
 
         wc.hCursor        = LoadCursor( NULL, IDC_ARROW );
         wc.hbrBackground  = NULL;
         wc.lpszMenuName   = NULL;
-        wc.lpszClassName  = "FREEGLUT";
+        wc.lpszClassName  = _T("FREEGLUT");
 
-        /*
-         * Register the window class
-         */
+        /* Register the window class */
         atom = RegisterClass( &wc );
-        assert( atom );
+        FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Not Registered", "fghInitialize" );
     }
 
-    /*
-     * The screen dimensions can be obtained via GetSystemMetrics() calls
-     */
+    /* The screen dimensions can be obtained via GetSystemMetrics() calls */
     fgDisplay.ScreenWidth  = GetSystemMetrics( SM_CXSCREEN );
     fgDisplay.ScreenHeight = GetSystemMetrics( SM_CYSCREEN );
 
@@ -194,12 +366,42 @@ void fgInitialize( const char* displayName )
 
         ReleaseDC( desktop, context );
     }
+    /* If we have a DisplayName try to use it for metrics */
+    if( fgDisplay.DisplayName )
+    {
+        HDC context = CreateDC(fgDisplay.DisplayName,0,0,0);
+        if( context )
+        {
+           fgDisplay.ScreenWidth  = GetDeviceCaps( context, HORZRES );
+           fgDisplay.ScreenHeight = GetDeviceCaps( context, VERTRES );
+           fgDisplay.ScreenWidthMM  = GetDeviceCaps( context, HORZSIZE );
+           fgDisplay.ScreenHeightMM = GetDeviceCaps( context, VERTSIZE );
+           DeleteDC(context);
+        }
+        else
+           fgWarning("fghInitialize: "
+                     "CreateDC failed, Screen size info may be incorrect\n"
+          "This is quite likely caused by a bad '-display' parameter");
+      
+    }
+    /* Set the timer granularity to 1 ms */
+    timeBeginPeriod ( 1 );
 
 #endif
 
-    fgJoystickInit( 0 );
+    fgState.Initialised = GL_TRUE;
 
-    fgState.Initalized = GL_TRUE;
+    /* Avoid registering atexit callback on Win32 as it results in an access
+     * violation due to calling into a module which has been unloaded.
+     * Any cleanup isn't needed on Windows anyway, the OS takes care of it.c
+     * see: http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx
+     */
+#if ( TARGET_HOST_MS_WINDOWS == 0 )
+    atexit(fgDeinitialize);
+#endif
+
+    /* InputDevice uses GlutTimerFunc(), so fgState.Initialised must be TRUE */
+    fgInitialiseInputDevices();
 }
 
 /*
@@ -209,33 +411,59 @@ void fgDeinitialize( void )
 {
     SFG_Timer *timer;
 
-    if( !fgState.Initalized )
+    if( !fgState.Initialised )
     {
-        fgWarning( "fgDeinitialize(): "
-                   "no valid initialization has been performed" );
         return;
     }
 
-    fgState.Initalized = GL_FALSE;
+       /* If we're in game mode, we want to leave game mode */
+    if( fgStructure.GameModeWindow ) {
+        glutLeaveGameMode();
+    }
 
-    /*
-     * If there was a menu created, destroy the rendering context
-     */
+    /* If there was a menu created, destroy the rendering context */
     if( fgStructure.MenuContext )
     {
+#if TARGET_HOST_POSIX_X11
+        /* Note that the MVisualInfo is not owned by the MenuContext! */
+        glXDestroyContext( fgDisplay.Display, fgStructure.MenuContext->MContext );
+#endif
         free( fgStructure.MenuContext );
         fgStructure.MenuContext = NULL;
     }
 
     fgDestroyStructure( );
 
-    while( timer = ( SFG_Timer * )fgState.Timers.First )
+    while( ( timer = fgState.Timers.First) )
+    {
+        fgListRemove( &fgState.Timers, &timer->Node );
+        free( timer );
+    }
+
+    while( ( timer = fgState.FreeTimers.First) )
     {
-        fgListRemove ( &fgState.Timers, &timer->Node );
+        fgListRemove( &fgState.FreeTimers, &timer->Node );
         free( timer );
     }
 
-    fgJoystickClose( );
+#if !defined(_WIN32_WCE)
+    if ( fgState.JoysticksInitialised )
+        fgJoystickClose( );
+
+    if ( fgState.InputDevsInitialised )
+        fgInputDeviceClose( );
+#endif /* !defined(_WIN32_WCE) */
+    fgState.JoysticksInitialised = GL_FALSE;
+    fgState.InputDevsInitialised = GL_FALSE;
+
+       fgState.MouseWheelTicks = 0;
+
+    fgState.MajorVersion = 1;
+    fgState.MinorVersion = 0;
+    fgState.ContextFlags = 0;
+    fgState.ContextProfile = 0;
+
+    fgState.Initialised = GL_FALSE;
 
     fgState.Position.X = -1;
     fgState.Position.Y = -1;
@@ -247,25 +475,25 @@ void fgDeinitialize( void )
 
     fgState.DisplayMode = GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH;
 
-    fgState.ForceDirectContext  = GL_FALSE;
-    fgState.TryDirectContext    = GL_TRUE;
+    fgState.DirectContext  = GLUT_TRY_DIRECT_CONTEXT;
     fgState.ForceIconic         = GL_FALSE;
     fgState.UseCurrentContext   = GL_FALSE;
     fgState.GLDebugSwitch       = GL_FALSE;
     fgState.XSyncSwitch         = GL_FALSE;
-    fgState.ActionOnWindowClose = GLUT_ACTION_EXIT ;
-    fgState.ExecState           = GLUT_EXEC_STATE_INIT ;
+    fgState.ActionOnWindowClose = GLUT_ACTION_EXIT;
+    fgState.ExecState           = GLUT_EXEC_STATE_INIT;
 
-    fgState.IgnoreKeyRepeat = GL_TRUE;
+    fgState.KeyRepeat       = GLUT_KEY_REPEAT_ON;
+    fgState.Modifiers       = INVALID_MODIFIERS;
 
     fgState.GameModeSize.X  = 640;
     fgState.GameModeSize.Y  = 480;
     fgState.GameModeDepth   =  16;
     fgState.GameModeRefresh =  72;
 
-    fgState.Time.Set = GL_FALSE;
+    fgListInit( &fgState.Timers );
+    fgListInit( &fgState.FreeTimers );
 
-    fgState.Timers.First = fgState.Timers.Last = NULL;
     fgState.IdleCallback = NULL;
     fgState.MenuStateCallback = ( FGCBMenuState )NULL;
     fgState.MenuStatusCallback = ( FGCBMenuStatus )NULL;
@@ -279,9 +507,8 @@ void fgDeinitialize( void )
         free( fgState.ProgramName );
         fgState.ProgramName = NULL;
     }
-    
 
-#if TARGET_HOST_UNIX_X11
+#if TARGET_HOST_POSIX_X11
 
     /*
      * Make sure all X-client data we have created will be destroyed on
@@ -295,9 +522,191 @@ void fgDeinitialize( void )
      */
     XCloseDisplay( fgDisplay.Display );
 
+#elif TARGET_HOST_MS_WINDOWS
+    if( fgDisplay.DisplayName )
+    {
+        free( fgDisplay.DisplayName );
+        fgDisplay.DisplayName = NULL;
+    }
+
+    /* Reset the timer granularity */
+    timeEndPeriod ( 1 );
+
 #endif
+
+    fgState.Initialised = GL_FALSE;
+}
+
+/*
+ * Everything inside the following #ifndef is copied from the X sources.
+ */
+
+#if TARGET_HOST_MS_WINDOWS
+
+/*
+
+Copyright 1985, 1986, 1987,1998  The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+
+#define NoValue         0x0000
+#define XValue          0x0001
+#define YValue          0x0002
+#define WidthValue      0x0004
+#define HeightValue     0x0008
+#define AllValues       0x000F
+#define XNegative       0x0010
+#define YNegative       0x0020
+
+/*
+ *    XParseGeometry parses strings of the form
+ *   "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
+ *   width, height, xoffset, and yoffset are unsigned integers.
+ *   Example:  "=80x24+300-49"
+ *   The equal sign is optional.
+ *   It returns a bitmask that indicates which of the four values
+ *   were actually found in the string.  For each value found,
+ *   the corresponding argument is updated;  for each value
+ *   not found, the corresponding argument is left unchanged.
+ */
+
+static int
+ReadInteger(char *string, char **NextString)
+{
+    register int Result = 0;
+    int Sign = 1;
+
+    if (*string == '+')
+        string++;
+    else if (*string == '-')
+    {
+        string++;
+        Sign = -1;
+    }
+    for (; (*string >= '0') && (*string <= '9'); string++)
+    {
+        Result = (Result * 10) + (*string - '0');
+    }
+    *NextString = string;
+    if (Sign >= 0)
+        return Result;
+    else
+        return -Result;
 }
 
+static int XParseGeometry (
+    const char *string,
+    int *x,
+    int *y,
+    unsigned int *width,    /* RETURN */
+    unsigned int *height)    /* RETURN */
+{
+    int mask = NoValue;
+    register char *strind;
+    unsigned int tempWidth = 0, tempHeight = 0;
+    int tempX = 0, tempY = 0;
+    char *nextCharacter;
+
+    if ( (string == NULL) || (*string == '\0'))
+      return mask;
+    if (*string == '=')
+        string++;  /* ignore possible '=' at beg of geometry spec */
+
+    strind = (char *)string;
+    if (*strind != '+' && *strind != '-' && *strind != 'x') {
+        tempWidth = ReadInteger(strind, &nextCharacter);
+        if (strind == nextCharacter)
+            return 0;
+        strind = nextCharacter;
+        mask |= WidthValue;
+    }
+
+    if (*strind == 'x' || *strind == 'X') {
+        strind++;
+        tempHeight = ReadInteger(strind, &nextCharacter);
+        if (strind == nextCharacter)
+            return 0;
+        strind = nextCharacter;
+        mask |= HeightValue;
+    }
+
+    if ((*strind == '+') || (*strind == '-')) {
+        if (*strind == '-') {
+            strind++;
+            tempX = -ReadInteger(strind, &nextCharacter);
+            if (strind == nextCharacter)
+                return 0;
+            strind = nextCharacter;
+            mask |= XNegative;
+        }
+        else
+        {
+            strind++;
+            tempX = ReadInteger(strind, &nextCharacter);
+            if (strind == nextCharacter)
+                return 0;
+            strind = nextCharacter;
+        }
+        mask |= XValue;
+        if ((*strind == '+') || (*strind == '-')) {
+            if (*strind == '-') {
+                strind++;
+                tempY = -ReadInteger(strind, &nextCharacter);
+                if (strind == nextCharacter)
+                    return 0;
+                strind = nextCharacter;
+                mask |= YNegative;
+            }
+            else
+            {
+                strind++;
+                tempY = ReadInteger(strind, &nextCharacter);
+                if (strind == nextCharacter)
+                    return 0;
+                strind = nextCharacter;
+            }
+            mask |= YValue;
+        }
+    }
+
+    /* If strind isn't at the end of the string the it's an invalid
+       geometry specification. */
+
+    if (*strind != '\0') return 0;
+
+    if (mask & XValue)
+        *x = tempX;
+    if (mask & YValue)
+        *y = tempY;
+    if (mask & WidthValue)
+        *width = tempWidth;
+    if (mask & HeightValue)
+        *height = tempHeight;
+    return mask;
+}
+#endif
 
 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
 
@@ -308,41 +717,43 @@ void fgDeinitialize( void )
 void FGAPIENTRY glutInit( int* pargc, char** argv )
 {
     char* displayName = NULL;
+    char* geometry = NULL;
     int i, j, argc = *pargc;
 
+    if( fgState.Initialised )
+        fgError( "illegal glutInit() reinitialization attempt" );
+
     if (pargc && *pargc && argv && *argv && **argv)
+    {
         fgState.ProgramName = strdup (*argv);
-    else
-        fgState.ProgramName = strdup ("");
-    if( !fgState.ProgramName )
-        fgError ("Could not allocate space for the program's name.");
 
-    if( fgState.Initalized )
-        fgError( "illegal glutInit() reinitialization attemp" );
+        if( !fgState.ProgramName )
+            fgError ("Could not allocate space for the program's name.");
+    }
 
     fgCreateStructure( );
 
-    fgElapsedTime( );
+    /* Get start time */
+    fgState.Time = fgSystemTime();
 
     /* check if GLUT_FPS env var is set */
+#ifndef _WIN32_WCE
     {
         const char *fps = getenv( "GLUT_FPS" );
+
         if( fps )
         {
-            sscanf( fps, "%d", &fgState.FPSInterval );
-            if( fgState.FPSInterval <= 0 )
-                fgState.FPSInterval = 5000;  /* 5000 milliseconds */
+            int interval;
+            sscanf( fps, "%d", &interval );
+
+            if( interval <= 0 )
+                fgState.FPSInterval = 5000;  /* 5000 millisecond default */
+            else
+                fgState.FPSInterval = interval;
         }
     }
 
-#if TARGET_HOST_WIN32
-    if( !getenv( "DISPLAY" ) )
-        displayName = strdup( "" );
-    else
-#endif
-        displayName = strdup( getenv( "DISPLAY" ) );
-    if( !displayName )
-        fgError( "Could not allocate space for display name." );
+    displayName = getenv( "DISPLAY" );
 
     for( i = 1; i < argc; i++ )
     {
@@ -351,12 +762,7 @@ void FGAPIENTRY glutInit( int* pargc, char** argv )
             if( ++i >= argc )
                 fgError( "-display parameter must be followed by display name" );
 
-            if( displayName )
-                free( displayName );
-            displayName = strdup( argv[ i ] );
-            if( !displayName )
-                fgError( "Could not allocate space for display name (%s)",
-                    argv [ i ] );
+            displayName = argv[ i ];
 
             argv[ i - 1 ] = NULL;
             argv[ i     ] = NULL;
@@ -364,36 +770,11 @@ void FGAPIENTRY glutInit( int* pargc, char** argv )
         }
         else if( strcmp( argv[ i ], "-geometry" ) == 0 )
         {
-            int result, x, y;
-            unsigned int w, h;
-
             if( ++i >= argc )
                 fgError( "-geometry parameter must be followed by window "
                          "geometry settings" );
-            result = sscanf( argv[ i ], "%dx%d+%d+%d", &x, &y, &w, &h );
 
-            if( result > 3 )
-                fgState.Size.Y = h;
-            if( result > 2 )
-                fgState.Size.X = w;
-
-            if( result > 1 )
-            {
-                if( y < 0 )
-                    fgState.Position.Y =
-                        fgDisplay.ScreenHeight + y - fgState.Size.Y;
-                else
-                    fgState.Position.Y = y;
-            }
-
-            if( result > 0 )
-            {
-                if( x < 0 )
-                    fgState.Position.X =
-                        fgDisplay.ScreenWidth + x - fgState.Size.X;
-                else
-                    fgState.Position.X = x;
-            }
+            geometry = argv[ i ];
 
             argv[ i - 1 ] = NULL;
             argv[ i     ] = NULL;
@@ -401,21 +782,21 @@ void FGAPIENTRY glutInit( int* pargc, char** argv )
         }
         else if( strcmp( argv[ i ], "-direct" ) == 0)
         {
-            if( ! fgState.TryDirectContext )
+            if( fgState.DirectContext == GLUT_FORCE_INDIRECT_CONTEXT )
                 fgError( "parameters ambiguity, -direct and -indirect "
                     "cannot be both specified" );
 
-            fgState.ForceDirectContext = GL_TRUE;
+            fgState.DirectContext = GLUT_FORCE_DIRECT_CONTEXT;
             argv[ i ] = NULL;
             ( *pargc )--;
         }
         else if( strcmp( argv[ i ], "-indirect" ) == 0 )
         {
-            if( fgState.ForceDirectContext )
+            if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT )
                 fgError( "parameters ambiguity, -direct and -indirect "
                     "cannot be both specified" );
 
-            fgState.TryDirectContext = GL_FALSE;
+            fgState.DirectContext = GLUT_FORCE_INDIRECT_CONTEXT;
             argv[ i ] = NULL;
             (*pargc)--;
         }
@@ -439,45 +820,70 @@ void FGAPIENTRY glutInit( int* pargc, char** argv )
         }
     }
 
-    /*
-     * Compact {argv}.
-     */
-    j = 2 ;
-    for( i = 1; i < *pargc; i++, j++ )
+    /* Compact {argv}. */
+    for( i = j = 1; i < *pargc; i++, j++ )
     {
-        if( argv[ i ] == NULL )
-        {
-            /* Guaranteed to end because there are "*pargc" arguments left */
-            while ( argv[ j ] == NULL )
-                j++;
-            argv[ i ] = argv[ j ] ;
-        }
+        /* Guaranteed to end because there are "*pargc" arguments left */
+        while ( argv[ j ] == NULL )
+            j++;
+        if ( i != j )
+            argv[ i ] = argv[ j ];
     }
 
+#endif /* _WIN32_WCE */
+
     /*
-     * Have the display created now. As I am too lazy to implement
-     * the program arguments parsing, we will have the DISPLAY
-     * environment variable used for opening the X display:
-     *
-     * XXX The above comment is rather unclear.  We have just
-     * XXX completed parsing of the program arguments for GLUT
-     * XXX parameters.  We obviously canNOT parse the application-
-     * XXX specific parameters.  Can someone re-write the above
-     * XXX more clearly?
+     * Have the display created now. If there wasn't a "-display"
+     * in the program arguments, we will use the DISPLAY environment
+     * variable for opening the X display (see code above):
      */
-    fgInitialize( displayName );
+    fghInitialize( displayName );
 
     /*
-     * Check for the minus one settings for both position and size...
+     * Geometry parsing deffered until here because we may need the screen
+     * size.
      */
-    if( fgState.Position.X < 0 || fgState.Position.Y < 0 )
-        fgState.Position.Use = GL_FALSE;
 
-    if( fgState.Size.X < 0 || fgState.Size.Y < 0 )
-        fgState.Size.Use = GL_FALSE;
+    if (geometry )
+    {
+        unsigned int parsedWidth, parsedHeight;
+        int mask = XParseGeometry( geometry,
+                                   &fgState.Position.X, &fgState.Position.Y,
+                                   &parsedWidth, &parsedHeight );
+        /* TODO: Check for overflow? */
+        fgState.Size.X = parsedWidth;
+        fgState.Size.Y = parsedHeight;
 
-    if( displayName )
-        free( displayName );
+        if( (mask & (WidthValue|HeightValue)) == (WidthValue|HeightValue) )
+            fgState.Size.Use = GL_TRUE;
+
+        if( mask & XNegative )
+            fgState.Position.X += fgDisplay.ScreenWidth - fgState.Size.X;
+
+        if( mask & YNegative )
+            fgState.Position.Y += fgDisplay.ScreenHeight - fgState.Size.Y;
+
+        if( (mask & (XValue|YValue)) == (XValue|YValue) )
+            fgState.Position.Use = GL_TRUE;
+    }
+}
+
+#if TARGET_HOST_MS_WINDOWS
+void (__cdecl *__glutExitFunc)( int return_value ) = NULL;
+
+void FGAPIENTRY __glutInitWithExit( int *pargc, char **argv, void (__cdecl *exit_function)(int) )
+{
+  __glutExitFunc = exit_function;
+  glutInit(pargc, argv);
+}
+#endif
+
+/*
+ * Undoes all the "glutInit" stuff
+ */
+void FGAPIENTRY glutExit ( void )
+{
+  fgDeinitialize ();
 }
 
 /*
@@ -485,18 +891,13 @@ void FGAPIENTRY glutInit( int* pargc, char** argv )
  */
 void FGAPIENTRY glutInitWindowPosition( int x, int y )
 {
+    fgState.Position.X = x;
+    fgState.Position.Y = y;
+
     if( ( x >= 0 ) && ( y >= 0 ) )
-    {
-        fgState.Position.X   =       x;
-        fgState.Position.Y   =       y;
         fgState.Position.Use = GL_TRUE;
-    }
     else
-    {
-        fgState.Position.X   =       -1;
-        fgState.Position.Y   =       -1;
         fgState.Position.Use = GL_FALSE;
-    }
 }
 
 /*
@@ -504,18 +905,13 @@ void FGAPIENTRY glutInitWindowPosition( int x, int y )
  */
 void FGAPIENTRY glutInitWindowSize( int width, int height )
 {
+    fgState.Size.X = width;
+    fgState.Size.Y = height;
+
     if( ( width > 0 ) && ( height > 0 ) )
-    {
-        fgState.Size.X   =   width;
-        fgState.Size.Y   =  height;
         fgState.Size.Use = GL_TRUE;
-    }
     else
-    {
-        fgState.Size.X   =       -1;
-        fgState.Size.Y   =       -1;
         fgState.Size.Use = GL_FALSE;
-    }
 }
 
 /*
@@ -523,470 +919,265 @@ void FGAPIENTRY glutInitWindowSize( int width, int height )
  */
 void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode )
 {
-    /*
-     * We will make use of this value when creating a new OpenGL context...
-     */
+    /* We will make use of this value when creating a new OpenGL context... */
     fgState.DisplayMode = displayMode;
 }
 
 
 /* -- INIT DISPLAY STRING PARSING ------------------------------------------ */
 
-#if 0 /* FIXME: CJP */
-/*
- * There is a discrete number of comparison operators we can encounter:
- *
- *     comparison ::= "=" | "!=" | "<" | ">" | "<=" | ">=" | "~"
- */
-#define  FG_NONE           0x0000
-#define  FG_EQUAL          0x0001
-#define  FG_NOT_EQUAL      0x0002
-#define  FG_LESS           0x0003
-#define  FG_MORE           0x0004
-#define  FG_LESS_OR_EQUAL  0x0005
-#define  FG_MORE_OR_EQUAL  0x0006
-#define  FG_CLOSEST        0x0007
-
-/*
- * The caller can feed us with a number of capability tokens:
- *
- * capability ::= "alpha" | "acca" | "acc" | "blue" | "buffer" | "conformant" | "depth" | "double" |
- *                "green" | "index" | "num" | "red" | "rgba" | "rgb" | "luminance" | "stencil" |
- *                "single" | "stereo" | "samples" | "slow" | "win32pdf" | "xvisual" | "xstaticgray" |
- *                "xgrayscale" | "xstaticcolor" | "xpseudocolor" | "xtruecolor" | "xdirectcolor"
- */
-static gchar* g_Tokens[] =
-{
-    "none", "alpha", "acca", "acc", "blue", "buffer", "conformant", "depth", "double", "green",
-    "index", "num", "red", "rgba", "rgb", "luminance", "stencil", "single", "stereo", "samples",
-    "slow", "win32pdf", "xvisual", "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor",
-    "xtruecolor", "xdirectcolor", NULL
-};
-
-/*
- * The structure to hold the parsed display string tokens
- */
-typedef struct tagSFG_Capability SFG_Capability;
-struct tagSFG_Capability
-{
-    gint capability;        /* the capability token enumerator */
-    gint comparison;        /* the comparison operator used    */
-    gint value;             /* the value we're comparing to    */
-};
-
-/*
- * The scanner configuration for the init display string
- */
-static GScannerConfig fgInitDisplayStringScannerConfig =
+static char* Tokens[] =
 {
-    ( " \t\r\n" )               /* cset_skip_characters     */,
-    (
-        G_CSET_a_2_z
-        "_"
-        G_CSET_A_2_Z
-    )                                        /* cset_identifier_first    */,
-    (
-        G_CSET_a_2_z
-        "_0123456789"
-        G_CSET_A_2_Z
-        G_CSET_LATINS
-        G_CSET_LATINC
-        "<>!=~"
-    )                                        /* cset_identifier_nth      */,
-    ( "#\n" )                            /* cpair_comment_single     */,
-    FALSE                                    /* case_sensitive           */,
-    TRUE                                    /* skip_comment_multi       */,
-    TRUE                                    /* skip_comment_single      */,
-    TRUE                                    /* scan_comment_multi       */,
-    TRUE                                    /* scan_identifier          */,
-    FALSE                                    /* scan_identifier_1char    */,
-    FALSE                                    /* scan_identifier_NULL     */,
-    TRUE                                    /* scan_symbols             */,
-    FALSE                                    /* scan_binary              */,
-    TRUE                                    /* scan_octal               */,
-    TRUE                                    /* scan_float               */,
-    TRUE                                    /* scan_hex                 */,
-    FALSE                                    /* scan_hex_dollar          */,
-    TRUE                                    /* scan_string_sq           */,
-    TRUE                                    /* scan_string_dq           */,
-    TRUE                                    /* numbers_2_int            */,
-    FALSE                                    /* int_2_float              */,
-    FALSE                                    /* identifier_2_string      */,
-    TRUE                                    /* char_2_token             */,
-    FALSE                                    /* symbol_2_token           */,
-    FALSE                                    /* scope_0_fallback         */,
+    "alpha", "acca", "acc", "blue", "buffer", "conformant", "depth", "double",
+    "green", "index", "num", "red", "rgba", "rgb", "luminance", "stencil",
+    "single", "stereo", "samples", "slow", "win32pdf", "win32pfd", "xvisual",
+    "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor",
+    "xtruecolor", "xdirectcolor",
+    "xstaticgrey", "xgreyscale", "xstaticcolour", "xpseudocolour",
+    "xtruecolour", "xdirectcolour", "borderless", "aux"
 };
+#define NUM_TOKENS             (sizeof(Tokens) / sizeof(*Tokens))
 
-/*
- * Sets the default display mode for all new windows using a string
- */
-void FGAPIENTRY glutInitDisplayString( char* displayMode )
+void FGAPIENTRY glutInitDisplayString( const char* displayMode )
 {
+    int glut_state_flag = 0 ;
     /*
-     * display_string ::= (switch)
-     * switch         ::= capability [comparison value]
-     * comparison     ::= "=" | "!=" | "<" | ">" | "<=" | ">=" | "~"
-     * capability     ::= "alpha" | "acca" | "acc" | "blue" | "buffer" | "conformant" |
-     *                    "depth" | "double" | "green" | "index" | "num" | "red" | "rgba" |
-     *                    "rgb" | "luminance" | "stencil" | "single" | "stereo" |
-     *                    "samples" | "slow" | "win32pdf" | "xvisual" | "xstaticgray" |
-     *                    "xgrayscale" | "xstaticcolor" | "xpseudocolor" |
-     *                    "xtruecolor" | "xdirectcolor"
-     * value          ::= 0..9 [value]
-     *
-     * The display string grammar. This should be EBNF, but I couldn't find the definitions so, to
-     * clarify: (expr) means 0 or more times the expression, [expr] means 0 or 1 times expr.
-     *
-     * Create a new GLib lexical analyzer to process the display mode string
+     * Unpack a lot of options from a character string.  The options are
+     * delimited by blanks or tabs.
      */
-    GScanner* scanner = g_scanner_new( &fgInitDisplayStringScannerConfig );
-    GList* caps = NULL;
-    gint i;
+    char *token ;
+    size_t len = strlen ( displayMode );
+    char *buffer = (char *)malloc ( (len+1) * sizeof(char) );
+    memcpy ( buffer, displayMode, len );
+    buffer[len] = '\0';
 
-    /*
-     * Fail if the display mode string is empty or the scanner failed to initialize
-     */
-    freeglut_return_if_fail( (scanner != NULL) && (strlen( displayMode ) > 0) );
+    token = strtok ( buffer, " \t" );
 
-    /*
-     * Set the scanner's input name (for debugging)
-     */
-    scanner->input_name = "glutInitDisplayString";
-
-    /*
-     * Start the lexical analysis of the extensions string
-     */
-    g_scanner_input_text( scanner, displayMode, strlen( displayMode ) );
-
-    /*
-     * While there are any more tokens to be checked...
-     */
-    while( !g_scanner_eof( scanner ) )
+    while ( token )
     {
-        /*
-         * Actually we're expecting only string tokens
-         */
-        GTokenType tokenType = g_scanner_get_next_token( scanner );
+        /* Process this token */
+        int i ;
 
-        /*
-         * We are looking for identifiers
+        /* Temporary fix:  Ignore any length specifications and at least
+         * process the basic token
+         * TODO:  Fix this permanently
          */
-        if( tokenType == G_TOKEN_IDENTIFIER )
-        {
-            gchar* capability  = NULL;  /* the capability identifier string (always present) */
-            gint   capID       =    0;  /* the capability identifier value (from g_Tokens)   */
-            gint   comparison  =    0;  /* the comparison operator value, see definitions    */
-            gchar* valueString = NULL;  /* if the previous one is present, this is needed    */
-            gint   value       =    0;  /* the integer value converted using a strtol call   */
-            SFG_Capability* capStruct;  /* the capability description structure              */
-
-            /*
-             * OK. The general rule of thumb that we always should be getting a capability identifier
-             * string (see the grammar description). If it is followed by a comparison identifier, then
-             * there must follow an integer value we're comparing the capability to...
-             *
-             * Have the current token analyzed with that in mind...
-             */
-            for( i=0; i<(gint) strlen( scanner->value.v_identifier ); i++ )
-            {
-                gchar c = scanner->value.v_identifier[ i ];
-
-                if( (c == '=') || (c == '!') || (c == '<') || (c == '>') || (c == '~') )
-                    break;
-            }
-
-            /*
-             * Here we go with the length of the capability identifier string.
-             * In the worst of cases, it is as long as the token identifier.
-             */
-            capability = g_strndup( scanner->value.v_identifier, i );
-
-            /*
-             * OK. Is there a chance for comparison and value identifiers to follow?
-             * Note: checking against i+1 as this handles two cases: single character
-             * comparison operator and first of value's digits, which must always be
-             * there, or the two-character comparison operators.
-             */
-            if( (i + 1) < (gint) strlen( scanner->value.v_identifier ) )
-            {
-                /*
-                 * Yeah, indeed, it is the i-th character to start the identifier, then.
-                 */
-                gchar c1 = scanner->value.v_identifier[ i + 0 ];
-                gchar c2 = scanner->value.v_identifier[ i + 1 ];
-
-                if( (c1 == '=')                ) { i += 1; comparison = FG_EQUAL;         } else
-                if( (c1 == '!') && (c2 == '=') ) { i += 2; comparison = FG_NOT_EQUAL;     } else
-                if( (c1 == '<') && (c2 == '=') ) { i += 2; comparison = FG_LESS_OR_EQUAL; } else
-                if( (c1 == '>') && (c2 == '=') ) { i += 2; comparison = FG_MORE_OR_EQUAL; } else
-                if( (c1 == '<')                ) { i += 1; comparison = FG_LESS;          } else
-                if( (c1 == '>')                ) { i += 1; comparison = FG_MORE;          } else
-                if( (c1 == '~')                ) { i += 1; comparison = FG_CLOSEST;       } else
-                g_warning( "invalid comparison operator in token `%s'", scanner->value.v_identifier );
-            }
+        size_t cleanlength = strcspn ( token, "=<>~!" );
 
-            /*
-             * Grab the value string that must follow the comparison operator...
-             */
-            if( comparison != FG_NONE && i < (gint) strlen( scanner->value.v_identifier ) )
-            {
-                valueString = strdup( scanner->value.v_identifier + i );
-                if (!valueString)
-                    fgError ("Could not allocate an internal string.");
-            }                
-
-            /*
-             * If there was a value string, convert it to integer...
-             */
-            if( comparison != FG_NONE && strlen( valueString ) > 0 )
-                value = strtol( valueString, NULL, 0 );
-
-            /*
-             * Now we need to match the capability string and its ID
-             */
-            for( i=0; g_Tokens[ i ]!=NULL; i++ )
-            {
-                if( strcmp( capability, g_Tokens[ i ] ) == 0 )
-                {
-                    /*
-                     * Looks like we've found the one we were looking for
-                     */
-                    capID = i;
-                    break;
-                }
-            }
-
-            /*
-             * Create a new capability description structure
-             */
-            capStruct = g_new0( SFG_Capability, 1 );
-
-            /*
-             * Fill in the cap's values, as we have parsed it:
-             */
-            capStruct->capability =      capID;
-            capStruct->comparison = comparison;
-            capStruct->value      =      value;
-
-            /*
-             * Add the new capabaility to the caps list
-             */
-            caps = g_list_append( caps, capStruct );
-
-            /*
-             * Clean up the local mess and keep rolling on
-             */
-            g_free( valueString );
-            g_free( capability );
+        for ( i = 0; i < NUM_TOKENS; i++ )
+        {
+            if ( strncmp ( token, Tokens[i], cleanlength ) == 0 ) break ;
         }
-    }
 
-    /*
-     * Now that we have converted the string into somewhat more machine-friendly
-     * form, proceed with matching the frame buffer configuration...
-     *
-     * The caps list could be passed to a function that would try finding the closest 
-     * matching pixel format, visual, frame buffer configuration or whatever. It would 
-     * be good to convert the glutInitDisplayMode() to use the same method.
-     */
-#if 0
-    g_message( "found %i capability preferences", g_list_length( caps ) );
-
-    g_message( "token `%s': cap: %i, com: %i, val: %i",
-        scanner->value.v_identifier,
-        capStruct->capability,
-        capStruct->comparison,
-        capStruct->value
-    );
+        switch ( i )
+        {
+        case 0 :  /* "alpha":  Alpha color buffer precision in bits */
+            glut_state_flag |= GLUT_ALPHA ;  /* Somebody fix this for me! */
+            break ;
+
+        case 1 :  /* "acca":  Red, green, blue, and alpha accumulation buffer
+                     precision in bits */
+            break ;
+
+        case 2 :  /* "acc":  Red, green, and blue accumulation buffer precision
+                     in bits with zero bits alpha */
+            glut_state_flag |= GLUT_ACCUM ;  /* Somebody fix this for me! */
+            break ;
+
+        case 3 :  /* "blue":  Blue color buffer precision in bits */
+            break ;
+
+        case 4 :  /* "buffer":  Number of bits in the color index color buffer
+                   */
+            break ;
+
+        case 5 :  /* "conformant":  Boolean indicating if the frame buffer
+                     configuration is conformant or not */
+            break ;
+
+        case 6 : /* "depth":  Number of bits of precsion in the depth buffer */
+            glut_state_flag |= GLUT_DEPTH ;  /* Somebody fix this for me! */
+            break ;
+
+        case 7 :  /* "double":  Boolean indicating if the color buffer is
+                     double buffered */
+            glut_state_flag |= GLUT_DOUBLE ;
+            break ;
+
+        case 8 :  /* "green":  Green color buffer precision in bits */
+            break ;
+
+        case 9 :  /* "index":  Boolean if the color model is color index or not
+                   */
+            glut_state_flag |= GLUT_INDEX ;
+            break ;
+
+        case 10 :  /* "num":  A special capability  name indicating where the
+                      value represents the Nth frame buffer configuration
+                      matching the description string */
+            break ;
+
+        case 11 :  /* "red":  Red color buffer precision in bits */
+            break ;
+
+        case 12 :  /* "rgba":  Number of bits of red, green, blue, and alpha in
+                      the RGBA color buffer */
+            glut_state_flag |= GLUT_RGBA ;  /* Somebody fix this for me! */
+            break ;
+
+        case 13 :  /* "rgb":  Number of bits of red, green, and blue in the
+                      RGBA color buffer with zero bits alpha */
+            glut_state_flag |= GLUT_RGB ;  /* Somebody fix this for me! */
+            break ;
+
+        case 14 :  /* "luminance":  Number of bits of red in the RGBA and zero
+                      bits of green, blue (alpha not specified) of color buffer
+                      precision */
+            glut_state_flag |= GLUT_LUMINANCE ; /* Somebody fix this for me! */
+            break ;
+
+        case 15 :  /* "stencil":  Number of bits in the stencil buffer */
+            glut_state_flag |= GLUT_STENCIL;  /* Somebody fix this for me! */
+            break ;
+
+        case 16 :  /* "single":  Boolean indicate the color buffer is single
+                      buffered */
+            glut_state_flag |= GLUT_SINGLE ;
+            break ;
+
+        case 17 :  /* "stereo":  Boolean indicating the color buffer supports
+                      OpenGL-style stereo */
+            glut_state_flag |= GLUT_STEREO ;
+            break ;
+
+        case 18 :  /* "samples":  Indicates the number of multisamples to use
+                      based on GLX's SGIS_multisample extension (for
+                      antialiasing) */
+            glut_state_flag |= GLUT_MULTISAMPLE ; /*Somebody fix this for me!*/
+            break ;
+
+        case 19 :  /* "slow":  Boolean indicating if the frame buffer
+                      configuration is slow or not */
+            break ;
+
+        case 20 :  /* "win32pdf": (incorrect spelling but was there before */
+        case 21 :  /* "win32pfd":  matches the Win32 Pixel Format Descriptor by
+                      number */
+#if TARGET_HOST_MS_WINDOWS
 #endif
+            break ;
 
-    /*
-     * Free the capabilities we have parsed
-     */
-    for( i=0; i<(gint) g_list_length( caps ); i++ )
-        g_free( g_list_nth( caps, i )->data );
-
-    /*
-     * Destroy the capabilities list itself
-     */
-    g_list_free( caps );
-
-    /*
-     * Free the lexical scanner now...
-     */
-    g_scanner_destroy( scanner );
-}
+        case 22 :  /* "xvisual":  matches the X visual ID by number */
+#if TARGET_HOST_POSIX_X11
 #endif
+            break ;
 
-#define NUM_TOKENS             28
-static char* Tokens[] =
-{
-    "alpha", "acca", "acc", "blue", "buffer", "conformant", "depth", "double", "green",
-    "index", "num", "red", "rgba", "rgb", "luminance", "stencil", "single", "stereo", "samples",
-    "slow", "win32pdf", "xvisual", "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor",
-    "xtruecolor", "xdirectcolor"
-};
-
-static int TokenLengths[] =
-{
-         5,      4,     3,      4,        6,           10,       5,        6,       5,
-         5,     3,     3,      4,     3,           9,         7,        6,        6,         7,
-        4,          8,         7,            11,           10,             12,             12,
-             10,             12
-};
-
-void FGAPIENTRY glutInitDisplayString( const char* displayMode )
-{
-  int glut_state_flag = 0 ;
-  /*
-   * Unpack a lot of options from a character string.  The options are delimited by blanks or tabs.
-   */
-  char *token ;
-  int len = strlen ( displayMode ) ;
-  char *buffer = (char *)malloc ( (len+1) * sizeof(char) ) ;
-  memcpy ( buffer, displayMode, len ) ;
-  buffer[len] = '\0' ;
-
-  token = strtok ( buffer, " \t" ) ;
-  while ( token )
-  {
-    /*
-     * Process this token
-     */
-    int i ;
-    for ( i = 0; i < NUM_TOKENS; i++ )
-    {
-      if ( strncmp ( token, Tokens[i], TokenLengths[i] ) == 0 ) break ;
-    }
-
-    switch ( i )
-    {
-    case 0 :  /* "alpha":  Alpha color buffer precision in bits */
-      glut_state_flag |= GLUT_ALPHA ;  /* Somebody fix this for me! */
-      break ;
-
-    case 1 :  /* "acca":  Red, green, blue, and alpha accumulation buffer precision in bits */
-      break ;
-
-    case 2 :  /* "acc":  Red, green, and blue accumulation buffer precision in bits with zero bits alpha */
-      glut_state_flag |= GLUT_ACCUM ;  /* Somebody fix this for me! */
-      break ;
-
-    case 3 :  /* "blue":  Blue color buffer precision in bits */
-      break ;
-
-    case 4 :  /* "buffer":  Number of bits in the color index color buffer */
-      break ;
-
-    case 5 :  /* "conformant":  Boolean indicating if the frame buffer configuration is conformant or not */
-      break ;
-
-    case 6 :  /* "depth":  Number of bits of precsion in the depth buffer */
-      glut_state_flag |= GLUT_DEPTH ;  /* Somebody fix this for me! */
-      break ;
-
-    case 7 :  /* "double":  Boolean indicating if the color buffer is double buffered */
-      glut_state_flag |= GLUT_DOUBLE ;
-      break ;
-
-    case 8 :  /* "green":  Green color buffer precision in bits */
-      break ;
-
-    case 9 :  /* "index":  Boolean if the color model is color index or not */
-      glut_state_flag |= GLUT_INDEX ;
-      break ;
-
-    case 10 :  /* "num":  A special capability  name indicating where the value represents the Nth frame buffer configuration matching the description string */
-      break ;
-
-    case 11 :  /* "red":  Red color buffer precision in bits */
-      break ;
-
-    case 12 :  /* "rgba":  Number of bits of red, green, blue, and alpha in the RGBA color buffer */
-      glut_state_flag |= GLUT_RGBA ;  /* Somebody fix this for me! */
-      break ;
-
-    case 13 :  /* "rgb":  Number of bits of red, green, and blue in the RGBA color buffer with zero bits alpha */
-      glut_state_flag |= GLUT_RGB ;  /* Somebody fix this for me! */
-      break ;
-
-    case 14 :  /* "luminance":  Number of bits of red in the RGBA and zero bits of green, blue (alpha not specified) of color buffer precision */
-      glut_state_flag |= GLUT_LUMINANCE ;  /* Somebody fix this for me! */
-      break ;
-
-    case 15 :  /* "stencil":  Number of bits in the stencil buffer */
-      glut_state_flag |= GLUT_STENCIL ;  /* Somebody fix this for me! */
-      break ;
-
-    case 16 :  /* "single":  Boolean indicate the color buffer is single buffered */
-      glut_state_flag |= GLUT_SINGLE ;
-      break ;
-
-    case 17 :  /* "stereo":  Boolean indicating the color buffer supports OpenGL-style stereo */
-      glut_state_flag |= GLUT_STEREO ;
-      break ;
-
-    case 18 :  /* "samples":  Indicates the number of multisamples to use based on GLX's SGIS_multisample extension (for antialiasing) */
-      glut_state_flag |= GLUT_MULTISAMPLE ;  /* Somebody fix this for me! */
-      break ;
-
-    case 19 :  /* "slow":  Boolean indicating if the frame buffer configuration is slow or not */
-      break ;
-
-    case 20 :  /* "win32pdf":  matches the Win32 Pixel Format Descriptor by number */
-#if TARGET_HOST_WIN32
+        case 23 :  /* "xstaticgray": */
+        case 29 :  /* "xstaticgrey":  boolean indicating if the frame buffer
+                      configuration's X visual is of type StaticGray */
+#if TARGET_HOST_POSIX_X11
 #endif
-      break ;
+            break ;
 
-    case 21 :  /* "xvisual":  matches the X visual ID by number */
-#if TARGET_HOST_UNIX_X11
+        case 24 :  /* "xgrayscale": */
+        case 30 :  /* "xgreyscale":  boolean indicating if the frame buffer
+                      configuration's X visual is of type GrayScale */
+#if TARGET_HOST_POSIX_X11
 #endif
-      break ;
+            break ;
 
-    case 22 :  /* "xstaticgray":  boolean indicating if the frame buffer configuration's X visual is of type StaticGray */
-#if TARGET_HOST_UNIX_X11
+        case 25 :  /* "xstaticcolor": */
+        case 31 :  /* "xstaticcolour":  boolean indicating if the frame buffer
+                      configuration's X visual is of type StaticColor */
+#if TARGET_HOST_POSIX_X11
 #endif
-      break ;
+            break ;
 
-    case 23 :  /* "xgrayscale":  boolean indicating if the frame buffer configuration's X visual is of type GrayScale */
-#if TARGET_HOST_UNIX_X11
+        case 26 :  /* "xpseudocolor": */
+        case 32 :  /* "xpseudocolour":  boolean indicating if the frame buffer
+                      configuration's X visual is of type PseudoColor */
+#if TARGET_HOST_POSIX_X11
 #endif
-      break ;
+            break ;
 
-    case 24 :  /* "xstaticcolor":  boolean indicating if the frame buffer configuration's X visual is of type StaticColor */
-#if TARGET_HOST_UNIX_X11
+        case 27 :  /* "xtruecolor": */
+        case 33 :  /* "xtruecolour":  boolean indicating if the frame buffer
+                      configuration's X visual is of type TrueColor */
+#if TARGET_HOST_POSIX_X11
 #endif
-      break ;
+            break ;
 
-    case 25 :  /* "xpseudocolor":  boolean indicating if the frame buffer configuration's X visual is of type PseudoColor */
-#if TARGET_HOST_UNIX_X11
+        case 28 :  /* "xdirectcolor": */
+        case 34 :  /* "xdirectcolour":  boolean indicating if the frame buffer
+                      configuration's X visual is of type DirectColor */
+#if TARGET_HOST_POSIX_X11
 #endif
-      break ;
+            break ;
 
-    case 26 :  /* "xtruecolor":  boolean indicating if the frame buffer configuration's X visual is of type TrueColor */
-#if TARGET_HOST_UNIX_X11
+        case 35 :  /* "borderless":  windows should not have borders */
+#if TARGET_HOST_POSIX_X11
 #endif
-      break ;
+            break ;
 
-    case 27 :  /* "xdirectcolor":  boolean indicating if the frame buffer configuration's X visual is of type DirectColor */
-#if TARGET_HOST_UNIX_X11
-#endif
-      break ;
+        case 36 :  /* "aux":  some number of aux buffers */
+            glut_state_flag |= GLUT_AUX;
+            break ;
+
+        case 37 :  /* Unrecognized */
+            fgWarning ( "WARNING - Display string token not recognized:  %s",
+                        token );
+            break ;
+        }
 
-    case 28 :  /* Unrecognized */
-      printf ( "WARNING - Display string token not recognized:  %s\n", token ) ;
-      break ;
+        token = strtok ( NULL, " \t" );
     }
 
-    token = strtok ( NULL, " \t" ) ;
-  }
+    free ( buffer );
 
-  free ( buffer ) ;
+    /* We will make use of this value when creating a new OpenGL context... */
+    fgState.DisplayMode = glut_state_flag;
+}
 
-  /*
-   * We will make use of this value when creating a new OpenGL context...
-   */
-  fgState.DisplayMode = glut_state_flag;
+/* -- SETTING OPENGL 3.0 CONTEXT CREATION PARAMETERS ---------------------- */
+
+void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion )
+{
+    /* We will make use of these valuse when creating a new OpenGL context... */
+    fgState.MajorVersion = majorVersion;
+    fgState.MinorVersion = minorVersion;
+}
+
+
+void FGAPIENTRY glutInitContextFlags( int flags )
+{
+    /* We will make use of this value when creating a new OpenGL context... */
+    fgState.ContextFlags = flags;
+}
+
+void FGAPIENTRY glutInitContextProfile( int profile )
+{
+    /* We will make use of this value when creating a new OpenGL context... */
+    fgState.ContextProfile = profile;
+}
+
+/* -------------- User Defined Error/Warning Handler Support -------------- */
+
+/*
+ * Sets the user error handler (note the use of va_list for the args to the fmt)
+ */
+void FGAPIENTRY glutInitErrorFunc( void (* vfgError) ( const char *fmt, va_list ap ) )
+{
+    /* This allows user programs to handle freeglut errors */
+    fgState.ErrorFunc = vfgError;
+}
+
+/*
+ * Sets the user warning handler (note the use of va_list for the args to the fmt)
+ */
+void FGAPIENTRY glutInitWarningFunc( void (* vfgWarning) ( const char *fmt, va_list ap ) )
+{
+    /* This allows user programs to handle freeglut warnings */
+    fgState.WarningFunc = vfgWarning;
 }
 
 /*** END OF FILE ***/