Moving the Windows-specific "glutInitWithExit" function to a Windows-specific file
[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 fgPlatformInitialize( const char* displayName );\r
104 extern void fgPlatformDeinitialiseInputDevices ( void );\r
105 extern void fgPlatformCloseDisplay ( 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.pDisplay.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.pDisplay.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.pDisplay.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 void fgPlatformInitialize( const char* displayName )\r
250 {\r
251     fgDisplay.pDisplay.Display = XOpenDisplay( displayName );\r
252 \r
253     if( fgDisplay.pDisplay.Display == NULL )\r
254         fgError( "failed to open display '%s'", XDisplayName( displayName ) );\r
255 \r
256     if( !glXQueryExtension( fgDisplay.pDisplay.Display, NULL, NULL ) )\r
257         fgError( "OpenGL GLX extension not supported by display '%s'",\r
258             XDisplayName( displayName ) );\r
259 \r
260     fgDisplay.pDisplay.Screen = DefaultScreen( fgDisplay.pDisplay.Display );\r
261     fgDisplay.pDisplay.RootWindow = RootWindow(\r
262         fgDisplay.pDisplay.Display,\r
263         fgDisplay.pDisplay.Screen\r
264     );\r
265 \r
266     fgDisplay.ScreenWidth  = DisplayWidth(\r
267         fgDisplay.pDisplay.Display,\r
268         fgDisplay.pDisplay.Screen\r
269     );\r
270     fgDisplay.ScreenHeight = DisplayHeight(\r
271         fgDisplay.pDisplay.Display,\r
272         fgDisplay.pDisplay.Screen\r
273     );\r
274 \r
275     fgDisplay.ScreenWidthMM = DisplayWidthMM(\r
276         fgDisplay.pDisplay.Display,\r
277         fgDisplay.pDisplay.Screen\r
278     );\r
279     fgDisplay.ScreenHeightMM = DisplayHeightMM(\r
280         fgDisplay.pDisplay.Display,\r
281         fgDisplay.pDisplay.Screen\r
282     );\r
283 \r
284     fgDisplay.pDisplay.Connection = ConnectionNumber( fgDisplay.pDisplay.Display );\r
285 \r
286     /* Create the window deletion atom */\r
287     fgDisplay.pDisplay.DeleteWindow = fghGetAtom("WM_DELETE_WINDOW");\r
288 \r
289     /* Create the state and full screen atoms */\r
290     fgDisplay.pDisplay.State           = None;\r
291     fgDisplay.pDisplay.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.pDisplay.RootWindow, supported, state))\r
300       {\r
301         const Atom full_screen = fghGetAtom("_NET_WM_STATE_FULLSCREEN");\r
302         \r
303         fgDisplay.pDisplay.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.pDisplay.RootWindow, supported, full_screen))\r
308         {\r
309           fgDisplay.pDisplay.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 void fgPlatformDeinitialiseInputDevices ( 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 void fgPlatformCloseDisplay ( 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.pDisplay.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.pDisplay.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.pDisplay.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         fgPlatformDeinitialiseInputDevices ();\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         fgPlatformCloseDisplay ();\r
564 \r
565     fgState.Initialised = GL_FALSE;\r
566 }\r
567 \r
568 \r
569 #if TARGET_HOST_MS_WINDOWS\r
570 #define NoValue         0x0000\r
571 #define XValue          0x0001\r
572 #define YValue          0x0002\r
573 #define WidthValue      0x0004\r
574 #define HeightValue     0x0008\r
575 #define AllValues       0x000F\r
576 #define XNegative       0x0010\r
577 #define YNegative       0x0020\r
578 \r
579 extern int XParseGeometry (\r
580     const char *string,\r
581     int *x,\r
582     int *y,\r
583     unsigned int *width,    /* RETURN */\r
584     unsigned int *height);    /* RETURN */\r
585 #endif\r
586 \r
587 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */\r
588 \r
589 /*\r
590  * Perform initialization. This usually happens on the program startup\r
591  * and restarting after glutMainLoop termination...\r
592  */\r
593 void FGAPIENTRY glutInit( int* pargc, char** argv )\r
594 {\r
595     char* displayName = NULL;\r
596     char* geometry = NULL;\r
597     if( fgState.Initialised )\r
598         fgError( "illegal glutInit() reinitialization attempt" );\r
599 \r
600     if (pargc && *pargc && argv && *argv && **argv)\r
601     {\r
602         fgState.ProgramName = strdup (*argv);\r
603 \r
604         if( !fgState.ProgramName )\r
605             fgError ("Could not allocate space for the program's name.");\r
606     }\r
607 \r
608     fgCreateStructure( );\r
609 \r
610     /* Get start time */\r
611     fgState.Time = fgSystemTime();\r
612 \r
613         fghParseCommandLineArguments ( pargc, argv, &displayName, &geometry );\r
614 \r
615     /*\r
616      * Have the display created now. If there wasn't a "-display"\r
617      * in the program arguments, we will use the DISPLAY environment\r
618      * variable for opening the X display (see code above):\r
619      */\r
620     fgPlatformInitialize( displayName );\r
621 \r
622     /*\r
623      * Geometry parsing deffered until here because we may need the screen\r
624      * size.\r
625      */\r
626 \r
627     if (geometry )\r
628     {\r
629         unsigned int parsedWidth, parsedHeight;\r
630         int mask = XParseGeometry( geometry,\r
631                                    &fgState.Position.X, &fgState.Position.Y,\r
632                                    &parsedWidth, &parsedHeight );\r
633         /* TODO: Check for overflow? */\r
634         fgState.Size.X = parsedWidth;\r
635         fgState.Size.Y = parsedHeight;\r
636 \r
637         if( (mask & (WidthValue|HeightValue)) == (WidthValue|HeightValue) )\r
638             fgState.Size.Use = GL_TRUE;\r
639 \r
640         if( mask & XNegative )\r
641             fgState.Position.X += fgDisplay.ScreenWidth - fgState.Size.X;\r
642 \r
643         if( mask & YNegative )\r
644             fgState.Position.Y += fgDisplay.ScreenHeight - fgState.Size.Y;\r
645 \r
646         if( (mask & (XValue|YValue)) == (XValue|YValue) )\r
647             fgState.Position.Use = GL_TRUE;\r
648     }\r
649 }\r
650 \r
651 /*\r
652  * Undoes all the "glutInit" stuff\r
653  */\r
654 void FGAPIENTRY glutExit ( void )\r
655 {\r
656   fgDeinitialize ();\r
657 }\r
658 \r
659 /*\r
660  * Sets the default initial window position for new windows\r
661  */\r
662 void FGAPIENTRY glutInitWindowPosition( int x, int y )\r
663 {\r
664     fgState.Position.X = x;\r
665     fgState.Position.Y = y;\r
666 \r
667     if( ( x >= 0 ) && ( y >= 0 ) )\r
668         fgState.Position.Use = GL_TRUE;\r
669     else\r
670         fgState.Position.Use = GL_FALSE;\r
671 }\r
672 \r
673 /*\r
674  * Sets the default initial window size for new windows\r
675  */\r
676 void FGAPIENTRY glutInitWindowSize( int width, int height )\r
677 {\r
678     fgState.Size.X = width;\r
679     fgState.Size.Y = height;\r
680 \r
681     if( ( width > 0 ) && ( height > 0 ) )\r
682         fgState.Size.Use = GL_TRUE;\r
683     else\r
684         fgState.Size.Use = GL_FALSE;\r
685 }\r
686 \r
687 /*\r
688  * Sets the default display mode for all new windows\r
689  */\r
690 void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode )\r
691 {\r
692     /* We will make use of this value when creating a new OpenGL context... */\r
693     fgState.DisplayMode = displayMode;\r
694 }\r
695 \r
696 \r
697 /* -- INIT DISPLAY STRING PARSING ------------------------------------------ */\r
698 \r
699 static char* Tokens[] =\r
700 {\r
701     "alpha", "acca", "acc", "blue", "buffer", "conformant", "depth", "double",\r
702     "green", "index", "num", "red", "rgba", "rgb", "luminance", "stencil",\r
703     "single", "stereo", "samples", "slow", "win32pdf", "win32pfd", "xvisual",\r
704     "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor",\r
705     "xtruecolor", "xdirectcolor",\r
706     "xstaticgrey", "xgreyscale", "xstaticcolour", "xpseudocolour",\r
707     "xtruecolour", "xdirectcolour", "borderless", "aux"\r
708 };\r
709 #define NUM_TOKENS             (sizeof(Tokens) / sizeof(*Tokens))\r
710 \r
711 void FGAPIENTRY glutInitDisplayString( const char* displayMode )\r
712 {\r
713     int glut_state_flag = 0 ;\r
714     /*\r
715      * Unpack a lot of options from a character string.  The options are\r
716      * delimited by blanks or tabs.\r
717      */\r
718     char *token ;\r
719     size_t len = strlen ( displayMode );\r
720     char *buffer = (char *)malloc ( (len+1) * sizeof(char) );\r
721     memcpy ( buffer, displayMode, len );\r
722     buffer[len] = '\0';\r
723 \r
724     token = strtok ( buffer, " \t" );\r
725 \r
726     while ( token )\r
727     {\r
728         /* Process this token */\r
729         int i ;\r
730 \r
731         /* Temporary fix:  Ignore any length specifications and at least\r
732          * process the basic token\r
733          * TODO:  Fix this permanently\r
734          */\r
735         size_t cleanlength = strcspn ( token, "=<>~!" );\r
736 \r
737         for ( i = 0; i < NUM_TOKENS; i++ )\r
738         {\r
739             if ( strncmp ( token, Tokens[i], cleanlength ) == 0 ) break ;\r
740         }\r
741 \r
742         switch ( i )\r
743         {\r
744         case 0 :  /* "alpha":  Alpha color buffer precision in bits */\r
745             glut_state_flag |= GLUT_ALPHA ;  /* Somebody fix this for me! */\r
746             break ;\r
747 \r
748         case 1 :  /* "acca":  Red, green, blue, and alpha accumulation buffer\r
749                      precision in bits */\r
750             break ;\r
751 \r
752         case 2 :  /* "acc":  Red, green, and blue accumulation buffer precision\r
753                      in bits with zero bits alpha */\r
754             glut_state_flag |= GLUT_ACCUM ;  /* Somebody fix this for me! */\r
755             break ;\r
756 \r
757         case 3 :  /* "blue":  Blue color buffer precision in bits */\r
758             break ;\r
759 \r
760         case 4 :  /* "buffer":  Number of bits in the color index color buffer\r
761                    */\r
762             break ;\r
763 \r
764         case 5 :  /* "conformant":  Boolean indicating if the frame buffer\r
765                      configuration is conformant or not */\r
766             break ;\r
767 \r
768         case 6 : /* "depth":  Number of bits of precsion in the depth buffer */\r
769             glut_state_flag |= GLUT_DEPTH ;  /* Somebody fix this for me! */\r
770             break ;\r
771 \r
772         case 7 :  /* "double":  Boolean indicating if the color buffer is\r
773                      double buffered */\r
774             glut_state_flag |= GLUT_DOUBLE ;\r
775             break ;\r
776 \r
777         case 8 :  /* "green":  Green color buffer precision in bits */\r
778             break ;\r
779 \r
780         case 9 :  /* "index":  Boolean if the color model is color index or not\r
781                    */\r
782             glut_state_flag |= GLUT_INDEX ;\r
783             break ;\r
784 \r
785         case 10 :  /* "num":  A special capability  name indicating where the\r
786                       value represents the Nth frame buffer configuration\r
787                       matching the description string */\r
788             break ;\r
789 \r
790         case 11 :  /* "red":  Red color buffer precision in bits */\r
791             break ;\r
792 \r
793         case 12 :  /* "rgba":  Number of bits of red, green, blue, and alpha in\r
794                       the RGBA color buffer */\r
795             glut_state_flag |= GLUT_RGBA ;  /* Somebody fix this for me! */\r
796             break ;\r
797 \r
798         case 13 :  /* "rgb":  Number of bits of red, green, and blue in the\r
799                       RGBA color buffer with zero bits alpha */\r
800             glut_state_flag |= GLUT_RGB ;  /* Somebody fix this for me! */\r
801             break ;\r
802 \r
803         case 14 :  /* "luminance":  Number of bits of red in the RGBA and zero\r
804                       bits of green, blue (alpha not specified) of color buffer\r
805                       precision */\r
806             glut_state_flag |= GLUT_LUMINANCE ; /* Somebody fix this for me! */\r
807             break ;\r
808 \r
809         case 15 :  /* "stencil":  Number of bits in the stencil buffer */\r
810             glut_state_flag |= GLUT_STENCIL;  /* Somebody fix this for me! */\r
811             break ;\r
812 \r
813         case 16 :  /* "single":  Boolean indicate the color buffer is single\r
814                       buffered */\r
815             glut_state_flag |= GLUT_SINGLE ;\r
816             break ;\r
817 \r
818         case 17 :  /* "stereo":  Boolean indicating the color buffer supports\r
819                       OpenGL-style stereo */\r
820             glut_state_flag |= GLUT_STEREO ;\r
821             break ;\r
822 \r
823         case 18 :  /* "samples":  Indicates the number of multisamples to use\r
824                       based on GLX's SGIS_multisample extension (for\r
825                       antialiasing) */\r
826             glut_state_flag |= GLUT_MULTISAMPLE ; /*Somebody fix this for me!*/\r
827             break ;\r
828 \r
829         case 19 :  /* "slow":  Boolean indicating if the frame buffer\r
830                       configuration is slow or not */\r
831             break ;\r
832 \r
833         case 20 :  /* "win32pdf": (incorrect spelling but was there before */\r
834         case 21 :  /* "win32pfd":  matches the Win32 Pixel Format Descriptor by\r
835                       number */\r
836 #if TARGET_HOST_MS_WINDOWS\r
837 #endif\r
838             break ;\r
839 \r
840         case 22 :  /* "xvisual":  matches the X visual ID by number */\r
841 #if TARGET_HOST_POSIX_X11\r
842 #endif\r
843             break ;\r
844 \r
845         case 23 :  /* "xstaticgray": */\r
846         case 29 :  /* "xstaticgrey":  boolean indicating if the frame buffer\r
847                       configuration's X visual is of type StaticGray */\r
848 #if TARGET_HOST_POSIX_X11\r
849 #endif\r
850             break ;\r
851 \r
852         case 24 :  /* "xgrayscale": */\r
853         case 30 :  /* "xgreyscale":  boolean indicating if the frame buffer\r
854                       configuration's X visual is of type GrayScale */\r
855 #if TARGET_HOST_POSIX_X11\r
856 #endif\r
857             break ;\r
858 \r
859         case 25 :  /* "xstaticcolor": */\r
860         case 31 :  /* "xstaticcolour":  boolean indicating if the frame buffer\r
861                       configuration's X visual is of type StaticColor */\r
862 #if TARGET_HOST_POSIX_X11\r
863 #endif\r
864             break ;\r
865 \r
866         case 26 :  /* "xpseudocolor": */\r
867         case 32 :  /* "xpseudocolour":  boolean indicating if the frame buffer\r
868                       configuration's X visual is of type PseudoColor */\r
869 #if TARGET_HOST_POSIX_X11\r
870 #endif\r
871             break ;\r
872 \r
873         case 27 :  /* "xtruecolor": */\r
874         case 33 :  /* "xtruecolour":  boolean indicating if the frame buffer\r
875                       configuration's X visual is of type TrueColor */\r
876 #if TARGET_HOST_POSIX_X11\r
877 #endif\r
878             break ;\r
879 \r
880         case 28 :  /* "xdirectcolor": */\r
881         case 34 :  /* "xdirectcolour":  boolean indicating if the frame buffer\r
882                       configuration's X visual is of type DirectColor */\r
883 #if TARGET_HOST_POSIX_X11\r
884 #endif\r
885             break ;\r
886 \r
887         case 35 :  /* "borderless":  windows should not have borders */\r
888 #if TARGET_HOST_POSIX_X11\r
889 #endif\r
890             break ;\r
891 \r
892         case 36 :  /* "aux":  some number of aux buffers */\r
893             glut_state_flag |= GLUT_AUX;\r
894             break ;\r
895 \r
896         case 37 :  /* Unrecognized */\r
897             fgWarning ( "WARNING - Display string token not recognized:  %s",\r
898                         token );\r
899             break ;\r
900         }\r
901 \r
902         token = strtok ( NULL, " \t" );\r
903     }\r
904 \r
905     free ( buffer );\r
906 \r
907     /* We will make use of this value when creating a new OpenGL context... */\r
908     fgState.DisplayMode = glut_state_flag;\r
909 }\r
910 \r
911 /* -- SETTING OPENGL 3.0 CONTEXT CREATION PARAMETERS ---------------------- */\r
912 \r
913 void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion )\r
914 {\r
915     /* We will make use of these valuse when creating a new OpenGL context... */\r
916     fgState.MajorVersion = majorVersion;\r
917     fgState.MinorVersion = minorVersion;\r
918 }\r
919 \r
920 \r
921 void FGAPIENTRY glutInitContextFlags( int flags )\r
922 {\r
923     /* We will make use of this value when creating a new OpenGL context... */\r
924     fgState.ContextFlags = flags;\r
925 }\r
926 \r
927 void FGAPIENTRY glutInitContextProfile( int profile )\r
928 {\r
929     /* We will make use of this value when creating a new OpenGL context... */\r
930     fgState.ContextProfile = profile;\r
931 }\r
932 \r
933 /* -------------- User Defined Error/Warning Handler Support -------------- */\r
934 \r
935 /*\r
936  * Sets the user error handler (note the use of va_list for the args to the fmt)\r
937  */\r
938 void FGAPIENTRY glutInitErrorFunc( void (* vfgError) ( const char *fmt, va_list ap ) )\r
939 {\r
940     /* This allows user programs to handle freeglut errors */\r
941     fgState.ErrorFunc = vfgError;\r
942 }\r
943 \r
944 /*\r
945  * Sets the user warning handler (note the use of va_list for the args to the fmt)\r
946  */\r
947 void FGAPIENTRY glutInitWarningFunc( void (* vfgWarning) ( const char *fmt, va_list ap ) )\r
948 {\r
949     /* This allows user programs to handle freeglut warnings */\r
950     fgState.WarningFunc = vfgWarning;\r
951 }\r
952 \r
953 /*** END OF FILE ***/\r