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