c96ca104c259e87e42587fc56e6abe9bd54fdeaa
[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     fgDisplay.DisplayName=strdup(displayName);
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     /* If we have a DisplayName try to use it for metrics */
367     if( fgDisplay.DisplayName )
368     {
369         HDC context = CreateDC(fgDisplay.DisplayName,0,0,0);
370         if( context )
371         {
372             fgDisplay.ScreenWidth  = GetDeviceCaps( context, HORZRES );
373             fgDisplay.ScreenHeight = GetDeviceCaps( context, VERTRES );
374             fgDisplay.ScreenWidthMM  = GetDeviceCaps( context, HORZSIZE );
375             fgDisplay.ScreenHeightMM = GetDeviceCaps( context, VERTSIZE );
376             DeleteDC(context);
377         }
378         else
379             fgWarning("fghInitialize: "
380                       "CreateDC failed, Screen size info may be incorrect");
381       
382     }
383     /* Set the timer granularity to 1 ms */
384     timeBeginPeriod ( 1 );
385
386 #endif
387
388     fgState.Initialised = GL_TRUE;
389
390     /* InputDevice uses GlutTimerFunc(), so fgState.Initialised must be TRUE */
391     fgInitialiseInputDevices();
392 }
393
394 /*
395  * Perform the freeglut deinitialization...
396  */
397 void fgDeinitialize( void )
398 {
399     SFG_Timer *timer;
400
401     if( !fgState.Initialised )
402     {
403         fgWarning( "fgDeinitialize(): "
404                    "no valid initialization has been performed" );
405         return;
406     }
407
408     /* If there was a menu created, destroy the rendering context */
409     if( fgStructure.MenuContext )
410     {
411 #if TARGET_HOST_POSIX_X11
412         /* Note that the MVisualInfo is not owned by the MenuContext! */
413         glXDestroyContext( fgDisplay.Display, fgStructure.MenuContext->MContext );
414 #endif
415         free( fgStructure.MenuContext );
416         fgStructure.MenuContext = NULL;
417     }
418
419     fgDestroyStructure( );
420
421     while( ( timer = fgState.Timers.First) )
422     {
423         fgListRemove( &fgState.Timers, &timer->Node );
424         free( timer );
425     }
426
427     while( ( timer = fgState.FreeTimers.First) )
428     {
429         fgListRemove( &fgState.FreeTimers, &timer->Node );
430         free( timer );
431     }
432
433 #if !defined(_WIN32_WCE)
434     if ( fgState.JoysticksInitialised )
435         fgJoystickClose( );
436
437     if ( fgState.InputDevsInitialised )
438         fgInputDeviceClose( );
439 #endif /* !defined(_WIN32_WCE) */
440     fgState.JoysticksInitialised = GL_FALSE;
441     fgState.InputDevsInitialised = GL_FALSE;
442
443     fgState.MajorVersion = 1;
444     fgState.MinorVersion = 0;
445     fgState.ContextFlags = 0;
446     fgState.ContextProfile = 0;
447
448     fgState.Initialised = GL_FALSE;
449
450     fgState.Position.X = -1;
451     fgState.Position.Y = -1;
452     fgState.Position.Use = GL_FALSE;
453
454     fgState.Size.X = 300;
455     fgState.Size.Y = 300;
456     fgState.Size.Use = GL_TRUE;
457
458     fgState.DisplayMode = GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH;
459
460     fgState.DirectContext  = GLUT_TRY_DIRECT_CONTEXT;
461     fgState.ForceIconic         = GL_FALSE;
462     fgState.UseCurrentContext   = GL_FALSE;
463     fgState.GLDebugSwitch       = GL_FALSE;
464     fgState.XSyncSwitch         = GL_FALSE;
465     fgState.ActionOnWindowClose = GLUT_ACTION_EXIT;
466     fgState.ExecState           = GLUT_EXEC_STATE_INIT;
467
468     fgState.KeyRepeat       = GLUT_KEY_REPEAT_ON;
469     fgState.Modifiers       = INVALID_MODIFIERS;
470
471     fgState.GameModeSize.X  = 640;
472     fgState.GameModeSize.Y  = 480;
473     fgState.GameModeDepth   =  16;
474     fgState.GameModeRefresh =  72;
475
476     fgListInit( &fgState.Timers );
477     fgListInit( &fgState.FreeTimers );
478
479     fgState.IdleCallback = NULL;
480     fgState.MenuStateCallback = ( FGCBMenuState )NULL;
481     fgState.MenuStatusCallback = ( FGCBMenuStatus )NULL;
482
483     fgState.SwapCount   = 0;
484     fgState.SwapTime    = 0;
485     fgState.FPSInterval = 0;
486
487     if( fgState.ProgramName )
488     {
489         free( fgState.ProgramName );
490         fgState.ProgramName = NULL;
491     }
492
493 #if TARGET_HOST_POSIX_X11
494
495     /*
496      * Make sure all X-client data we have created will be destroyed on
497      * display closing
498      */
499     XSetCloseDownMode( fgDisplay.Display, DestroyAll );
500
501     /*
502      * Close the display connection, destroying all windows we have
503      * created so far
504      */
505     XCloseDisplay( fgDisplay.Display );
506
507 #elif TARGET_HOST_MS_WINDOWS
508     if( fgDisplay.DisplayName )
509     {
510         free( fgDisplay.DisplayName );
511         fgDisplay.DisplayName = NULL;
512     }
513
514     /* Reset the timer granularity */
515     timeEndPeriod ( 1 );
516
517 #endif
518
519     fgState.Initialised = GL_FALSE;
520 }
521
522 /*
523  * Everything inside the following #ifndef is copied from the X sources.
524  */
525
526 #if TARGET_HOST_MS_WINDOWS
527
528 /*
529
530 Copyright 1985, 1986, 1987,1998  The Open Group
531
532 Permission to use, copy, modify, distribute, and sell this software and its
533 documentation for any purpose is hereby granted without fee, provided that
534 the above copyright notice appear in all copies and that both that
535 copyright notice and this permission notice appear in supporting
536 documentation.
537
538 The above copyright notice and this permission notice shall be included
539 in all copies or substantial portions of the Software.
540
541 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
542 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
543 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
544 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
545 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
546 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
547 OTHER DEALINGS IN THE SOFTWARE.
548
549 Except as contained in this notice, the name of The Open Group shall
550 not be used in advertising or otherwise to promote the sale, use or
551 other dealings in this Software without prior written authorization
552 from The Open Group.
553
554 */
555
556 #define NoValue         0x0000
557 #define XValue          0x0001
558 #define YValue          0x0002
559 #define WidthValue      0x0004
560 #define HeightValue     0x0008
561 #define AllValues       0x000F
562 #define XNegative       0x0010
563 #define YNegative       0x0020
564
565 /*
566  *    XParseGeometry parses strings of the form
567  *   "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
568  *   width, height, xoffset, and yoffset are unsigned integers.
569  *   Example:  "=80x24+300-49"
570  *   The equal sign is optional.
571  *   It returns a bitmask that indicates which of the four values
572  *   were actually found in the string.  For each value found,
573  *   the corresponding argument is updated;  for each value
574  *   not found, the corresponding argument is left unchanged.
575  */
576
577 static int
578 ReadInteger(char *string, char **NextString)
579 {
580     register int Result = 0;
581     int Sign = 1;
582
583     if (*string == '+')
584         string++;
585     else if (*string == '-')
586     {
587         string++;
588         Sign = -1;
589     }
590     for (; (*string >= '0') && (*string <= '9'); string++)
591     {
592         Result = (Result * 10) + (*string - '0');
593     }
594     *NextString = string;
595     if (Sign >= 0)
596         return Result;
597     else
598         return -Result;
599 }
600
601 static int XParseGeometry (
602     const char *string,
603     int *x,
604     int *y,
605     unsigned int *width,    /* RETURN */
606     unsigned int *height)    /* RETURN */
607 {
608     int mask = NoValue;
609     register char *strind;
610     unsigned int tempWidth = 0, tempHeight = 0;
611     int tempX = 0, tempY = 0;
612     char *nextCharacter;
613
614     if ( (string == NULL) || (*string == '\0'))
615       return mask;
616     if (*string == '=')
617         string++;  /* ignore possible '=' at beg of geometry spec */
618
619     strind = (char *)string;
620     if (*strind != '+' && *strind != '-' && *strind != 'x') {
621         tempWidth = ReadInteger(strind, &nextCharacter);
622         if (strind == nextCharacter)
623             return 0;
624         strind = nextCharacter;
625         mask |= WidthValue;
626     }
627
628     if (*strind == 'x' || *strind == 'X') {
629         strind++;
630         tempHeight = ReadInteger(strind, &nextCharacter);
631         if (strind == nextCharacter)
632             return 0;
633         strind = nextCharacter;
634         mask |= HeightValue;
635     }
636
637     if ((*strind == '+') || (*strind == '-')) {
638         if (*strind == '-') {
639             strind++;
640             tempX = -ReadInteger(strind, &nextCharacter);
641             if (strind == nextCharacter)
642                 return 0;
643             strind = nextCharacter;
644             mask |= XNegative;
645         }
646         else
647         {
648             strind++;
649             tempX = ReadInteger(strind, &nextCharacter);
650             if (strind == nextCharacter)
651                 return 0;
652             strind = nextCharacter;
653         }
654         mask |= XValue;
655         if ((*strind == '+') || (*strind == '-')) {
656             if (*strind == '-') {
657                 strind++;
658                 tempY = -ReadInteger(strind, &nextCharacter);
659                 if (strind == nextCharacter)
660                     return 0;
661                 strind = nextCharacter;
662                 mask |= YNegative;
663             }
664             else
665             {
666                 strind++;
667                 tempY = ReadInteger(strind, &nextCharacter);
668                 if (strind == nextCharacter)
669                     return 0;
670                 strind = nextCharacter;
671             }
672             mask |= YValue;
673         }
674     }
675
676     /* If strind isn't at the end of the string the it's an invalid
677        geometry specification. */
678
679     if (*strind != '\0') return 0;
680
681     if (mask & XValue)
682         *x = tempX;
683     if (mask & YValue)
684         *y = tempY;
685     if (mask & WidthValue)
686         *width = tempWidth;
687     if (mask & HeightValue)
688         *height = tempHeight;
689     return mask;
690 }
691 #endif
692
693 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
694
695 /*
696  * Perform initialization. This usually happens on the program startup
697  * and restarting after glutMainLoop termination...
698  */
699 void FGAPIENTRY glutInit( int* pargc, char** argv )
700 {
701     char* displayName = NULL;
702     char* geometry = NULL;
703     int i, j, argc = *pargc;
704
705     if( fgState.Initialised )
706         fgError( "illegal glutInit() reinitialization attempt" );
707
708     if (pargc && *pargc && argv && *argv && **argv)
709     {
710         fgState.ProgramName = strdup (*argv);
711
712         if( !fgState.ProgramName )
713             fgError ("Could not allocate space for the program's name.");
714     }
715
716     fgCreateStructure( );
717
718     /* Get start time */
719     fgState.Time = fgSystemTime();
720
721     /* check if GLUT_FPS env var is set */
722 #ifndef _WIN32_WCE
723     {
724         const char *fps = getenv( "GLUT_FPS" );
725
726         if( fps )
727         {
728             int interval;
729             sscanf( fps, "%d", &interval );
730
731             if( interval <= 0 )
732                 fgState.FPSInterval = 5000;  /* 5000 millisecond default */
733             else
734                 fgState.FPSInterval = interval;
735         }
736     }
737
738     displayName = getenv( "DISPLAY" );
739
740     for( i = 1; i < argc; i++ )
741     {
742         if( strcmp( argv[ i ], "-display" ) == 0 )
743         {
744             if( ++i >= argc )
745                 fgError( "-display parameter must be followed by display name" );
746
747             displayName = argv[ i ];
748
749             argv[ i - 1 ] = NULL;
750             argv[ i     ] = NULL;
751             ( *pargc ) -= 2;
752         }
753         else if( strcmp( argv[ i ], "-geometry" ) == 0 )
754         {
755             if( ++i >= argc )
756                 fgError( "-geometry parameter must be followed by window "
757                          "geometry settings" );
758
759             geometry = argv[ i ];
760
761             argv[ i - 1 ] = NULL;
762             argv[ i     ] = NULL;
763             ( *pargc ) -= 2;
764         }
765         else if( strcmp( argv[ i ], "-direct" ) == 0)
766         {
767             if( fgState.DirectContext == GLUT_FORCE_INDIRECT_CONTEXT )
768                 fgError( "parameters ambiguity, -direct and -indirect "
769                     "cannot be both specified" );
770
771             fgState.DirectContext = GLUT_FORCE_DIRECT_CONTEXT;
772             argv[ i ] = NULL;
773             ( *pargc )--;
774         }
775         else if( strcmp( argv[ i ], "-indirect" ) == 0 )
776         {
777             if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT )
778                 fgError( "parameters ambiguity, -direct and -indirect "
779                     "cannot be both specified" );
780
781             fgState.DirectContext = GLUT_FORCE_INDIRECT_CONTEXT;
782             argv[ i ] = NULL;
783             (*pargc)--;
784         }
785         else if( strcmp( argv[ i ], "-iconic" ) == 0 )
786         {
787             fgState.ForceIconic = GL_TRUE;
788             argv[ i ] = NULL;
789             ( *pargc )--;
790         }
791         else if( strcmp( argv[ i ], "-gldebug" ) == 0 )
792         {
793             fgState.GLDebugSwitch = GL_TRUE;
794             argv[ i ] = NULL;
795             ( *pargc )--;
796         }
797         else if( strcmp( argv[ i ], "-sync" ) == 0 )
798         {
799             fgState.XSyncSwitch = GL_TRUE;
800             argv[ i ] = NULL;
801             ( *pargc )--;
802         }
803     }
804
805     /* Compact {argv}. */
806     for( i = j = 1; i < *pargc; i++, j++ )
807     {
808         /* Guaranteed to end because there are "*pargc" arguments left */
809         while ( argv[ j ] == NULL )
810             j++;
811         if ( i != j )
812             argv[ i ] = argv[ j ];
813     }
814
815 #endif /* _WIN32_WCE */
816
817     /*
818      * Have the display created now. If there wasn't a "-display"
819      * in the program arguments, we will use the DISPLAY environment
820      * variable for opening the X display (see code above):
821      */
822     fghInitialize( displayName );
823
824     /*
825      * Geometry parsing deffered until here because we may need the screen
826      * size.
827      */
828
829     if (geometry )
830     {
831         unsigned int parsedWidth, parsedHeight;
832         int mask = XParseGeometry( geometry,
833                                    &fgState.Position.X, &fgState.Position.Y,
834                                    &parsedWidth, &parsedHeight );
835         /* TODO: Check for overflow? */
836         fgState.Size.X = parsedWidth;
837         fgState.Size.Y = parsedHeight;
838
839         if( (mask & (WidthValue|HeightValue)) == (WidthValue|HeightValue) )
840             fgState.Size.Use = GL_TRUE;
841
842         if( mask & XNegative )
843             fgState.Position.X += fgDisplay.ScreenWidth - fgState.Size.X;
844
845         if( mask & YNegative )
846             fgState.Position.Y += fgDisplay.ScreenHeight - fgState.Size.Y;
847
848         if( (mask & (XValue|YValue)) == (XValue|YValue) )
849             fgState.Position.Use = GL_TRUE;
850     }
851 }
852
853 #if TARGET_HOST_MS_WINDOWS
854 void (__cdecl *__glutExitFunc)( int return_value ) = NULL;
855
856 void FGAPIENTRY __glutInitWithExit( int *pargc, char **argv, void (__cdecl *exit_function)(int) )
857 {
858   __glutExitFunc = exit_function;
859   glutInit(pargc, argv);
860 }
861 #endif
862
863 /*
864  * Undoes all the "glutInit" stuff
865  */
866 void FGAPIENTRY glutExit ( void )
867 {
868   fgDeinitialize ();
869 }
870
871 /*
872  * Sets the default initial window position for new windows
873  */
874 void FGAPIENTRY glutInitWindowPosition( int x, int y )
875 {
876     fgState.Position.X = x;
877     fgState.Position.Y = y;
878
879     if( ( x >= 0 ) && ( y >= 0 ) )
880         fgState.Position.Use = GL_TRUE;
881     else
882         fgState.Position.Use = GL_FALSE;
883 }
884
885 /*
886  * Sets the default initial window size for new windows
887  */
888 void FGAPIENTRY glutInitWindowSize( int width, int height )
889 {
890     fgState.Size.X = width;
891     fgState.Size.Y = height;
892
893     if( ( width > 0 ) && ( height > 0 ) )
894         fgState.Size.Use = GL_TRUE;
895     else
896         fgState.Size.Use = GL_FALSE;
897 }
898
899 /*
900  * Sets the default display mode for all new windows
901  */
902 void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode )
903 {
904     /* We will make use of this value when creating a new OpenGL context... */
905     fgState.DisplayMode = displayMode;
906 }
907
908
909 /* -- INIT DISPLAY STRING PARSING ------------------------------------------ */
910
911 static char* Tokens[] =
912 {
913     "alpha", "acca", "acc", "blue", "buffer", "conformant", "depth", "double",
914     "green", "index", "num", "red", "rgba", "rgb", "luminance", "stencil",
915     "single", "stereo", "samples", "slow", "win32pdf", "win32pfd", "xvisual",
916     "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor",
917     "xtruecolor", "xdirectcolor",
918     "xstaticgrey", "xgreyscale", "xstaticcolour", "xpseudocolour",
919     "xtruecolour", "xdirectcolour", "borderless", "aux"
920 };
921 #define NUM_TOKENS             (sizeof(Tokens) / sizeof(*Tokens))
922
923 void FGAPIENTRY glutInitDisplayString( const char* displayMode )
924 {
925     int glut_state_flag = 0 ;
926     /*
927      * Unpack a lot of options from a character string.  The options are
928      * delimited by blanks or tabs.
929      */
930     char *token ;
931     size_t len = strlen ( displayMode );
932     char *buffer = (char *)malloc ( (len+1) * sizeof(char) );
933     memcpy ( buffer, displayMode, len );
934     buffer[len] = '\0';
935
936     token = strtok ( buffer, " \t" );
937
938     while ( token )
939     {
940         /* Process this token */
941         int i ;
942
943         /* Temporary fix:  Ignore any length specifications and at least
944          * process the basic token
945          * TODO:  Fix this permanently
946          */
947         size_t cleanlength = strcspn ( token, "=<>~!" );
948
949         for ( i = 0; i < NUM_TOKENS; i++ )
950         {
951             if ( strncmp ( token, Tokens[i], cleanlength ) == 0 ) break ;
952         }
953
954         switch ( i )
955         {
956         case 0 :  /* "alpha":  Alpha color buffer precision in bits */
957             glut_state_flag |= GLUT_ALPHA ;  /* Somebody fix this for me! */
958             break ;
959
960         case 1 :  /* "acca":  Red, green, blue, and alpha accumulation buffer
961                      precision in bits */
962             break ;
963
964         case 2 :  /* "acc":  Red, green, and blue accumulation buffer precision
965                      in bits with zero bits alpha */
966             glut_state_flag |= GLUT_ACCUM ;  /* Somebody fix this for me! */
967             break ;
968
969         case 3 :  /* "blue":  Blue color buffer precision in bits */
970             break ;
971
972         case 4 :  /* "buffer":  Number of bits in the color index color buffer
973                    */
974             break ;
975
976         case 5 :  /* "conformant":  Boolean indicating if the frame buffer
977                      configuration is conformant or not */
978             break ;
979
980         case 6 : /* "depth":  Number of bits of precsion in the depth buffer */
981             glut_state_flag |= GLUT_DEPTH ;  /* Somebody fix this for me! */
982             break ;
983
984         case 7 :  /* "double":  Boolean indicating if the color buffer is
985                      double buffered */
986             glut_state_flag |= GLUT_DOUBLE ;
987             break ;
988
989         case 8 :  /* "green":  Green color buffer precision in bits */
990             break ;
991
992         case 9 :  /* "index":  Boolean if the color model is color index or not
993                    */
994             glut_state_flag |= GLUT_INDEX ;
995             break ;
996
997         case 10 :  /* "num":  A special capability  name indicating where the
998                       value represents the Nth frame buffer configuration
999                       matching the description string */
1000             break ;
1001
1002         case 11 :  /* "red":  Red color buffer precision in bits */
1003             break ;
1004
1005         case 12 :  /* "rgba":  Number of bits of red, green, blue, and alpha in
1006                       the RGBA color buffer */
1007             glut_state_flag |= GLUT_RGBA ;  /* Somebody fix this for me! */
1008             break ;
1009
1010         case 13 :  /* "rgb":  Number of bits of red, green, and blue in the
1011                       RGBA color buffer with zero bits alpha */
1012             glut_state_flag |= GLUT_RGB ;  /* Somebody fix this for me! */
1013             break ;
1014
1015         case 14 :  /* "luminance":  Number of bits of red in the RGBA and zero
1016                       bits of green, blue (alpha not specified) of color buffer
1017                       precision */
1018             glut_state_flag |= GLUT_LUMINANCE ; /* Somebody fix this for me! */
1019             break ;
1020
1021         case 15 :  /* "stencil":  Number of bits in the stencil buffer */
1022             glut_state_flag |= GLUT_STENCIL;  /* Somebody fix this for me! */
1023             break ;
1024
1025         case 16 :  /* "single":  Boolean indicate the color buffer is single
1026                       buffered */
1027             glut_state_flag |= GLUT_SINGLE ;
1028             break ;
1029
1030         case 17 :  /* "stereo":  Boolean indicating the color buffer supports
1031                       OpenGL-style stereo */
1032             glut_state_flag |= GLUT_STEREO ;
1033             break ;
1034
1035         case 18 :  /* "samples":  Indicates the number of multisamples to use
1036                       based on GLX's SGIS_multisample extension (for
1037                       antialiasing) */
1038             glut_state_flag |= GLUT_MULTISAMPLE ; /*Somebody fix this for me!*/
1039             break ;
1040
1041         case 19 :  /* "slow":  Boolean indicating if the frame buffer
1042                       configuration is slow or not */
1043             break ;
1044
1045         case 20 :  /* "win32pdf": (incorrect spelling but was there before */
1046         case 21 :  /* "win32pfd":  matches the Win32 Pixel Format Descriptor by
1047                       number */
1048 #if TARGET_HOST_MS_WINDOWS
1049 #endif
1050             break ;
1051
1052         case 22 :  /* "xvisual":  matches the X visual ID by number */
1053 #if TARGET_HOST_POSIX_X11
1054 #endif
1055             break ;
1056
1057         case 23 :  /* "xstaticgray": */
1058         case 29 :  /* "xstaticgrey":  boolean indicating if the frame buffer
1059                       configuration's X visual is of type StaticGray */
1060 #if TARGET_HOST_POSIX_X11
1061 #endif
1062             break ;
1063
1064         case 24 :  /* "xgrayscale": */
1065         case 30 :  /* "xgreyscale":  boolean indicating if the frame buffer
1066                       configuration's X visual is of type GrayScale */
1067 #if TARGET_HOST_POSIX_X11
1068 #endif
1069             break ;
1070
1071         case 25 :  /* "xstaticcolor": */
1072         case 31 :  /* "xstaticcolour":  boolean indicating if the frame buffer
1073                       configuration's X visual is of type StaticColor */
1074 #if TARGET_HOST_POSIX_X11
1075 #endif
1076             break ;
1077
1078         case 26 :  /* "xpseudocolor": */
1079         case 32 :  /* "xpseudocolour":  boolean indicating if the frame buffer
1080                       configuration's X visual is of type PseudoColor */
1081 #if TARGET_HOST_POSIX_X11
1082 #endif
1083             break ;
1084
1085         case 27 :  /* "xtruecolor": */
1086         case 33 :  /* "xtruecolour":  boolean indicating if the frame buffer
1087                       configuration's X visual is of type TrueColor */
1088 #if TARGET_HOST_POSIX_X11
1089 #endif
1090             break ;
1091
1092         case 28 :  /* "xdirectcolor": */
1093         case 34 :  /* "xdirectcolour":  boolean indicating if the frame buffer
1094                       configuration's X visual is of type DirectColor */
1095 #if TARGET_HOST_POSIX_X11
1096 #endif
1097             break ;
1098
1099         case 35 :  /* "borderless":  windows should not have borders */
1100 #if TARGET_HOST_POSIX_X11
1101 #endif
1102             break ;
1103
1104         case 36 :  /* "aux":  some number of aux buffers */
1105             glut_state_flag |= GLUT_AUX;
1106             break ;
1107
1108         case 37 :  /* Unrecognized */
1109             fgWarning ( "WARNING - Display string token not recognized:  %s",
1110                         token );
1111             break ;
1112         }
1113
1114         token = strtok ( NULL, " \t" );
1115     }
1116
1117     free ( buffer );
1118
1119     /* We will make use of this value when creating a new OpenGL context... */
1120     fgState.DisplayMode = glut_state_flag;
1121 }
1122
1123 /* -- SETTING OPENGL 3.0 CONTEXT CREATION PARAMETERS ---------------------- */
1124
1125 void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion )
1126 {
1127     /* We will make use of these valuse when creating a new OpenGL context... */
1128     fgState.MajorVersion = majorVersion;
1129     fgState.MinorVersion = minorVersion;
1130 }
1131
1132
1133 void FGAPIENTRY glutInitContextFlags( int flags )
1134 {
1135     /* We will make use of this value when creating a new OpenGL context... */
1136     fgState.ContextFlags = flags;
1137 }
1138
1139 void FGAPIENTRY glutInitContextProfile( int profile )
1140 {
1141     /* We will make use of this value when creating a new OpenGL context... */
1142     fgState.ContextProfile = profile;
1143 }
1144
1145 /*** END OF FILE ***/