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