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