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