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