Removing some build warnings from deprecated functions for VS2008 per e-mail from...
[freeglut] / src / freeglut_init.c
1 /*
2  * freeglut_init.c
3  *
4  * Various freeglut initialization functions.
5  *
6  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7  * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8  * Creation date: Thu Dec 2 1999
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  */
27
28 #include <GL/freeglut.h>
29 #include "freeglut_internal.h"
30
31 #if TARGET_HOST_POSIX_X11
32 #include <limits.h>  /* LONG_MAX */
33 #endif
34
35 /*
36  * TODO BEFORE THE STABLE RELEASE:
37  *
38  *  fgDeinitialize()        -- Win32's OK, X11 needs the OS-specific
39  *                             deinitialization done
40  *  glutInitDisplayString() -- display mode string parsing
41  *
42  * Wouldn't it be cool to use gettext() for error messages? I just love
43  * bash saying  "nie znaleziono pliku" instead of "file not found" :)
44  * Is gettext easily portable?
45  */
46
47 /* -- GLOBAL VARIABLES ----------------------------------------------------- */
48
49 /*
50  * A structure pointed by g_pDisplay holds all information
51  * regarding the display, screen, root window etc.
52  */
53 SFG_Display fgDisplay;
54
55 /*
56  * The settings for the current freeglut session
57  */
58 SFG_State fgState = { { -1, -1, GL_FALSE },  /* Position */
59                       { 300, 300, GL_TRUE }, /* Size */
60                       GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH,  /* DisplayMode */
61                       GL_FALSE,              /* Initialised */
62                       GLUT_TRY_DIRECT_CONTEXT,  /* DirectContext */
63                       GL_FALSE,              /* ForceIconic */
64                       GL_FALSE,              /* UseCurrentContext */
65                       GL_FALSE,              /* GLDebugSwitch */
66                       GL_FALSE,              /* XSyncSwitch */
67                       GLUT_KEY_REPEAT_ON,    /* KeyRepeat */
68                       INVALID_MODIFIERS,     /* Modifiers */
69                       0,                     /* FPSInterval */
70                       0,                     /* SwapCount */
71                       0,                     /* SwapTime */
72                       0,                     /* Time */
73                       { NULL, NULL },         /* Timers */
74                       { NULL, NULL },         /* FreeTimers */
75                       NULL,                   /* IdleCallback */
76                       0,                      /* ActiveMenus */
77                       NULL,                   /* MenuStateCallback */
78                       NULL,                   /* MenuStatusCallback */
79                       { 640, 480, GL_TRUE },  /* GameModeSize */
80                       16,                     /* GameModeDepth */
81                       72,                     /* GameModeRefresh */
82                       GLUT_ACTION_EXIT,       /* ActionOnWindowClose */
83                       GLUT_EXEC_STATE_INIT,   /* ExecState */
84                       NULL,                   /* ProgramName */
85                       GL_FALSE,               /* JoysticksInitialised */
86                       GL_FALSE,               /* InputDevsInitialised */
87                       1,                      /* AuxiliaryBufferNumber */
88                       4,                      /* SampleNumber */
89                       1,                      /* MajorVersion */
90                       0,                      /* MajorVersion */
91                       0                       /* ContextFlags */
92 };
93
94
95 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
96
97 #if TARGET_HOST_POSIX_X11
98
99 /* Return the atom associated with "name". */
100 static Atom fghGetAtom(const char * name)
101 {
102   return XInternAtom(fgDisplay.Display, name, False);
103 }
104
105 /*
106  * Check if "property" is set on "window".  The property's values are returned
107  * through "data".  If the property is set and is of type "type", return the
108  * number of elements in "data".  Return zero otherwise.  In both cases, use
109  * "Xfree()" to free "data".
110  */
111 static int fghGetWindowProperty(Window window,
112                                 Atom property,
113                                 Atom type,
114                                 unsigned char ** data)
115 {
116   /*
117    * Caller always has to use "Xfree()" to free "data", since
118    * "XGetWindowProperty() always allocates one extra byte in prop_return
119    * [i.e. "data"] (even if the property is zero length) [..]".
120    */
121
122   int status;  /*  Returned by "XGetWindowProperty". */
123
124   Atom          type_returned;
125   int           temp_format;             /*  Not used. */
126   unsigned long number_of_elements;
127   unsigned long temp_bytes_after;        /*  Not used. */
128
129
130   status = XGetWindowProperty(fgDisplay.Display,
131                               window,
132                               property,
133                               0,
134                               LONG_MAX,
135                               False,
136                               type,
137                               &type_returned,
138                               &temp_format,
139                               &number_of_elements,
140                               &temp_bytes_after,
141                               data);
142
143   FREEGLUT_INTERNAL_ERROR_EXIT(status == Success,
144                                "XGetWindowProperty failled",
145                                "fghGetWindowProperty");
146
147   if (type_returned != type)
148     {
149       number_of_elements = 0;
150     }
151
152   return number_of_elements;
153 }
154
155 /*  Check if the window manager is NET WM compliant. */
156 static int fghNetWMSupported(void)
157 {
158   Atom wm_check;
159   Window ** window_ptr_1;
160
161   int number_of_windows;
162   int net_wm_supported;
163
164
165   net_wm_supported = 0;
166
167   wm_check = fghGetAtom("_NET_SUPPORTING_WM_CHECK");
168   window_ptr_1 = malloc(sizeof(Window *));
169
170   /*
171    * Check that the window manager has set this property on the root window.
172    * The property must be the ID of a child window.
173    */
174   number_of_windows = fghGetWindowProperty(fgDisplay.RootWindow,
175                                            wm_check,
176                                            XA_WINDOW,
177                                            (unsigned char **) window_ptr_1);
178   if (number_of_windows == 1)
179     {
180       Window ** window_ptr_2;
181
182       window_ptr_2 = malloc(sizeof(Window *));
183
184       /* Check that the window has the same property set to the same value. */
185       number_of_windows = fghGetWindowProperty(**window_ptr_1,
186                                                wm_check,
187                                                XA_WINDOW,
188                                                (unsigned char **) window_ptr_2);
189       if ((number_of_windows == 1) && (**window_ptr_1 == **window_ptr_2))
190       {
191         /* NET WM compliant */
192         net_wm_supported = 1;
193       }
194
195       XFree(*window_ptr_2);
196       free(window_ptr_2);
197     }
198
199         XFree(*window_ptr_1);
200         free(window_ptr_1);
201
202         return net_wm_supported;
203 }
204
205 /*  Check if "hint" is present in "property" for "window". */
206 int fgHintPresent(Window window, Atom property, Atom hint)
207 {
208   Atom ** atoms_ptr;
209   int number_of_atoms;
210   int supported;
211   int i;
212
213   supported = 0;
214
215   atoms_ptr = malloc(sizeof(Atom *));
216   number_of_atoms = fghGetWindowProperty(window,
217                                          property,
218                                          XA_ATOM,
219                                          (unsigned char **) atoms_ptr);
220   for (i = 0; i < number_of_atoms; i++)
221     {
222       if ((*atoms_ptr)[i] == hint)
223       {
224           supported = 1;
225           break;
226       }
227     }
228
229   return supported;
230 }
231
232 #endif /*  TARGET_HOST_POSIX_X11  */
233
234
235 /*
236  * A call to this function should initialize all the display stuff...
237  */
238 static void fghInitialize( const char* displayName )
239 {
240 #if TARGET_HOST_POSIX_X11
241     fgDisplay.Display = XOpenDisplay( displayName );
242
243     if( fgDisplay.Display == NULL )
244         fgError( "failed to open display '%s'", XDisplayName( displayName ) );
245
246     if( !glXQueryExtension( fgDisplay.Display, NULL, NULL ) )
247         fgError( "OpenGL GLX extension not supported by display '%s'",
248             XDisplayName( displayName ) );
249
250     fgDisplay.Screen = DefaultScreen( fgDisplay.Display );
251     fgDisplay.RootWindow = RootWindow(
252         fgDisplay.Display,
253         fgDisplay.Screen
254     );
255
256     fgDisplay.ScreenWidth  = DisplayWidth(
257         fgDisplay.Display,
258         fgDisplay.Screen
259     );
260     fgDisplay.ScreenHeight = DisplayHeight(
261         fgDisplay.Display,
262         fgDisplay.Screen
263     );
264
265     fgDisplay.ScreenWidthMM = DisplayWidthMM(
266         fgDisplay.Display,
267         fgDisplay.Screen
268     );
269     fgDisplay.ScreenHeightMM = DisplayHeightMM(
270         fgDisplay.Display,
271         fgDisplay.Screen
272     );
273
274     fgDisplay.Connection = ConnectionNumber( fgDisplay.Display );
275
276     /* Create the window deletion atom */
277     fgDisplay.DeleteWindow = fghGetAtom("WM_DELETE_WINDOW");
278
279     /* Create the state and full screen atoms */
280     fgDisplay.State           = None;
281     fgDisplay.StateFullScreen = None;
282
283     if (fghNetWMSupported())
284     {
285       const Atom supported = fghGetAtom("_NET_SUPPORTED");
286       const Atom state     = fghGetAtom("_NET_WM_STATE");
287       
288       /* Check if the state hint is supported. */
289       if (fgHintPresent(fgDisplay.RootWindow, supported, state))
290       {
291         const Atom full_screen = fghGetAtom("_NET_WM_STATE_FULLSCREEN");
292         
293         fgDisplay.State = state;
294         
295         /* Check if the window manager supports full screen. */
296         /**  Check "_NET_WM_ALLOWED_ACTIONS" on our window instead? **/
297         if (fgHintPresent(fgDisplay.RootWindow, supported, full_screen))
298         {
299           fgDisplay.StateFullScreen = full_screen;
300         }
301       }
302     }
303
304 #elif TARGET_HOST_MS_WINDOWS
305
306     WNDCLASS wc;
307     ATOM atom;
308
309     /* What we need to do is to initialize the fgDisplay global structure here. */
310     fgDisplay.Instance = GetModuleHandle( NULL );
311
312     atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc );
313
314     if( atom == 0 )
315     {
316         ZeroMemory( &wc, sizeof(WNDCLASS) );
317
318         /*
319          * Each of the windows should have its own device context, and we
320          * want redraw events during Vertical and Horizontal Resizes by
321          * the user.
322          *
323          * XXX Old code had "| CS_DBCLCKS" commented out.  Plans for the
324          * XXX future?  Dead-end idea?
325          */
326         wc.lpfnWndProc    = fgWindowProc;
327         wc.cbClsExtra     = 0;
328         wc.cbWndExtra     = 0;
329         wc.hInstance      = fgDisplay.Instance;
330         wc.hIcon          = LoadIcon( fgDisplay.Instance, _T("GLUT_ICON") );
331
332 #if defined(_WIN32_WCE)
333         wc.style          = CS_HREDRAW | CS_VREDRAW;
334 #else
335         wc.style          = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
336         if (!wc.hIcon)
337           wc.hIcon        = LoadIcon( NULL, IDI_WINLOGO );
338 #endif
339
340         wc.hCursor        = LoadCursor( NULL, IDC_ARROW );
341         wc.hbrBackground  = NULL;
342         wc.lpszMenuName   = NULL;
343         wc.lpszClassName  = _T("FREEGLUT");
344
345         /* Register the window class */
346         atom = RegisterClass( &wc );
347         FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Not Registered", "fghInitialize" );
348     }
349
350     /* The screen dimensions can be obtained via GetSystemMetrics() calls */
351     fgDisplay.ScreenWidth  = GetSystemMetrics( SM_CXSCREEN );
352     fgDisplay.ScreenHeight = GetSystemMetrics( SM_CYSCREEN );
353
354     {
355         HWND desktop = GetDesktopWindow( );
356         HDC  context = GetDC( desktop );
357
358         fgDisplay.ScreenWidthMM  = GetDeviceCaps( context, HORZSIZE );
359         fgDisplay.ScreenHeightMM = GetDeviceCaps( context, VERTSIZE );
360
361         ReleaseDC( desktop, context );
362     }
363
364     /* Set the timer granularity to 1 ms */
365     timeBeginPeriod ( 1 );
366
367 #endif
368
369     fgState.Initialised = GL_TRUE;
370
371     /* InputDevice uses GlutTimerFunc(), so fgState.Initialised must be TRUE */
372     fgInitialiseInputDevices();
373 }
374
375 /*
376  * Perform the freeglut deinitialization...
377  */
378 void fgDeinitialize( void )
379 {
380     SFG_Timer *timer;
381
382     if( !fgState.Initialised )
383     {
384         fgWarning( "fgDeinitialize(): "
385                    "no valid initialization has been performed" );
386         return;
387     }
388
389     /* If there was a menu created, destroy the rendering context */
390     if( fgStructure.MenuContext )
391     {
392 #if TARGET_HOST_POSIX_X11
393         /* Note that the MVisualInfo is not owned by the MenuContext! */
394         glXDestroyContext( fgDisplay.Display, fgStructure.MenuContext->MContext );
395 #endif
396         free( fgStructure.MenuContext );
397         fgStructure.MenuContext = NULL;
398     }
399
400     fgDestroyStructure( );
401
402     while( ( timer = fgState.Timers.First) )
403     {
404         fgListRemove( &fgState.Timers, &timer->Node );
405         free( timer );
406     }
407
408     while( ( timer = fgState.FreeTimers.First) )
409     {
410         fgListRemove( &fgState.FreeTimers, &timer->Node );
411         free( timer );
412     }
413
414 #if !defined(_WIN32_WCE)
415     if ( fgState.JoysticksInitialised )
416         fgJoystickClose( );
417
418     if ( fgState.InputDevsInitialised )
419         fgInputDeviceClose( );
420 #endif /* !defined(_WIN32_WCE) */
421     fgState.JoysticksInitialised = GL_FALSE;
422     fgState.InputDevsInitialised = GL_FALSE;
423
424     fgState.MajorVersion = 1;
425     fgState.MinorVersion = 0;
426     fgState.ContextFlags = 0;
427
428     fgState.Initialised = GL_FALSE;
429
430     fgState.Position.X = -1;
431     fgState.Position.Y = -1;
432     fgState.Position.Use = GL_FALSE;
433
434     fgState.Size.X = 300;
435     fgState.Size.Y = 300;
436     fgState.Size.Use = GL_TRUE;
437
438     fgState.DisplayMode = GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH;
439
440     fgState.DirectContext  = GLUT_TRY_DIRECT_CONTEXT;
441     fgState.ForceIconic         = GL_FALSE;
442     fgState.UseCurrentContext   = GL_FALSE;
443     fgState.GLDebugSwitch       = GL_FALSE;
444     fgState.XSyncSwitch         = GL_FALSE;
445     fgState.ActionOnWindowClose = GLUT_ACTION_EXIT;
446     fgState.ExecState           = GLUT_EXEC_STATE_INIT;
447
448     fgState.KeyRepeat       = GLUT_KEY_REPEAT_ON;
449     fgState.Modifiers       = INVALID_MODIFIERS;
450
451     fgState.GameModeSize.X  = 640;
452     fgState.GameModeSize.Y  = 480;
453     fgState.GameModeDepth   =  16;
454     fgState.GameModeRefresh =  72;
455
456     fgListInit( &fgState.Timers );
457     fgListInit( &fgState.FreeTimers );
458
459     fgState.IdleCallback = NULL;
460     fgState.MenuStateCallback = ( FGCBMenuState )NULL;
461     fgState.MenuStatusCallback = ( FGCBMenuStatus )NULL;
462
463     fgState.SwapCount   = 0;
464     fgState.SwapTime    = 0;
465     fgState.FPSInterval = 0;
466
467     if( fgState.ProgramName )
468     {
469         free( fgState.ProgramName );
470         fgState.ProgramName = NULL;
471     }
472
473 #if TARGET_HOST_POSIX_X11
474
475     /*
476      * Make sure all X-client data we have created will be destroyed on
477      * display closing
478      */
479     XSetCloseDownMode( fgDisplay.Display, DestroyAll );
480
481     /*
482      * Close the display connection, destroying all windows we have
483      * created so far
484      */
485     XCloseDisplay( fgDisplay.Display );
486
487 #elif TARGET_HOST_MS_WINDOWS
488
489     /* Reset the timer granularity */
490     timeEndPeriod ( 1 );
491
492 #endif
493
494     fgState.Initialised = GL_FALSE;
495 }
496
497 /*
498  * Everything inside the following #ifndef is copied from the X sources.
499  */
500
501 #if TARGET_HOST_MS_WINDOWS
502
503 /*
504
505 Copyright 1985, 1986, 1987,1998  The Open Group
506
507 Permission to use, copy, modify, distribute, and sell this software and its
508 documentation for any purpose is hereby granted without fee, provided that
509 the above copyright notice appear in all copies and that both that
510 copyright notice and this permission notice appear in supporting
511 documentation.
512
513 The above copyright notice and this permission notice shall be included
514 in all copies or substantial portions of the Software.
515
516 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
517 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
518 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
519 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
520 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
521 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
522 OTHER DEALINGS IN THE SOFTWARE.
523
524 Except as contained in this notice, the name of The Open Group shall
525 not be used in advertising or otherwise to promote the sale, use or
526 other dealings in this Software without prior written authorization
527 from The Open Group.
528
529 */
530
531 #define NoValue         0x0000
532 #define XValue          0x0001
533 #define YValue          0x0002
534 #define WidthValue      0x0004
535 #define HeightValue     0x0008
536 #define AllValues       0x000F
537 #define XNegative       0x0010
538 #define YNegative       0x0020
539
540 /*
541  *    XParseGeometry parses strings of the form
542  *   "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
543  *   width, height, xoffset, and yoffset are unsigned integers.
544  *   Example:  "=80x24+300-49"
545  *   The equal sign is optional.
546  *   It returns a bitmask that indicates which of the four values
547  *   were actually found in the string.  For each value found,
548  *   the corresponding argument is updated;  for each value
549  *   not found, the corresponding argument is left unchanged.
550  */
551
552 static int
553 ReadInteger(char *string, char **NextString)
554 {
555     register int Result = 0;
556     int Sign = 1;
557
558     if (*string == '+')
559         string++;
560     else if (*string == '-')
561     {
562         string++;
563         Sign = -1;
564     }
565     for (; (*string >= '0') && (*string <= '9'); string++)
566     {
567         Result = (Result * 10) + (*string - '0');
568     }
569     *NextString = string;
570     if (Sign >= 0)
571         return Result;
572     else
573         return -Result;
574 }
575
576 static int XParseGeometry (
577     const char *string,
578     int *x,
579     int *y,
580     unsigned int *width,    /* RETURN */
581     unsigned int *height)    /* RETURN */
582 {
583     int mask = NoValue;
584     register char *strind;
585     unsigned int tempWidth = 0, tempHeight = 0;
586     int tempX = 0, tempY = 0;
587     char *nextCharacter;
588
589     if ( (string == NULL) || (*string == '\0'))
590       return mask;
591     if (*string == '=')
592         string++;  /* ignore possible '=' at beg of geometry spec */
593
594     strind = (char *)string;
595     if (*strind != '+' && *strind != '-' && *strind != 'x') {
596         tempWidth = ReadInteger(strind, &nextCharacter);
597         if (strind == nextCharacter)
598             return 0;
599         strind = nextCharacter;
600         mask |= WidthValue;
601     }
602
603     if (*strind == 'x' || *strind == 'X') {
604         strind++;
605         tempHeight = ReadInteger(strind, &nextCharacter);
606         if (strind == nextCharacter)
607             return 0;
608         strind = nextCharacter;
609         mask |= HeightValue;
610     }
611
612     if ((*strind == '+') || (*strind == '-')) {
613         if (*strind == '-') {
614             strind++;
615             tempX = -ReadInteger(strind, &nextCharacter);
616             if (strind == nextCharacter)
617                 return 0;
618             strind = nextCharacter;
619             mask |= XNegative;
620         }
621         else
622         {
623             strind++;
624             tempX = ReadInteger(strind, &nextCharacter);
625             if (strind == nextCharacter)
626                 return 0;
627             strind = nextCharacter;
628         }
629         mask |= XValue;
630         if ((*strind == '+') || (*strind == '-')) {
631             if (*strind == '-') {
632                 strind++;
633                 tempY = -ReadInteger(strind, &nextCharacter);
634                 if (strind == nextCharacter)
635                     return 0;
636                 strind = nextCharacter;
637                 mask |= YNegative;
638             }
639             else
640             {
641                 strind++;
642                 tempY = ReadInteger(strind, &nextCharacter);
643                 if (strind == nextCharacter)
644                     return 0;
645                 strind = nextCharacter;
646             }
647             mask |= YValue;
648         }
649     }
650
651     /* If strind isn't at the end of the string the it's an invalid
652        geometry specification. */
653
654     if (*strind != '\0') return 0;
655
656     if (mask & XValue)
657         *x = tempX;
658     if (mask & YValue)
659         *y = tempY;
660     if (mask & WidthValue)
661         *width = tempWidth;
662     if (mask & HeightValue)
663         *height = tempHeight;
664     return mask;
665 }
666 #endif
667
668 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
669
670 /*
671  * Perform initialization. This usually happens on the program startup
672  * and restarting after glutMainLoop termination...
673  */
674 void FGAPIENTRY glutInit( int* pargc, char** argv )
675 {
676     char* displayName = NULL;
677     char* geometry = NULL;
678     int i, j, argc = *pargc;
679
680 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) // will return true for VC8 (VC2005) and higher
681     size_t sLen;
682     errno_t err;
683 #endif
684
685     if( fgState.Initialised )
686         fgError( "illegal glutInit() reinitialization attempt" );
687
688     if (pargc && *pargc && argv && *argv && **argv)
689     {
690         fgState.ProgramName = strdup (*argv);
691
692         if( !fgState.ProgramName )
693             fgError ("Could not allocate space for the program's name.");
694     }
695
696     fgCreateStructure( );
697
698     /* Get start time */
699     fgState.Time = fgSystemTime();
700
701     /* check if GLUT_FPS env var is set */
702 #ifndef _WIN32_WCE
703     {
704 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) // will return true for VC8 (VC2005) and higher
705         char* fps = NULL;
706         err = _dupenv_s( &fps, &sLen, "GLUT_FPS" );
707         if (err)
708             fgError("Error getting GLUT_FPS environment variable"); 
709 #else
710         const char *fps = getenv( "GLUT_FPS" );
711 #endif
712         if( fps )
713         {
714             int interval;
715             sscanf( fps, "%d", &interval );
716
717             if( interval <= 0 )
718                 fgState.FPSInterval = 5000;  /* 5000 millisecond default */
719             else
720                 fgState.FPSInterval = interval;
721         }
722 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) // will return true for VC8 (VC2005) and higher
723         free ( fps );  fps = NULL;  /* dupenv_s allocates a string that we must free */
724 #endif
725     }
726
727 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) // will return true for VC8 (VC2005) and higher
728     err = _dupenv_s( &displayName, &sLen, "DISPLAY" );
729     if (err)
730         fgError("Error getting DISPLAY environment variable");
731 #else
732     displayName = getenv( "DISPLAY" );
733 #endif
734
735     for( i = 1; i < argc; i++ )
736     {
737         if( strcmp( argv[ i ], "-display" ) == 0 )
738         {
739             if( ++i >= argc )
740                 fgError( "-display parameter must be followed by display name" );
741
742             displayName = argv[ i ];
743
744             argv[ i - 1 ] = NULL;
745             argv[ i     ] = NULL;
746             ( *pargc ) -= 2;
747         }
748         else if( strcmp( argv[ i ], "-geometry" ) == 0 )
749         {
750             if( ++i >= argc )
751                 fgError( "-geometry parameter must be followed by window "
752                          "geometry settings" );
753
754             geometry = argv[ i ];
755
756             argv[ i - 1 ] = NULL;
757             argv[ i     ] = NULL;
758             ( *pargc ) -= 2;
759         }
760         else if( strcmp( argv[ i ], "-direct" ) == 0)
761         {
762             if( fgState.DirectContext == GLUT_FORCE_INDIRECT_CONTEXT )
763                 fgError( "parameters ambiguity, -direct and -indirect "
764                     "cannot be both specified" );
765
766             fgState.DirectContext = GLUT_FORCE_DIRECT_CONTEXT;
767             argv[ i ] = NULL;
768             ( *pargc )--;
769         }
770         else if( strcmp( argv[ i ], "-indirect" ) == 0 )
771         {
772             if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT )
773                 fgError( "parameters ambiguity, -direct and -indirect "
774                     "cannot be both specified" );
775
776             fgState.DirectContext = GLUT_FORCE_INDIRECT_CONTEXT;
777             argv[ i ] = NULL;
778             (*pargc)--;
779         }
780         else if( strcmp( argv[ i ], "-iconic" ) == 0 )
781         {
782             fgState.ForceIconic = GL_TRUE;
783             argv[ i ] = NULL;
784             ( *pargc )--;
785         }
786         else if( strcmp( argv[ i ], "-gldebug" ) == 0 )
787         {
788             fgState.GLDebugSwitch = GL_TRUE;
789             argv[ i ] = NULL;
790             ( *pargc )--;
791         }
792         else if( strcmp( argv[ i ], "-sync" ) == 0 )
793         {
794             fgState.XSyncSwitch = GL_TRUE;
795             argv[ i ] = NULL;
796             ( *pargc )--;
797         }
798     }
799
800     /* Compact {argv}. */
801     for( i = j = 1; i < *pargc; i++, j++ )
802     {
803         /* Guaranteed to end because there are "*pargc" arguments left */
804         while ( argv[ j ] == NULL )
805             j++;
806         if ( i != j )
807             argv[ i ] = argv[ j ];
808     }
809
810 #endif /* _WIN32_WCE */
811
812     /*
813      * Have the display created now. If there wasn't a "-display"
814      * in the program arguments, we will use the DISPLAY environment
815      * variable for opening the X display (see code above):
816      */
817     fghInitialize( displayName );
818 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) // will return true for VC8 (VC2005) and higher
819     free ( displayName );  displayName = NULL;  /* dupenv_s allocates a string that we must free */
820 #endif
821
822     /*
823      * Geometry parsing deffered until here because we may need the screen
824      * size.
825      */
826
827     if (geometry )
828     {
829         unsigned int parsedWidth, parsedHeight;
830         int mask = XParseGeometry( geometry,
831                                    &fgState.Position.X, &fgState.Position.Y,
832                                    &parsedWidth, &parsedHeight );
833         /* TODO: Check for overflow? */
834         fgState.Size.X = parsedWidth;
835         fgState.Size.Y = parsedHeight;
836
837         if( (mask & (WidthValue|HeightValue)) == (WidthValue|HeightValue) )
838             fgState.Size.Use = GL_TRUE;
839
840         if( mask & XNegative )
841             fgState.Position.X += fgDisplay.ScreenWidth - fgState.Size.X;
842
843         if( mask & YNegative )
844             fgState.Position.Y += fgDisplay.ScreenHeight - fgState.Size.Y;
845
846         if( (mask & (XValue|YValue)) == (XValue|YValue) )
847             fgState.Position.Use = GL_TRUE;
848     }
849 }
850
851 /*
852  * Undoes all the "glutInit" stuff
853  */
854 void FGAPIENTRY glutExit ( void )
855 {
856   fgDeinitialize ();
857 }
858
859 /*
860  * Sets the default initial window position for new windows
861  */
862 void FGAPIENTRY glutInitWindowPosition( int x, int y )
863 {
864     fgState.Position.X = x;
865     fgState.Position.Y = y;
866
867     if( ( x >= 0 ) && ( y >= 0 ) )
868         fgState.Position.Use = GL_TRUE;
869     else
870         fgState.Position.Use = GL_FALSE;
871 }
872
873 /*
874  * Sets the default initial window size for new windows
875  */
876 void FGAPIENTRY glutInitWindowSize( int width, int height )
877 {
878     fgState.Size.X = width;
879     fgState.Size.Y = height;
880
881     if( ( width > 0 ) && ( height > 0 ) )
882         fgState.Size.Use = GL_TRUE;
883     else
884         fgState.Size.Use = GL_FALSE;
885 }
886
887 /*
888  * Sets the default display mode for all new windows
889  */
890 void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode )
891 {
892     /* We will make use of this value when creating a new OpenGL context... */
893     fgState.DisplayMode = displayMode;
894 }
895
896
897 /* -- INIT DISPLAY STRING PARSING ------------------------------------------ */
898
899 static char* Tokens[] =
900 {
901     "alpha", "acca", "acc", "blue", "buffer", "conformant", "depth", "double",
902     "green", "index", "num", "red", "rgba", "rgb", "luminance", "stencil",
903     "single", "stereo", "samples", "slow", "win32pdf", "win32pfd", "xvisual",
904     "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor",
905     "xtruecolor", "xdirectcolor",
906     "xstaticgrey", "xgreyscale", "xstaticcolour", "xpseudocolour",
907     "xtruecolour", "xdirectcolour", "borderless", "aux"
908 };
909 #define NUM_TOKENS             (sizeof(Tokens) / sizeof(*Tokens))
910
911 void FGAPIENTRY glutInitDisplayString( const char* displayMode )
912 {
913     int glut_state_flag = 0 ;
914     /*
915      * Unpack a lot of options from a character string.  The options are
916      * delimited by blanks or tabs.
917      */
918     char *token ;
919 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) // will return true for VC8 (VC2005) and higher
920     char *next_token = NULL;
921 #endif
922     size_t len = strlen ( displayMode );
923     char *buffer = (char *)malloc ( (len+1) * sizeof(char) );
924     memcpy ( buffer, displayMode, len );
925     buffer[len] = '\0';
926
927 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) // will return true for VC8 (VC2005) and higher
928     token = strtok_s ( buffer, " \t", &next_token );
929 #else
930     token = strtok ( buffer, " \t" );
931 #endif
932     while ( token )
933     {
934         /* Process this token */
935         int i ;
936
937         /* Temporary fix:  Ignore any length specifications and at least
938          * process the basic token
939          * TODO:  Fix this permanently
940          */
941         size_t cleanlength = strcspn ( token, "=<>~!" );
942
943         for ( i = 0; i < NUM_TOKENS; i++ )
944         {
945             if ( strncmp ( token, Tokens[i], cleanlength ) == 0 ) break ;
946         }
947
948         switch ( i )
949         {
950         case 0 :  /* "alpha":  Alpha color buffer precision in bits */
951             glut_state_flag |= GLUT_ALPHA ;  /* Somebody fix this for me! */
952             break ;
953
954         case 1 :  /* "acca":  Red, green, blue, and alpha accumulation buffer
955                      precision in bits */
956             break ;
957
958         case 2 :  /* "acc":  Red, green, and blue accumulation buffer precision
959                      in bits with zero bits alpha */
960             glut_state_flag |= GLUT_ACCUM ;  /* Somebody fix this for me! */
961             break ;
962
963         case 3 :  /* "blue":  Blue color buffer precision in bits */
964             break ;
965
966         case 4 :  /* "buffer":  Number of bits in the color index color buffer
967                    */
968             break ;
969
970         case 5 :  /* "conformant":  Boolean indicating if the frame buffer
971                      configuration is conformant or not */
972             break ;
973
974         case 6 : /* "depth":  Number of bits of precsion in the depth buffer */
975             glut_state_flag |= GLUT_DEPTH ;  /* Somebody fix this for me! */
976             break ;
977
978         case 7 :  /* "double":  Boolean indicating if the color buffer is
979                      double buffered */
980             glut_state_flag |= GLUT_DOUBLE ;
981             break ;
982
983         case 8 :  /* "green":  Green color buffer precision in bits */
984             break ;
985
986         case 9 :  /* "index":  Boolean if the color model is color index or not
987                    */
988             glut_state_flag |= GLUT_INDEX ;
989             break ;
990
991         case 10 :  /* "num":  A special capability  name indicating where the
992                       value represents the Nth frame buffer configuration
993                       matching the description string */
994             break ;
995
996         case 11 :  /* "red":  Red color buffer precision in bits */
997             break ;
998
999         case 12 :  /* "rgba":  Number of bits of red, green, blue, and alpha in
1000                       the RGBA color buffer */
1001             glut_state_flag |= GLUT_RGBA ;  /* Somebody fix this for me! */
1002             break ;
1003
1004         case 13 :  /* "rgb":  Number of bits of red, green, and blue in the
1005                       RGBA color buffer with zero bits alpha */
1006             glut_state_flag |= GLUT_RGB ;  /* Somebody fix this for me! */
1007             break ;
1008
1009         case 14 :  /* "luminance":  Number of bits of red in the RGBA and zero
1010                       bits of green, blue (alpha not specified) of color buffer
1011                       precision */
1012             glut_state_flag |= GLUT_LUMINANCE ; /* Somebody fix this for me! */
1013             break ;
1014
1015         case 15 :  /* "stencil":  Number of bits in the stencil buffer */
1016             glut_state_flag |= GLUT_STENCIL;  /* Somebody fix this for me! */
1017             break ;
1018
1019         case 16 :  /* "single":  Boolean indicate the color buffer is single
1020                       buffered */
1021             glut_state_flag |= GLUT_SINGLE ;
1022             break ;
1023
1024         case 17 :  /* "stereo":  Boolean indicating the color buffer supports
1025                       OpenGL-style stereo */
1026             glut_state_flag |= GLUT_STEREO ;
1027             break ;
1028
1029         case 18 :  /* "samples":  Indicates the number of multisamples to use
1030                       based on GLX's SGIS_multisample extension (for
1031                       antialiasing) */
1032             glut_state_flag |= GLUT_MULTISAMPLE ; /*Somebody fix this for me!*/
1033             break ;
1034
1035         case 19 :  /* "slow":  Boolean indicating if the frame buffer
1036                       configuration is slow or not */
1037             break ;
1038
1039         case 20 :  /* "win32pdf": (incorrect spelling but was there before */
1040         case 21 :  /* "win32pfd":  matches the Win32 Pixel Format Descriptor by
1041                       number */
1042 #if TARGET_HOST_MS_WINDOWS
1043 #endif
1044             break ;
1045
1046         case 22 :  /* "xvisual":  matches the X visual ID by number */
1047 #if TARGET_HOST_POSIX_X11
1048 #endif
1049             break ;
1050
1051         case 23 :  /* "xstaticgray": */
1052         case 29 :  /* "xstaticgrey":  boolean indicating if the frame buffer
1053                       configuration's X visual is of type StaticGray */
1054 #if TARGET_HOST_POSIX_X11
1055 #endif
1056             break ;
1057
1058         case 24 :  /* "xgrayscale": */
1059         case 30 :  /* "xgreyscale":  boolean indicating if the frame buffer
1060                       configuration's X visual is of type GrayScale */
1061 #if TARGET_HOST_POSIX_X11
1062 #endif
1063             break ;
1064
1065         case 25 :  /* "xstaticcolor": */
1066         case 31 :  /* "xstaticcolour":  boolean indicating if the frame buffer
1067                       configuration's X visual is of type StaticColor */
1068 #if TARGET_HOST_POSIX_X11
1069 #endif
1070             break ;
1071
1072         case 26 :  /* "xpseudocolor": */
1073         case 32 :  /* "xpseudocolour":  boolean indicating if the frame buffer
1074                       configuration's X visual is of type PseudoColor */
1075 #if TARGET_HOST_POSIX_X11
1076 #endif
1077             break ;
1078
1079         case 27 :  /* "xtruecolor": */
1080         case 33 :  /* "xtruecolour":  boolean indicating if the frame buffer
1081                       configuration's X visual is of type TrueColor */
1082 #if TARGET_HOST_POSIX_X11
1083 #endif
1084             break ;
1085
1086         case 28 :  /* "xdirectcolor": */
1087         case 34 :  /* "xdirectcolour":  boolean indicating if the frame buffer
1088                       configuration's X visual is of type DirectColor */
1089 #if TARGET_HOST_POSIX_X11
1090 #endif
1091             break ;
1092
1093         case 35 :  /* "borderless":  windows should not have borders */
1094 #if TARGET_HOST_POSIX_X11
1095 #endif
1096             break ;
1097
1098         case 36 :  /* "aux":  some number of aux buffers */
1099             glut_state_flag |= GLUT_AUX;
1100             break ;
1101
1102         case 37 :  /* Unrecognized */
1103             fgWarning ( "WARNING - Display string token not recognized:  %s",
1104                         token );
1105             break ;
1106         }
1107
1108 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) // will return true for VC8 (VC2005) and higher
1109         token = strtok_s ( NULL, " \t", &next_token );
1110 #else
1111         token = strtok ( NULL, " \t" );
1112 #endif
1113     }
1114
1115     free ( buffer );
1116
1117     /* We will make use of this value when creating a new OpenGL context... */
1118     fgState.DisplayMode = glut_state_flag;
1119 }
1120
1121 /* -- SETTING OPENGL 3.0 CONTEXT CREATION PARAMETERS ---------------------- */
1122
1123 void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion )
1124 {
1125     /* We will make use of these valuse when creating a new OpenGL context... */
1126     fgState.MajorVersion = majorVersion;
1127     fgState.MinorVersion = minorVersion;
1128 }
1129
1130
1131 void FGAPIENTRY glutInitContextFlags( int flags )
1132 {
1133     /* We will make use of this value when creating a new OpenGL context... */
1134     fgState.ContextFlags = flags;
1135 }
1136
1137 /*** END OF FILE ***/