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