01dabc788242936791f2b513015ec6037c1a4b4e
[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     /* will return true for VC8 (VC2005) and higher */
681 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 )
682     size_t sLen;
683     errno_t err;
684 #endif
685
686     if( fgState.Initialised )
687         fgError( "illegal glutInit() reinitialization attempt" );
688
689     if (pargc && *pargc && argv && *argv && **argv)
690     {
691         fgState.ProgramName = strdup (*argv);
692
693         if( !fgState.ProgramName )
694             fgError ("Could not allocate space for the program's name.");
695     }
696
697     fgCreateStructure( );
698
699     /* Get start time */
700     fgState.Time = fgSystemTime();
701
702     /* check if GLUT_FPS env var is set */
703 #ifndef _WIN32_WCE
704     {
705     /* will return true for VC8 (VC2005) and higher */
706 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 )
707         char* fps = NULL;
708         err = _dupenv_s( &fps, &sLen, "GLUT_FPS" );
709         if (err)
710             fgError("Error getting GLUT_FPS environment variable"); 
711 #else
712         const char *fps = getenv( "GLUT_FPS" );
713 #endif
714         if( fps )
715         {
716             int interval;
717             sscanf( fps, "%d", &interval );
718
719             if( interval <= 0 )
720                 fgState.FPSInterval = 5000;  /* 5000 millisecond default */
721             else
722                 fgState.FPSInterval = interval;
723         }
724     /* will return true for VC8 (VC2005) and higher */
725 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 )
726         free ( fps );  fps = NULL;  /* dupenv_s allocates a string that we must free */
727 #endif
728     }
729
730     /* will return true for VC8 (VC2005) and higher */
731 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 )
732     err = _dupenv_s( &displayName, &sLen, "DISPLAY" );
733     if (err)
734         fgError("Error getting DISPLAY environment variable");
735 #else
736     displayName = getenv( "DISPLAY" );
737 #endif
738
739     for( i = 1; i < argc; i++ )
740     {
741         if( strcmp( argv[ i ], "-display" ) == 0 )
742         {
743             if( ++i >= argc )
744                 fgError( "-display parameter must be followed by display name" );
745
746             displayName = argv[ i ];
747
748             argv[ i - 1 ] = NULL;
749             argv[ i     ] = NULL;
750             ( *pargc ) -= 2;
751         }
752         else if( strcmp( argv[ i ], "-geometry" ) == 0 )
753         {
754             if( ++i >= argc )
755                 fgError( "-geometry parameter must be followed by window "
756                          "geometry settings" );
757
758             geometry = argv[ i ];
759
760             argv[ i - 1 ] = NULL;
761             argv[ i     ] = NULL;
762             ( *pargc ) -= 2;
763         }
764         else if( strcmp( argv[ i ], "-direct" ) == 0)
765         {
766             if( fgState.DirectContext == GLUT_FORCE_INDIRECT_CONTEXT )
767                 fgError( "parameters ambiguity, -direct and -indirect "
768                     "cannot be both specified" );
769
770             fgState.DirectContext = GLUT_FORCE_DIRECT_CONTEXT;
771             argv[ i ] = NULL;
772             ( *pargc )--;
773         }
774         else if( strcmp( argv[ i ], "-indirect" ) == 0 )
775         {
776             if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT )
777                 fgError( "parameters ambiguity, -direct and -indirect "
778                     "cannot be both specified" );
779
780             fgState.DirectContext = GLUT_FORCE_INDIRECT_CONTEXT;
781             argv[ i ] = NULL;
782             (*pargc)--;
783         }
784         else if( strcmp( argv[ i ], "-iconic" ) == 0 )
785         {
786             fgState.ForceIconic = GL_TRUE;
787             argv[ i ] = NULL;
788             ( *pargc )--;
789         }
790         else if( strcmp( argv[ i ], "-gldebug" ) == 0 )
791         {
792             fgState.GLDebugSwitch = GL_TRUE;
793             argv[ i ] = NULL;
794             ( *pargc )--;
795         }
796         else if( strcmp( argv[ i ], "-sync" ) == 0 )
797         {
798             fgState.XSyncSwitch = GL_TRUE;
799             argv[ i ] = NULL;
800             ( *pargc )--;
801         }
802     }
803
804     /* Compact {argv}. */
805     for( i = j = 1; i < *pargc; i++, j++ )
806     {
807         /* Guaranteed to end because there are "*pargc" arguments left */
808         while ( argv[ j ] == NULL )
809             j++;
810         if ( i != j )
811             argv[ i ] = argv[ j ];
812     }
813
814 #endif /* _WIN32_WCE */
815
816     /*
817      * Have the display created now. If there wasn't a "-display"
818      * in the program arguments, we will use the DISPLAY environment
819      * variable for opening the X display (see code above):
820      */
821     fghInitialize( displayName );
822     /* will return true for VC8 (VC2005) and higher */
823 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 )
824     free ( displayName );  displayName = NULL;  /* dupenv_s allocates a string that we must free */
825 #endif
826
827     /*
828      * Geometry parsing deffered until here because we may need the screen
829      * size.
830      */
831
832     if (geometry )
833     {
834         unsigned int parsedWidth, parsedHeight;
835         int mask = XParseGeometry( geometry,
836                                    &fgState.Position.X, &fgState.Position.Y,
837                                    &parsedWidth, &parsedHeight );
838         /* TODO: Check for overflow? */
839         fgState.Size.X = parsedWidth;
840         fgState.Size.Y = parsedHeight;
841
842         if( (mask & (WidthValue|HeightValue)) == (WidthValue|HeightValue) )
843             fgState.Size.Use = GL_TRUE;
844
845         if( mask & XNegative )
846             fgState.Position.X += fgDisplay.ScreenWidth - fgState.Size.X;
847
848         if( mask & YNegative )
849             fgState.Position.Y += fgDisplay.ScreenHeight - fgState.Size.Y;
850
851         if( (mask & (XValue|YValue)) == (XValue|YValue) )
852             fgState.Position.Use = GL_TRUE;
853     }
854 }
855
856 /*
857  * Undoes all the "glutInit" stuff
858  */
859 void FGAPIENTRY glutExit ( void )
860 {
861   fgDeinitialize ();
862 }
863
864 /*
865  * Sets the default initial window position for new windows
866  */
867 void FGAPIENTRY glutInitWindowPosition( int x, int y )
868 {
869     fgState.Position.X = x;
870     fgState.Position.Y = y;
871
872     if( ( x >= 0 ) && ( y >= 0 ) )
873         fgState.Position.Use = GL_TRUE;
874     else
875         fgState.Position.Use = GL_FALSE;
876 }
877
878 /*
879  * Sets the default initial window size for new windows
880  */
881 void FGAPIENTRY glutInitWindowSize( int width, int height )
882 {
883     fgState.Size.X = width;
884     fgState.Size.Y = height;
885
886     if( ( width > 0 ) && ( height > 0 ) )
887         fgState.Size.Use = GL_TRUE;
888     else
889         fgState.Size.Use = GL_FALSE;
890 }
891
892 /*
893  * Sets the default display mode for all new windows
894  */
895 void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode )
896 {
897     /* We will make use of this value when creating a new OpenGL context... */
898     fgState.DisplayMode = displayMode;
899 }
900
901
902 /* -- INIT DISPLAY STRING PARSING ------------------------------------------ */
903
904 static char* Tokens[] =
905 {
906     "alpha", "acca", "acc", "blue", "buffer", "conformant", "depth", "double",
907     "green", "index", "num", "red", "rgba", "rgb", "luminance", "stencil",
908     "single", "stereo", "samples", "slow", "win32pdf", "win32pfd", "xvisual",
909     "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor",
910     "xtruecolor", "xdirectcolor",
911     "xstaticgrey", "xgreyscale", "xstaticcolour", "xpseudocolour",
912     "xtruecolour", "xdirectcolour", "borderless", "aux"
913 };
914 #define NUM_TOKENS             (sizeof(Tokens) / sizeof(*Tokens))
915
916 void FGAPIENTRY glutInitDisplayString( const char* displayMode )
917 {
918     int glut_state_flag = 0 ;
919     /*
920      * Unpack a lot of options from a character string.  The options are
921      * delimited by blanks or tabs.
922      */
923     char *token ;
924     /* will return true for VC8 (VC2005) and higher */
925 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 )
926     char *next_token = NULL;
927 #endif
928     size_t len = strlen ( displayMode );
929     char *buffer = (char *)malloc ( (len+1) * sizeof(char) );
930     memcpy ( buffer, displayMode, len );
931     buffer[len] = '\0';
932
933     /* will return true for VC8 (VC2005) and higher */
934 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 )
935     token = strtok_s ( buffer, " \t", &next_token );
936 #else
937     token = strtok ( buffer, " \t" );
938 #endif
939     while ( token )
940     {
941         /* Process this token */
942         int i ;
943
944         /* Temporary fix:  Ignore any length specifications and at least
945          * process the basic token
946          * TODO:  Fix this permanently
947          */
948         size_t cleanlength = strcspn ( token, "=<>~!" );
949
950         for ( i = 0; i < NUM_TOKENS; i++ )
951         {
952             if ( strncmp ( token, Tokens[i], cleanlength ) == 0 ) break ;
953         }
954
955         switch ( i )
956         {
957         case 0 :  /* "alpha":  Alpha color buffer precision in bits */
958             glut_state_flag |= GLUT_ALPHA ;  /* Somebody fix this for me! */
959             break ;
960
961         case 1 :  /* "acca":  Red, green, blue, and alpha accumulation buffer
962                      precision in bits */
963             break ;
964
965         case 2 :  /* "acc":  Red, green, and blue accumulation buffer precision
966                      in bits with zero bits alpha */
967             glut_state_flag |= GLUT_ACCUM ;  /* Somebody fix this for me! */
968             break ;
969
970         case 3 :  /* "blue":  Blue color buffer precision in bits */
971             break ;
972
973         case 4 :  /* "buffer":  Number of bits in the color index color buffer
974                    */
975             break ;
976
977         case 5 :  /* "conformant":  Boolean indicating if the frame buffer
978                      configuration is conformant or not */
979             break ;
980
981         case 6 : /* "depth":  Number of bits of precsion in the depth buffer */
982             glut_state_flag |= GLUT_DEPTH ;  /* Somebody fix this for me! */
983             break ;
984
985         case 7 :  /* "double":  Boolean indicating if the color buffer is
986                      double buffered */
987             glut_state_flag |= GLUT_DOUBLE ;
988             break ;
989
990         case 8 :  /* "green":  Green color buffer precision in bits */
991             break ;
992
993         case 9 :  /* "index":  Boolean if the color model is color index or not
994                    */
995             glut_state_flag |= GLUT_INDEX ;
996             break ;
997
998         case 10 :  /* "num":  A special capability  name indicating where the
999                       value represents the Nth frame buffer configuration
1000                       matching the description string */
1001             break ;
1002
1003         case 11 :  /* "red":  Red color buffer precision in bits */
1004             break ;
1005
1006         case 12 :  /* "rgba":  Number of bits of red, green, blue, and alpha in
1007                       the RGBA color buffer */
1008             glut_state_flag |= GLUT_RGBA ;  /* Somebody fix this for me! */
1009             break ;
1010
1011         case 13 :  /* "rgb":  Number of bits of red, green, and blue in the
1012                       RGBA color buffer with zero bits alpha */
1013             glut_state_flag |= GLUT_RGB ;  /* Somebody fix this for me! */
1014             break ;
1015
1016         case 14 :  /* "luminance":  Number of bits of red in the RGBA and zero
1017                       bits of green, blue (alpha not specified) of color buffer
1018                       precision */
1019             glut_state_flag |= GLUT_LUMINANCE ; /* Somebody fix this for me! */
1020             break ;
1021
1022         case 15 :  /* "stencil":  Number of bits in the stencil buffer */
1023             glut_state_flag |= GLUT_STENCIL;  /* Somebody fix this for me! */
1024             break ;
1025
1026         case 16 :  /* "single":  Boolean indicate the color buffer is single
1027                       buffered */
1028             glut_state_flag |= GLUT_SINGLE ;
1029             break ;
1030
1031         case 17 :  /* "stereo":  Boolean indicating the color buffer supports
1032                       OpenGL-style stereo */
1033             glut_state_flag |= GLUT_STEREO ;
1034             break ;
1035
1036         case 18 :  /* "samples":  Indicates the number of multisamples to use
1037                       based on GLX's SGIS_multisample extension (for
1038                       antialiasing) */
1039             glut_state_flag |= GLUT_MULTISAMPLE ; /*Somebody fix this for me!*/
1040             break ;
1041
1042         case 19 :  /* "slow":  Boolean indicating if the frame buffer
1043                       configuration is slow or not */
1044             break ;
1045
1046         case 20 :  /* "win32pdf": (incorrect spelling but was there before */
1047         case 21 :  /* "win32pfd":  matches the Win32 Pixel Format Descriptor by
1048                       number */
1049 #if TARGET_HOST_MS_WINDOWS
1050 #endif
1051             break ;
1052
1053         case 22 :  /* "xvisual":  matches the X visual ID by number */
1054 #if TARGET_HOST_POSIX_X11
1055 #endif
1056             break ;
1057
1058         case 23 :  /* "xstaticgray": */
1059         case 29 :  /* "xstaticgrey":  boolean indicating if the frame buffer
1060                       configuration's X visual is of type StaticGray */
1061 #if TARGET_HOST_POSIX_X11
1062 #endif
1063             break ;
1064
1065         case 24 :  /* "xgrayscale": */
1066         case 30 :  /* "xgreyscale":  boolean indicating if the frame buffer
1067                       configuration's X visual is of type GrayScale */
1068 #if TARGET_HOST_POSIX_X11
1069 #endif
1070             break ;
1071
1072         case 25 :  /* "xstaticcolor": */
1073         case 31 :  /* "xstaticcolour":  boolean indicating if the frame buffer
1074                       configuration's X visual is of type StaticColor */
1075 #if TARGET_HOST_POSIX_X11
1076 #endif
1077             break ;
1078
1079         case 26 :  /* "xpseudocolor": */
1080         case 32 :  /* "xpseudocolour":  boolean indicating if the frame buffer
1081                       configuration's X visual is of type PseudoColor */
1082 #if TARGET_HOST_POSIX_X11
1083 #endif
1084             break ;
1085
1086         case 27 :  /* "xtruecolor": */
1087         case 33 :  /* "xtruecolour":  boolean indicating if the frame buffer
1088                       configuration's X visual is of type TrueColor */
1089 #if TARGET_HOST_POSIX_X11
1090 #endif
1091             break ;
1092
1093         case 28 :  /* "xdirectcolor": */
1094         case 34 :  /* "xdirectcolour":  boolean indicating if the frame buffer
1095                       configuration's X visual is of type DirectColor */
1096 #if TARGET_HOST_POSIX_X11
1097 #endif
1098             break ;
1099
1100         case 35 :  /* "borderless":  windows should not have borders */
1101 #if TARGET_HOST_POSIX_X11
1102 #endif
1103             break ;
1104
1105         case 36 :  /* "aux":  some number of aux buffers */
1106             glut_state_flag |= GLUT_AUX;
1107             break ;
1108
1109         case 37 :  /* Unrecognized */
1110             fgWarning ( "WARNING - Display string token not recognized:  %s",
1111                         token );
1112             break ;
1113         }
1114
1115     /* will return true for VC8 (VC2005) and higher */
1116 #if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 )
1117         token = strtok_s ( NULL, " \t", &next_token );
1118 #else
1119         token = strtok ( NULL, " \t" );
1120 #endif
1121     }
1122
1123     free ( buffer );
1124
1125     /* We will make use of this value when creating a new OpenGL context... */
1126     fgState.DisplayMode = glut_state_flag;
1127 }
1128
1129 /* -- SETTING OPENGL 3.0 CONTEXT CREATION PARAMETERS ---------------------- */
1130
1131 void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion )
1132 {
1133     /* We will make use of these valuse when creating a new OpenGL context... */
1134     fgState.MajorVersion = majorVersion;
1135     fgState.MinorVersion = minorVersion;
1136 }
1137
1138
1139 void FGAPIENTRY glutInitContextFlags( int flags )
1140 {
1141     /* We will make use of this value when creating a new OpenGL context... */
1142     fgState.ContextFlags = flags;
1143 }
1144
1145 /*** END OF FILE ***/