Changing a bunch of platform-specific "fgDisplay" fields to "fgDisplay.pDisplay"...
[freeglut] / src / Common / freeglut_window.c
1 /*\r
2  * freeglut_window.c\r
3  *\r
4  * Window management methods.\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: Fri Dec 3 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 #include <unistd.h>  /* usleep */\r
35 #endif\r
36 \r
37 #if defined(_WIN32_WCE)\r
38 #   include <Aygshell.h>\r
39 #   ifdef FREEGLUT_LIB_PRAGMAS\r
40 #       pragma comment( lib, "Aygshell.lib" )\r
41 #   endif\r
42 #endif /* defined(_WIN32_WCE) */\r
43 \r
44 \r
45 #if TARGET_HOST_POSIX_X11\r
46 #ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB\r
47 #define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2\r
48 #endif\r
49 \r
50 #ifndef GLX_CONTEXT_MAJOR_VERSION_ARB\r
51 #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091\r
52 #endif\r
53 \r
54 #ifndef GLX_CONTEXT_MINOR_VERSION_ARB\r
55 #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092\r
56 #endif\r
57 \r
58 #ifndef GLX_CONTEXT_FLAGS_ARB\r
59 #define GLX_CONTEXT_FLAGS_ARB 0x2094\r
60 #endif\r
61 \r
62 #ifndef GLX_CONTEXT_PROFILE_MASK_ARB\r
63 #define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126\r
64 #endif\r
65 \r
66 #ifndef GLX_CONTEXT_DEBUG_BIT_ARB\r
67 #define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001\r
68 #endif\r
69 \r
70 #ifndef GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB\r
71 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002\r
72 #endif\r
73 \r
74 #ifndef GLX_CONTEXT_CORE_PROFILE_BIT_ARB\r
75 #define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001\r
76 #endif\r
77 \r
78 #ifndef GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB\r
79 #define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002\r
80 #endif\r
81 \r
82 #ifndef GLX_RGBA_FLOAT_TYPE\r
83 #define GLX_RGBA_FLOAT_TYPE 0x20B9\r
84 #endif\r
85 \r
86 #ifndef GLX_RGBA_FLOAT_BIT\r
87 #define GLX_RGBA_FLOAT_BIT 0x00000004\r
88 #endif\r
89 #endif  /* TARGET_HOST_POSIX_X11 */\r
90 \r
91 \r
92 /* pushing attribute/value pairs into an array */\r
93 #define ATTRIB(a) attributes[where++]=(a)\r
94 #define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);}\r
95 \r
96 /*\r
97  * TODO BEFORE THE STABLE RELEASE:\r
98  *\r
99  *  fgChooseFBConfig()      -- OK, but what about glutInitDisplayString()?\r
100  *  fgSetupPixelFormat      -- ignores the display mode settings\r
101  *  fgOpenWindow()          -- check the Win32 version, -iconic handling!\r
102  *  fgCloseWindow()         -- check the Win32 version\r
103  *  glutCreateWindow()      -- Check when default position and size is {-1,-1}\r
104  *  glutCreateSubWindow()   -- Check when default position and size is {-1,-1}\r
105  *  glutDestroyWindow()     -- check the Win32 version\r
106  *  glutSetWindow()         -- check the Win32 version\r
107  *  glutGetWindow()         -- OK\r
108  *  glutSetWindowTitle()    -- check the Win32 version\r
109  *  glutSetIconTitle()      -- check the Win32 version\r
110  *  glutShowWindow()        -- check the Win32 version\r
111  *  glutHideWindow()        -- check the Win32 version\r
112  *  glutIconifyWindow()     -- check the Win32 version\r
113  *  glutReshapeWindow()     -- check the Win32 version\r
114  *  glutPositionWindow()    -- check the Win32 version\r
115  *  glutPushWindow()        -- check the Win32 version\r
116  *  glutPopWindow()         -- check the Win32 version\r
117  */\r
118 \r
119 \r
120 extern void fgPlatformSetWindow ( SFG_Window *window );\r
121 extern void fgPlatformOpenWindow( SFG_Window* window, const char* title,\r
122                                   GLboolean positionUse, int x, int y,\r
123                                   GLboolean sizeUse, int w, int h,\r
124                                   GLboolean gameMode, GLboolean isSubWindow );\r
125 extern void fgPlatformCloseWindow( SFG_Window* window );\r
126 extern void fgPlatformGlutShowWindow( void );\r
127 extern void fgPlatformGlutHideWindow( void );\r
128 extern void fgPlatformGlutIconifyWindow( void );\r
129 extern void fgPlatformGlutSetWindowTitle( const char* title );\r
130 extern void fgPlatformGlutSetIconTitle( const char* title );\r
131 extern void fgPlatformGlutPositionWindow( int x, int y );\r
132 extern void fgPlatformGlutPushWindow( void );\r
133 extern void fgPlatformGlutPopWindow( void );\r
134 extern void fgPlatformGlutFullScreen( SFG_Window *win );\r
135 extern void fgPlatformGlutLeaveFullScreen( SFG_Window *win );\r
136 extern void fgPlatformGlutFullScreenToggle( SFG_Window *win );\r
137 \r
138 \r
139 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */\r
140 \r
141 int fghIsLegacyContextVersionRequested( void )\r
142 {\r
143   return fgState.MajorVersion < 2 || (fgState.MajorVersion == 2 && fgState.MinorVersion <= 1);\r
144 }\r
145 \r
146 int fghIsLegacyContextRequested( void )\r
147 {\r
148   return fghIsLegacyContextVersionRequested() &&\r
149          fgState.ContextFlags == 0 &&\r
150          fgState.ContextProfile == 0;\r
151 }\r
152 \r
153 int fghNumberOfAuxBuffersRequested( void )\r
154 {\r
155   if ( fgState.DisplayMode & GLUT_AUX4 ) {\r
156     return 4;\r
157   }\r
158   if ( fgState.DisplayMode & GLUT_AUX3 ) {\r
159     return 3;\r
160   }\r
161   if ( fgState.DisplayMode & GLUT_AUX2 ) {\r
162     return 2;\r
163   }\r
164   if ( fgState.DisplayMode & GLUT_AUX1 ) { /* NOTE: Same as GLUT_AUX! */\r
165     return fgState.AuxiliaryBufferNumber;\r
166   }\r
167   return 0;\r
168 }\r
169 \r
170 int fghMapBit( int mask, int from, int to )\r
171 {\r
172   return ( mask & from ) ? to : 0;\r
173 \r
174 }\r
175 \r
176 void fghContextCreationError( void )\r
177 {\r
178     fgError( "Unable to create OpenGL %d.%d context (flags %x, profile %x)",\r
179              fgState.MajorVersion, fgState.MinorVersion, fgState.ContextFlags,\r
180              fgState.ContextProfile );\r
181 }\r
182 \r
183 \r
184 /* -- SYSTEM-DEPENDENT PRIVATE FUNCTIONS ------------------------------------ */\r
185 \r
186 #if TARGET_HOST_POSIX_X11\r
187 /*\r
188  * Chooses a visual basing on the current display mode settings\r
189  */\r
190 \r
191 GLXFBConfig* fgChooseFBConfig( int *numcfgs )\r
192 {\r
193   GLboolean wantIndexedMode = GL_FALSE;\r
194   int attributes[ 100 ];\r
195   int where = 0, numAuxBuffers;\r
196 \r
197   /* First we have to process the display mode settings... */\r
198   if( fgState.DisplayMode & GLUT_INDEX ) {\r
199     ATTRIB_VAL( GLX_BUFFER_SIZE, 8 );\r
200     /*  Buffer size is selected later.  */\r
201 \r
202     ATTRIB_VAL( GLX_RENDER_TYPE, GLX_COLOR_INDEX_BIT );\r
203     wantIndexedMode = GL_TRUE;\r
204   } else {\r
205     ATTRIB_VAL( GLX_RED_SIZE,   1 );\r
206     ATTRIB_VAL( GLX_GREEN_SIZE, 1 );\r
207     ATTRIB_VAL( GLX_BLUE_SIZE,  1 );\r
208     if( fgState.DisplayMode & GLUT_ALPHA ) {\r
209       ATTRIB_VAL( GLX_ALPHA_SIZE, 1 );\r
210     }\r
211   }\r
212 \r
213   if( fgState.DisplayMode & GLUT_DOUBLE ) {\r
214     ATTRIB_VAL( GLX_DOUBLEBUFFER, True );\r
215   }\r
216 \r
217   if( fgState.DisplayMode & GLUT_STEREO ) {\r
218     ATTRIB_VAL( GLX_STEREO, True );\r
219   }\r
220 \r
221   if( fgState.DisplayMode & GLUT_DEPTH ) {\r
222     ATTRIB_VAL( GLX_DEPTH_SIZE, 1 );\r
223   }\r
224 \r
225   if( fgState.DisplayMode & GLUT_STENCIL ) {\r
226     ATTRIB_VAL( GLX_STENCIL_SIZE, 1 );\r
227   }\r
228 \r
229   if( fgState.DisplayMode & GLUT_ACCUM ) {\r
230     ATTRIB_VAL( GLX_ACCUM_RED_SIZE, 1 );\r
231     ATTRIB_VAL( GLX_ACCUM_GREEN_SIZE, 1 );\r
232     ATTRIB_VAL( GLX_ACCUM_BLUE_SIZE, 1 );\r
233     if( fgState.DisplayMode & GLUT_ALPHA ) {\r
234       ATTRIB_VAL( GLX_ACCUM_ALPHA_SIZE, 1 );\r
235     }\r
236   }\r
237 \r
238   numAuxBuffers = fghNumberOfAuxBuffersRequested();\r
239   if ( numAuxBuffers > 0 ) {\r
240     ATTRIB_VAL( GLX_AUX_BUFFERS, numAuxBuffers );\r
241   }\r
242 \r
243   if( fgState.DisplayMode & GLUT_SRGB ) {\r
244     ATTRIB_VAL( GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, True );\r
245   }\r
246 \r
247   if (fgState.DisplayMode & GLUT_MULTISAMPLE) {\r
248     ATTRIB_VAL(GLX_SAMPLE_BUFFERS, 1);\r
249     ATTRIB_VAL(GLX_SAMPLES, fgState.SampleNumber);\r
250   }\r
251 \r
252   /* Push a terminator at the end of the list */\r
253   ATTRIB( None );\r
254 \r
255     {\r
256         GLXFBConfig * fbconfigArray;  /*  Array of FBConfigs  */\r
257         GLXFBConfig * fbconfig;       /*  The FBConfig we want  */\r
258         int fbconfigArraySize;        /*  Number of FBConfigs in the array  */\r
259 \r
260 \r
261         /*  Get all FBConfigs that match "attributes".  */\r
262         fbconfigArray = glXChooseFBConfig( fgDisplay.pDisplay.Display,\r
263                                            fgDisplay.pDisplay.Screen,\r
264                                            attributes,\r
265                                            &fbconfigArraySize );\r
266 \r
267         if (fbconfigArray != NULL)\r
268         {\r
269             int result;  /* Returned by glXGetFBConfigAttrib, not checked. */\r
270 \r
271 \r
272             if( wantIndexedMode )\r
273             {\r
274                 /*\r
275                  * In index mode, we want the largest buffer size, i.e. visual\r
276                  * depth.  Here, FBConfigs are sorted by increasing buffer size\r
277                  * first, so FBConfigs with the largest size come last.\r
278                  */\r
279 \r
280                 int bufferSizeMin, bufferSizeMax;\r
281 \r
282                 /*  Get bufferSizeMin.  */\r
283                 result =\r
284                   glXGetFBConfigAttrib( fgDisplay.pDisplay.Display,\r
285                                         fbconfigArray[0],\r
286                                         GLX_BUFFER_SIZE,\r
287                                         &bufferSizeMin );\r
288                 /*  Get bufferSizeMax.  */\r
289                 result =\r
290                   glXGetFBConfigAttrib( fgDisplay.pDisplay.Display,\r
291                                         fbconfigArray[fbconfigArraySize - 1],\r
292                                         GLX_BUFFER_SIZE,\r
293                                         &bufferSizeMax );\r
294 \r
295                 if (bufferSizeMax > bufferSizeMin)\r
296                 {\r
297                     /* \r
298                      * Free and reallocate fbconfigArray, keeping only FBConfigs\r
299                      * with the largest buffer size.\r
300                      */\r
301                     XFree(fbconfigArray);\r
302 \r
303                     /*  Add buffer size token at the end of the list.  */\r
304                     where--;\r
305                     ATTRIB_VAL( GLX_BUFFER_SIZE, bufferSizeMax );\r
306                     ATTRIB( None );\r
307 \r
308                     fbconfigArray = glXChooseFBConfig( fgDisplay.pDisplay.Display,\r
309                                                        fgDisplay.Screen,\r
310                                                        attributes,\r
311                                                        &fbconfigArraySize );\r
312                 }\r
313             }\r
314 \r
315             /*\r
316              * We now have an array of FBConfigs, the first one being the "best"\r
317              * one.  So we should return only this FBConfig:\r
318              *\r
319              * int fbconfigXID;\r
320              *\r
321              *  - pick the XID of the FBConfig we want\r
322              * result = glXGetFBConfigAttrib( fgDisplay.pDisplay.Display,\r
323              *                                fbconfigArray[0],\r
324              *                                GLX_FBCONFIG_ID,\r
325              *                                &fbconfigXID );\r
326              *\r
327              * - free the array\r
328              * XFree(fbconfigArray);\r
329              *\r
330              * - reset "attributes" with the XID\r
331              * where = 0;\r
332              * ATTRIB_VAL( GLX_FBCONFIG_ID, fbconfigXID );\r
333              * ATTRIB( None );\r
334              *\r
335              * - get our FBConfig only\r
336              * fbconfig = glXChooseFBConfig( fgDisplay.pDisplay.Display,\r
337              *                               fgDisplay.pDisplay.Screen,\r
338              *                               attributes,\r
339              *                               &fbconfigArraySize );\r
340              *\r
341              * However, for some configurations (for instance multisampling with\r
342              * Mesa 6.5.2 and ATI drivers), this does not work:\r
343              * glXChooseFBConfig returns NULL, whereas fbconfigXID is a valid\r
344              * XID.  Further investigation is needed.\r
345              *\r
346              * So, for now, we return the whole array of FBConfigs.  This should\r
347              * not produce any side effects elsewhere.\r
348              */\r
349             fbconfig = fbconfigArray;\r
350         }\r
351         else\r
352         {\r
353            fbconfig = NULL;\r
354         }\r
355 \r
356         if (numcfgs)\r
357                 *numcfgs = fbconfigArraySize;\r
358 \r
359         return fbconfig;\r
360     }\r
361 }\r
362 \r
363 \r
364 static void fghFillContextAttributes( int *attributes ) {\r
365   int where = 0, contextFlags, contextProfile;\r
366 \r
367   if ( !fghIsLegacyContextVersionRequested() ) {\r
368     ATTRIB_VAL( GLX_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion );\r
369     ATTRIB_VAL( GLX_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion );\r
370   }\r
371 \r
372   contextFlags =\r
373     fghMapBit( fgState.ContextFlags, GLUT_DEBUG, GLX_CONTEXT_DEBUG_BIT_ARB ) |\r
374     fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB );\r
375   if ( contextFlags != 0 ) {\r
376     ATTRIB_VAL( GLX_CONTEXT_FLAGS_ARB, contextFlags );\r
377   }\r
378 \r
379   contextProfile =\r
380     fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB ) |\r
381     fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB );\r
382   if ( contextProfile != 0 ) {\r
383     ATTRIB_VAL( GLX_CONTEXT_PROFILE_MASK_ARB, contextProfile );\r
384   }\r
385 \r
386   ATTRIB( 0 );\r
387 }\r
388 \r
389 typedef GLXContext (*CreateContextAttribsProc)(Display *dpy, GLXFBConfig config,\r
390                                                GLXContext share_list, Bool direct,\r
391                                                const int *attrib_list);\r
392 \r
393 static GLXContext fghCreateNewContext( SFG_Window* window )\r
394 {\r
395   /* for color model calculation */\r
396   int menu = ( window->IsMenu && !fgStructure.MenuContext );\r
397   int index_mode = ( fgState.DisplayMode & GLUT_INDEX );\r
398 \r
399   /* "classic" context creation */\r
400   Display *dpy = fgDisplay.pDisplay.Display;\r
401   GLXFBConfig config = *(window->Window.pContext.FBConfig);\r
402   int render_type = ( !menu && index_mode ) ? GLX_COLOR_INDEX_TYPE : GLX_RGBA_TYPE;\r
403   GLXContext share_list = NULL;\r
404   Bool direct = ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT );\r
405   GLXContext context;\r
406 \r
407   /* new context creation */\r
408   int attributes[9];\r
409   CreateContextAttribsProc createContextAttribs = (CreateContextAttribsProc) fghGetProcAddress( "glXCreateContextAttribsARB" );\r
410  \r
411   /* glXCreateContextAttribsARB not found, yet the user has requested the new context creation */\r
412   if ( !createContextAttribs && !fghIsLegacyContextRequested() ) {\r
413     fgWarning( "OpenGL >2.1 context requested but glXCreateContextAttribsARB is not available! Falling back to legacy context creation" );\r
414         fgState.MajorVersion = 2;\r
415         fgState.MinorVersion = 1;\r
416   }\r
417 \r
418   /* If nothing fancy has been required, simply use the old context creation GLX API entry */\r
419   if ( fghIsLegacyContextRequested() || !createContextAttribs )\r
420   {\r
421     context = glXCreateNewContext( dpy, config, render_type, share_list, direct );\r
422     if ( context == NULL ) {\r
423       fghContextCreationError();\r
424     }\r
425     return context;\r
426   }\r
427 \r
428   /* color index mode is not available anymore with OpenGL 3.0 */\r
429   if ( render_type == GLX_COLOR_INDEX_TYPE ) {\r
430     fgWarning( "color index mode is deprecated, using RGBA mode" );\r
431   }\r
432 \r
433   fghFillContextAttributes( attributes );\r
434 \r
435   context = createContextAttribs( dpy, config, share_list, direct, attributes );\r
436   if ( context == NULL ) {\r
437     fghContextCreationError();\r
438   }\r
439   return context;\r
440 }\r
441 \r
442 \r
443 #define _NET_WM_STATE_TOGGLE    2\r
444 static int fghResizeFullscrToggle(void)\r
445 {\r
446     XWindowAttributes attributes;\r
447 \r
448     if(glutGet(GLUT_FULL_SCREEN)) {\r
449         /* restore original window size */\r
450         SFG_Window *win = fgStructure.CurrentWindow;\r
451         fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE;\r
452         fgStructure.CurrentWindow->State.Width  = win->State.pWState.OldWidth;\r
453         fgStructure.CurrentWindow->State.Height = win->State.pWState.OldHeight;\r
454 \r
455     } else {\r
456         /* resize the window to cover the entire screen */\r
457         XGetWindowAttributes(fgDisplay.pDisplay.Display,\r
458                 fgStructure.CurrentWindow->Window.Handle,\r
459                 &attributes);\r
460         \r
461         /*\r
462          * The "x" and "y" members of "attributes" are the window's coordinates\r
463          * relative to its parent, i.e. to the decoration window.\r
464          */\r
465         XMoveResizeWindow(fgDisplay.pDisplay.Display,\r
466                 fgStructure.CurrentWindow->Window.Handle,\r
467                 -attributes.x,\r
468                 -attributes.y,\r
469                 fgDisplay.ScreenWidth,\r
470                 fgDisplay.ScreenHeight);\r
471     }\r
472     return 0;\r
473 }\r
474 \r
475 static int fghEwmhFullscrToggle(void)\r
476 {\r
477     XEvent xev;\r
478     long evmask = SubstructureRedirectMask | SubstructureNotifyMask;\r
479 \r
480     if(!fgDisplay.State || !fgDisplay.StateFullScreen) {\r
481         return -1;\r
482     }\r
483 \r
484     xev.type = ClientMessage;\r
485     xev.xclient.window = fgStructure.CurrentWindow->Window.Handle;\r
486     xev.xclient.message_type = fgDisplay.State;\r
487     xev.xclient.format = 32;\r
488     xev.xclient.data.l[0] = _NET_WM_STATE_TOGGLE;\r
489     xev.xclient.data.l[1] = fgDisplay.StateFullScreen;\r
490     xev.xclient.data.l[2] = 0;  /* no second property to toggle */\r
491     xev.xclient.data.l[3] = 1;  /* source indication: application */\r
492     xev.xclient.data.l[4] = 0;  /* unused */\r
493 \r
494     if(!XSendEvent(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.RootWindow, 0, evmask, &xev)) {\r
495         return -1;\r
496     }\r
497     return 0;\r
498 }\r
499 \r
500 static int fghToggleFullscreen(void)\r
501 {\r
502     /* first try the EWMH (_NET_WM_STATE) method ... */\r
503     if(fghEwmhFullscrToggle() != -1) {\r
504         return 0;\r
505     }\r
506 \r
507     /* fall back to resizing the window */\r
508     if(fghResizeFullscrToggle() != -1) {\r
509         return 0;\r
510     }\r
511     return -1;\r
512 }\r
513 \r
514 void fgPlatformSetWindow ( SFG_Window *window )\r
515 {\r
516     if ( window )\r
517     {\r
518         glXMakeContextCurrent(\r
519             fgDisplay.pDisplay.Display,\r
520             window->Window.Handle,\r
521             window->Window.Handle,\r
522             window->Window.Context\r
523         );\r
524     }\r
525 }\r
526 \r
527 \r
528 /*\r
529  * Opens a window. Requires a SFG_Window object created and attached\r
530  * to the freeglut structure. OpenGL context is created here.\r
531  */\r
532 void fgPlatformOpenWindow( SFG_Window* window, const char* title,\r
533                            GLboolean positionUse, int x, int y,\r
534                            GLboolean sizeUse, int w, int h,\r
535                            GLboolean gameMode, GLboolean isSubWindow )\r
536 {\r
537     XVisualInfo * visualInfo = NULL;\r
538     XSetWindowAttributes winAttr;\r
539     XTextProperty textProperty;\r
540     XSizeHints sizeHints;\r
541     XWMHints wmHints;\r
542     XEvent eventReturnBuffer; /* return buffer required for a call */\r
543     unsigned long mask;\r
544     int num_FBConfigs, i;\r
545     unsigned int current_DisplayMode = fgState.DisplayMode ;\r
546 \r
547     /* Save the display mode if we are creating a menu window */\r
548     if( window->IsMenu && ( ! fgStructure.MenuContext ) )\r
549         fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ;\r
550 \r
551     window->Window.pContext.FBConfig = fgChooseFBConfig( &num_FBConfigs );\r
552 \r
553     if( window->IsMenu && ( ! fgStructure.MenuContext ) )\r
554         fgState.DisplayMode = current_DisplayMode ;\r
555 \r
556     if( ! window->Window.pContext.FBConfig )\r
557     {\r
558         /*\r
559          * The "fgChooseFBConfig" returned a null meaning that the visual\r
560          * context is not available.\r
561          * Try a couple of variations to see if they will work.\r
562          */\r
563         if( !( fgState.DisplayMode & GLUT_DOUBLE ) )\r
564         {\r
565             fgState.DisplayMode |= GLUT_DOUBLE ;\r
566             window->Window.pContext.FBConfig = fgChooseFBConfig( &num_FBConfigs );\r
567             fgState.DisplayMode &= ~GLUT_DOUBLE;\r
568         }\r
569 \r
570         if( fgState.DisplayMode & GLUT_MULTISAMPLE )\r
571         {\r
572             fgState.DisplayMode &= ~GLUT_MULTISAMPLE ;\r
573             window->Window.pContext.FBConfig = fgChooseFBConfig( &num_FBConfigs );\r
574             fgState.DisplayMode |= GLUT_MULTISAMPLE;\r
575         }\r
576     }\r
577 \r
578     FREEGLUT_INTERNAL_ERROR_EXIT( window->Window.pContext.FBConfig != NULL,\r
579                                   "FBConfig with necessary capabilities not found", "fgOpenWindow" );\r
580 \r
581     /*  Get the X visual.  */\r
582     for (i = 0; i < num_FBConfigs; i++) {\r
583             visualInfo = glXGetVisualFromFBConfig( fgDisplay.pDisplay.Display,\r
584                                                    window->Window.pContext.FBConfig[i] );\r
585             if (visualInfo)\r
586                 break;\r
587     }\r
588 \r
589     FREEGLUT_INTERNAL_ERROR_EXIT( visualInfo != NULL,\r
590                                   "visualInfo could not be retrieved from FBConfig", "fgOpenWindow" );\r
591 \r
592     /*\r
593      * XXX HINT: the masks should be updated when adding/removing callbacks.\r
594      * XXX       This might speed up message processing. Is that true?\r
595      * XXX\r
596      * XXX A: Not appreciably, but it WILL make it easier to debug.\r
597      * XXX    Try tracing old GLUT and try tracing freeglut.  Old GLUT\r
598      * XXX    turns off events that it doesn't need and is a whole lot\r
599      * XXX    more pleasant to trace.  (Think mouse-motion!  Tons of\r
600      * XXX    ``bonus'' GUI events stream in.)\r
601      */\r
602     winAttr.event_mask        =\r
603         StructureNotifyMask | SubstructureNotifyMask | ExposureMask |\r
604         ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |\r
605         VisibilityChangeMask | EnterWindowMask | LeaveWindowMask |\r
606         PointerMotionMask | ButtonMotionMask;\r
607     winAttr.background_pixmap = None;\r
608     winAttr.background_pixel  = 0;\r
609     winAttr.border_pixel      = 0;\r
610 \r
611     winAttr.colormap = XCreateColormap(\r
612         fgDisplay.pDisplay.Display, fgDisplay.pDisplay.RootWindow,\r
613         visualInfo->visual, AllocNone\r
614     );\r
615 \r
616     mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;\r
617 \r
618     if( window->IsMenu || ( gameMode == GL_TRUE ) )\r
619     {\r
620         winAttr.override_redirect = True;\r
621         mask |= CWOverrideRedirect;\r
622     }\r
623 \r
624     if( ! positionUse )\r
625         x = y = -1; /* default window position */\r
626     if( ! sizeUse )\r
627         w = h = 300; /* default window size */\r
628 \r
629     window->Window.Handle = XCreateWindow(\r
630         fgDisplay.pDisplay.Display,\r
631         window->Parent == NULL ? fgDisplay.pDisplay.RootWindow :\r
632         window->Parent->Window.Handle,\r
633         x, y, w, h, 0,\r
634         visualInfo->depth, InputOutput,\r
635         visualInfo->visual, mask,\r
636         &winAttr\r
637     );\r
638 \r
639     /*\r
640      * The GLX context creation, possibly trying the direct context rendering\r
641      *  or else use the current context if the user has so specified\r
642      */\r
643 \r
644     if( window->IsMenu )\r
645     {\r
646         /*\r
647          * If there isn't already an OpenGL rendering context for menu\r
648          * windows, make one\r
649          */\r
650         if( !fgStructure.MenuContext )\r
651         {\r
652             fgStructure.MenuContext =\r
653                 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );\r
654             fgStructure.MenuContext->MContext = fghCreateNewContext( window );\r
655         }\r
656 \r
657         /* window->Window.Context = fgStructure.MenuContext->MContext; */\r
658         window->Window.Context = fghCreateNewContext( window );\r
659     }\r
660     else if( fgState.UseCurrentContext )\r
661     {\r
662         window->Window.Context = glXGetCurrentContext( );\r
663 \r
664         if( ! window->Window.Context )\r
665             window->Window.Context = fghCreateNewContext( window );\r
666     }\r
667     else\r
668         window->Window.Context = fghCreateNewContext( window );\r
669 \r
670 #if !defined( __FreeBSD__ ) && !defined( __NetBSD__ )\r
671     if(  !glXIsDirect( fgDisplay.pDisplay.Display, window->Window.Context ) )\r
672     {\r
673       if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT )\r
674         fgError( "Unable to force direct context rendering for window '%s'",\r
675                  title );\r
676     }\r
677 #endif\r
678 \r
679     /*\r
680      * XXX Assume the new window is visible by default\r
681      * XXX Is this a  safe assumption?\r
682      */\r
683     window->State.Visible = GL_TRUE;\r
684 \r
685     sizeHints.flags = 0;\r
686     if ( positionUse )\r
687         sizeHints.flags |= USPosition;\r
688     if ( sizeUse )\r
689         sizeHints.flags |= USSize;\r
690 \r
691     /*\r
692      * Fill in the size hints values now (the x, y, width and height\r
693      * settings are obsolete, are there any more WMs that support them?)\r
694      * Unless the X servers actually stop supporting these, we should\r
695      * continue to fill them in.  It is *not* our place to tell the user\r
696      * that they should replace a window manager that they like, and which\r
697      * works, just because *we* think that it's not "modern" enough.\r
698      */\r
699     sizeHints.x      = x;\r
700     sizeHints.y      = y;\r
701     sizeHints.width  = w;\r
702     sizeHints.height = h;\r
703 \r
704     wmHints.flags = StateHint;\r
705     wmHints.initial_state = fgState.ForceIconic ? IconicState : NormalState;\r
706     /* Prepare the window and iconified window names... */\r
707     XStringListToTextProperty( (char **) &title, 1, &textProperty );\r
708 \r
709     XSetWMProperties(\r
710         fgDisplay.pDisplay.Display,\r
711         window->Window.Handle,\r
712         &textProperty,\r
713         &textProperty,\r
714         0,\r
715         0,\r
716         &sizeHints,\r
717         &wmHints,\r
718         NULL\r
719     );\r
720     XFree( textProperty.value );\r
721 \r
722     XSetWMProtocols( fgDisplay.pDisplay.Display, window->Window.Handle,\r
723                      &fgDisplay.pDisplay.DeleteWindow, 1 );\r
724 \r
725     glXMakeContextCurrent(\r
726         fgDisplay.pDisplay.Display,\r
727         window->Window.Handle,\r
728         window->Window.Handle,\r
729         window->Window.Context\r
730     );\r
731 \r
732     /* register extension events _before_ window is mapped */\r
733     #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H\r
734        fgRegisterDevices( fgDisplay.pDisplay.Display, &(window->Window.Handle) );\r
735     #endif\r
736 \r
737     XMapWindow( fgDisplay.pDisplay.Display, window->Window.Handle );\r
738 \r
739     XFree(visualInfo);\r
740 \r
741     if( !isSubWindow)\r
742         XPeekIfEvent( fgDisplay.pDisplay.Display, &eventReturnBuffer, &fghWindowIsVisible, (XPointer)(window->Window.Handle) );\r
743 }\r
744 \r
745 \r
746 /*\r
747  * Closes a window, destroying the frame and OpenGL context\r
748  */\r
749 void fgPlatformCloseWindow( SFG_Window* window )\r
750 {\r
751     if( window->Window.Context )\r
752         glXDestroyContext( fgDisplay.pDisplay.Display, window->Window.Context );\r
753     XFree( window->Window.pContext.FBConfig );\r
754 \r
755     if( window->Window.Handle ) {\r
756         XDestroyWindow( fgDisplay.pDisplay.Display, window->Window.Handle );\r
757     }\r
758     /* XFlush( fgDisplay.pDisplay.Display ); */ /* XXX Shouldn't need this */\r
759 }\r
760 \r
761 \r
762 static Bool fghWindowIsVisible( Display *display, XEvent *event, XPointer arg)\r
763 {\r
764     Window window = (Window)arg;\r
765     return (event->type == MapNotify) && (event->xmap.window == window);\r
766 }\r
767 \r
768 \r
769 \r
770 \r
771 /*\r
772  * This function makes the current window visible\r
773  */\r
774 void fgPlatformGlutShowWindow( void )\r
775 {\r
776     XMapWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle );\r
777     XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */\r
778 }\r
779 \r
780 /*\r
781  * This function hides the current window\r
782  */\r
783 void fgPlatformGlutHideWindow( void )\r
784 {\r
785     if( fgStructure.CurrentWindow->Parent == NULL )\r
786         XWithdrawWindow( fgDisplay.pDisplay.Display,\r
787                          fgStructure.CurrentWindow->Window.Handle,\r
788                          fgDisplay.pDisplay.Screen );\r
789     else\r
790         XUnmapWindow( fgDisplay.pDisplay.Display,\r
791                       fgStructure.CurrentWindow->Window.Handle );\r
792     XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */\r
793 }\r
794 \r
795 /*\r
796  * Iconify the current window (top-level windows only)\r
797  */\r
798 void fgPlatformGlutIconifyWindow( void )\r
799 {\r
800     XIconifyWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle,\r
801                     fgDisplay.pDisplay.Screen );\r
802     XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */\r
803 }\r
804 \r
805 /*\r
806  * Set the current window's title\r
807  */\r
808 void fgPlatformGlutSetWindowTitle( const char* title )\r
809 {\r
810     XTextProperty text;\r
811 \r
812     text.value = (unsigned char *) title;\r
813     text.encoding = XA_STRING;\r
814     text.format = 8;\r
815     text.nitems = strlen( title );\r
816 \r
817     XSetWMName(\r
818         fgDisplay.pDisplay.Display,\r
819         fgStructure.CurrentWindow->Window.Handle,\r
820         &text\r
821     );\r
822 \r
823     XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */\r
824 }\r
825 \r
826 /*\r
827  * Set the current window's iconified title\r
828  */\r
829 void fgPlatformGlutSetIconTitle( const char* title )\r
830 {\r
831     XTextProperty text;\r
832 \r
833     text.value = (unsigned char *) title;\r
834     text.encoding = XA_STRING;\r
835     text.format = 8;\r
836     text.nitems = strlen( title );\r
837 \r
838     XSetWMIconName(\r
839         fgDisplay.pDisplay.Display,\r
840         fgStructure.CurrentWindow->Window.Handle,\r
841         &text\r
842     );\r
843 \r
844     XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */\r
845 }\r
846 \r
847 /*\r
848  * Change the current window's position\r
849  */\r
850 void fgPlatformGlutPositionWindow( int x, int y )\r
851 {\r
852     XMoveWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle,\r
853                  x, y );\r
854     XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */\r
855 }\r
856 \r
857 /*\r
858  * Lowers the current window (by Z order change)\r
859  */\r
860 void fgPlatformGlutPushWindow( void )\r
861 {\r
862     XLowerWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle );\r
863 }\r
864 \r
865 /*\r
866  * Raises the current window (by Z order change)\r
867  */\r
868 void fgPlatformGlutPopWindow( void )\r
869 {\r
870     XRaiseWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle );\r
871 }\r
872 \r
873 /*\r
874  * Resize the current window so that it fits the whole screen\r
875  */\r
876 void fgPlatformGlutFullScreen( SFG_Window *win )\r
877 {\r
878     if(!glutGet(GLUT_FULL_SCREEN)) {\r
879         if(fghToggleFullscreen() != -1) {\r
880             win->State.IsFullscreen = GL_TRUE;\r
881         }\r
882     }\r
883 }\r
884 \r
885 /*\r
886  * If we are fullscreen, resize the current window back to its original size\r
887  */\r
888 void fgPlatformGlutLeaveFullScreen( SFG_Window *win )\r
889 {\r
890     if(glutGet(GLUT_FULL_SCREEN)) {\r
891         if(fghToggleFullscreen() != -1) {\r
892             win->State.IsFullscreen = GL_FALSE;\r
893         }\r
894     }\r
895 }\r
896 \r
897 /*\r
898  * Toggle the window's full screen state.\r
899  */\r
900 void fgPlatformGlutFullScreenToggle( SFG_Window *win )\r
901 {\r
902     if(fghToggleFullscreen() != -1) {\r
903         win->State.IsFullscreen = !win->State.IsFullscreen;\r
904     }\r
905 }\r
906 \r
907 \r
908 \r
909 #endif  /* TARGET_HOST_POSIX_X11 */\r
910 \r
911 \r
912 /*\r
913  * Sets the OpenGL context and the fgStructure "Current Window" pointer to\r
914  * the window structure passed in.\r
915  */\r
916 void fgSetWindow ( SFG_Window *window )\r
917 {\r
918         fgPlatformSetWindow ( window );\r
919 \r
920     fgStructure.CurrentWindow = window;\r
921 }\r
922 \r
923 \r
924 \r
925 \r
926 /*\r
927  * Opens a window. Requires a SFG_Window object created and attached\r
928  * to the freeglut structure. OpenGL context is created here.\r
929  */\r
930 void fgOpenWindow( SFG_Window* window, const char* title,\r
931                    GLboolean positionUse, int x, int y,\r
932                    GLboolean sizeUse, int w, int h,\r
933                    GLboolean gameMode, GLboolean isSubWindow )\r
934 {\r
935         fgPlatformOpenWindow( window, title,\r
936                    positionUse, x, y,\r
937                    sizeUse, w, h,\r
938                    gameMode, isSubWindow );\r
939 \r
940     fgSetWindow( window );\r
941 \r
942     window->Window.DoubleBuffered =\r
943         ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0;\r
944 \r
945     if ( ! window->Window.DoubleBuffered )\r
946     {\r
947         glDrawBuffer ( GL_FRONT );\r
948         glReadBuffer ( GL_FRONT );\r
949     }\r
950 }\r
951 \r
952 /*\r
953  * Closes a window, destroying the frame and OpenGL context\r
954  */\r
955 void fgCloseWindow( SFG_Window* window )\r
956 {\r
957     /* if we're in gamemode and we're closing the gamemode window,\r
958      * call glutLeaveGameMode first to make sure the gamemode is\r
959      * properly closed before closing the window\r
960      */\r
961     if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==window->ID)\r
962         glutLeaveGameMode();\r
963 \r
964         fgPlatformCloseWindow ( window );\r
965 }\r
966 \r
967 \r
968 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */\r
969 \r
970 /*\r
971  * Creates a new top-level freeglut window\r
972  */\r
973 int FGAPIENTRY glutCreateWindow( const char* title )\r
974 {\r
975     /* XXX GLUT does not exit; it simply calls "glutInit" quietly if the\r
976      * XXX application has not already done so.  The "freeglut" community\r
977      * XXX decided not to go this route (freeglut-developer e-mail from\r
978      * XXX Steve Baker, 12/16/04, 4:22 PM CST, "Re: [Freeglut-developer]\r
979      * XXX Desired 'freeglut' behaviour when there is no current window"\r
980      */\r
981     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateWindow" );\r
982 \r
983     return fgCreateWindow( NULL, title, fgState.Position.Use,\r
984                            fgState.Position.X, fgState.Position.Y,\r
985                            fgState.Size.Use, fgState.Size.X, fgState.Size.Y,\r
986                            GL_FALSE, GL_FALSE )->ID;\r
987 }\r
988 \r
989 /*\r
990  * This function creates a sub window.\r
991  */\r
992 int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h )\r
993 {\r
994     int ret = 0;\r
995     SFG_Window* window = NULL;\r
996     SFG_Window* parent = NULL;\r
997 \r
998     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateSubWindow" );\r
999     parent = fgWindowByID( parentID );\r
1000     freeglut_return_val_if_fail( parent != NULL, 0 );\r
1001     if ( x < 0 )\r
1002     {\r
1003         x = parent->State.Width + x ;\r
1004         if ( w >= 0 ) x -= w ;\r
1005     }\r
1006 \r
1007     if ( w < 0 ) w = parent->State.Width - x + w ;\r
1008     if ( w < 0 )\r
1009     {\r
1010         x += w ;\r
1011         w = -w ;\r
1012     }\r
1013 \r
1014     if ( y < 0 )\r
1015     {\r
1016         y = parent->State.Height + y ;\r
1017         if ( h >= 0 ) y -= h ;\r
1018     }\r
1019 \r
1020     if ( h < 0 ) h = parent->State.Height - y + h ;\r
1021     if ( h < 0 )\r
1022     {\r
1023         y += h ;\r
1024         h = -h ;\r
1025     }\r
1026 \r
1027     window = fgCreateWindow( parent, "", GL_TRUE, x, y, GL_TRUE, w, h, GL_FALSE, GL_FALSE );\r
1028     ret = window->ID;\r
1029 \r
1030     return ret;\r
1031 }\r
1032 \r
1033 /*\r
1034  * Destroys a window and all of its subwindows\r
1035  */\r
1036 void FGAPIENTRY glutDestroyWindow( int windowID )\r
1037 {\r
1038     SFG_Window* window;\r
1039     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyWindow" );\r
1040     window = fgWindowByID( windowID );\r
1041     freeglut_return_if_fail( window != NULL );\r
1042     {\r
1043         fgExecutionState ExecState = fgState.ExecState;\r
1044         fgAddToWindowDestroyList( window );\r
1045         fgState.ExecState = ExecState;\r
1046     }\r
1047 }\r
1048 \r
1049 /*\r
1050  * This function selects the current window\r
1051  */\r
1052 void FGAPIENTRY glutSetWindow( int ID )\r
1053 {\r
1054     SFG_Window* window = NULL;\r
1055 \r
1056     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindow" );\r
1057     if( fgStructure.CurrentWindow != NULL )\r
1058         if( fgStructure.CurrentWindow->ID == ID )\r
1059             return;\r
1060 \r
1061     window = fgWindowByID( ID );\r
1062     if( window == NULL )\r
1063     {\r
1064         fgWarning( "glutSetWindow(): window ID %d not found!", ID );\r
1065         return;\r
1066     }\r
1067 \r
1068     fgSetWindow( window );\r
1069 }\r
1070 \r
1071 /*\r
1072  * This function returns the ID number of the current window, 0 if none exists\r
1073  */\r
1074 int FGAPIENTRY glutGetWindow( void )\r
1075 {\r
1076     SFG_Window *win = fgStructure.CurrentWindow;\r
1077     /*\r
1078      * Since GLUT did not throw an error if this function was called without a prior call to\r
1079      * "glutInit", this function shouldn't do so here.  Instead let us return a zero.\r
1080      * See Feature Request "[ 1307049 ] glutInit check".\r
1081      */\r
1082     if ( ! fgState.Initialised )\r
1083         return 0;\r
1084 \r
1085     while ( win && win->IsMenu )\r
1086         win = win->Parent;\r
1087     return win ? win->ID : 0;\r
1088 }\r
1089 \r
1090 /*\r
1091  * This function makes the current window visible\r
1092  */\r
1093 void FGAPIENTRY glutShowWindow( void )\r
1094 {\r
1095     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutShowWindow" );\r
1096     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutShowWindow" );\r
1097 \r
1098         fgPlatformGlutShowWindow ();\r
1099 \r
1100     fgStructure.CurrentWindow->State.Redisplay = GL_TRUE;\r
1101 }\r
1102 \r
1103 /*\r
1104  * This function hides the current window\r
1105  */\r
1106 void FGAPIENTRY glutHideWindow( void )\r
1107 {\r
1108     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutHideWindow" );\r
1109     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutHideWindow" );\r
1110 \r
1111         fgPlatformGlutHideWindow ();\r
1112 \r
1113     fgStructure.CurrentWindow->State.Redisplay = GL_FALSE;\r
1114 }\r
1115 \r
1116 /*\r
1117  * Iconify the current window (top-level windows only)\r
1118  */\r
1119 void FGAPIENTRY glutIconifyWindow( void )\r
1120 {\r
1121     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIconifyWindow" );\r
1122     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIconifyWindow" );\r
1123 \r
1124     fgStructure.CurrentWindow->State.Visible   = GL_FALSE;\r
1125 \r
1126         fgPlatformGlutIconifyWindow ();\r
1127 \r
1128     fgStructure.CurrentWindow->State.Redisplay = GL_FALSE;\r
1129 }\r
1130 \r
1131 /*\r
1132  * Set the current window's title\r
1133  */\r
1134 void FGAPIENTRY glutSetWindowTitle( const char* title )\r
1135 {\r
1136     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowTitle" );\r
1137     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowTitle" );\r
1138     if( ! fgStructure.CurrentWindow->Parent )\r
1139     {\r
1140                 fgPlatformGlutSetWindowTitle ( title );\r
1141     }\r
1142 }\r
1143 \r
1144 /*\r
1145  * Set the current window's iconified title\r
1146  */\r
1147 void FGAPIENTRY glutSetIconTitle( const char* title )\r
1148 {\r
1149     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetIconTitle" );\r
1150     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetIconTitle" );\r
1151 \r
1152     if( ! fgStructure.CurrentWindow->Parent )\r
1153     {\r
1154                 fgPlatformGlutSetIconTitle ( title );\r
1155     }\r
1156 }\r
1157 \r
1158 /*\r
1159  * Change the current window's size\r
1160  */\r
1161 void FGAPIENTRY glutReshapeWindow( int width, int height )\r
1162 {\r
1163     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" );\r
1164     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" );\r
1165 \r
1166     if (glutGet(GLUT_FULL_SCREEN))\r
1167     {\r
1168       /*  Leave full screen state before resizing. */\r
1169       glutLeaveFullScreen();\r
1170     }\r
1171 \r
1172     fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE;\r
1173     fgStructure.CurrentWindow->State.Width  = width ;\r
1174     fgStructure.CurrentWindow->State.Height = height;\r
1175 }\r
1176 \r
1177 /*\r
1178  * Change the current window's position\r
1179  */\r
1180 void FGAPIENTRY glutPositionWindow( int x, int y )\r
1181 {\r
1182     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" );\r
1183     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" );\r
1184 \r
1185     if (glutGet(GLUT_FULL_SCREEN))\r
1186     {\r
1187       /*  Leave full screen state before moving. */\r
1188       glutLeaveFullScreen();\r
1189     }\r
1190 \r
1191         fgPlatformGlutPositionWindow ( x, y );\r
1192 }\r
1193 \r
1194 /*\r
1195  * Lowers the current window (by Z order change)\r
1196  */\r
1197 void FGAPIENTRY glutPushWindow( void )\r
1198 {\r
1199     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" );\r
1200     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" );\r
1201 \r
1202         fgPlatformGlutPushWindow ();\r
1203 }\r
1204 \r
1205 /*\r
1206  * Raises the current window (by Z order change)\r
1207  */\r
1208 void FGAPIENTRY glutPopWindow( void )\r
1209 {\r
1210     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" );\r
1211     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" );\r
1212 \r
1213         fgPlatformGlutPopWindow ();\r
1214 }\r
1215 \r
1216 /*\r
1217  * Resize the current window so that it fits the whole screen\r
1218  */\r
1219 void FGAPIENTRY glutFullScreen( void )\r
1220 {\r
1221     SFG_Window *win;\r
1222 \r
1223     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );\r
1224     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );\r
1225 \r
1226     win = fgStructure.CurrentWindow;\r
1227 \r
1228     if (win->Parent)\r
1229     {\r
1230         /* Child windows cannot be made fullscreen, consistent with GLUT's behavior\r
1231          * Also, what would it mean for a child window to be fullscreen, given that it\r
1232          * is confined to its parent?\r
1233          */\r
1234         fgWarning("glutFullScreen called on a child window, ignoring...");\r
1235         return;\r
1236     }\r
1237     else if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==win->ID)\r
1238     {\r
1239         /* Ignore fullscreen call on GameMode window, those are always fullscreen already */\r
1240         return;\r
1241     }\r
1242 \r
1243         fgPlatformGlutFullScreen ( win );\r
1244 }\r
1245 \r
1246 /*\r
1247  * If we are fullscreen, resize the current window back to its original size\r
1248  */\r
1249 void FGAPIENTRY glutLeaveFullScreen( void )\r
1250 {\r
1251     SFG_Window *win;\r
1252 \r
1253     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );\r
1254     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );\r
1255 \r
1256     win = fgStructure.CurrentWindow;\r
1257 \r
1258         fgPlatformGlutLeaveFullScreen ( win );\r
1259 }\r
1260 \r
1261 /*\r
1262  * Toggle the window's full screen state.\r
1263  */\r
1264 void FGAPIENTRY glutFullScreenToggle( void )\r
1265 {\r
1266     SFG_Window *win;\r
1267 \r
1268     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" );\r
1269     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" );\r
1270 \r
1271     win = fgStructure.CurrentWindow;\r
1272 \r
1273         fgPlatformGlutFullScreenToggle ( win );\r
1274 }\r
1275 \r
1276 /*\r
1277  * A.Donev: Set and retrieve the window's user data\r
1278  */\r
1279 void* FGAPIENTRY glutGetWindowData( void )\r
1280 {\r
1281     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" );\r
1282     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" );\r
1283     return fgStructure.CurrentWindow->UserData;\r
1284 }\r
1285 \r
1286 void FGAPIENTRY glutSetWindowData(void* data)\r
1287 {\r
1288     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" );\r
1289     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" );\r
1290     fgStructure.CurrentWindow->UserData = data;\r
1291 }\r
1292 \r
1293 /*** END OF FILE ***/\r