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