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