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