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