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