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