a5884ae94b5c8b9849c3e94ed258cfebdeb301f1
[freeglut] / src / freeglut_window.c
1 /*
2  * freeglut_window.c
3  *
4  * Window management methods.
5  *
6  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7  * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8  * Creation date: Fri Dec 3 1999
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  */
27
28 #define FREEGLUT_BUILDING_LIB
29 #include <GL/freeglut.h>
30 #include "freeglut_internal.h"
31
32 #if TARGET_HOST_POSIX_X11
33 #include <limits.h>  /* LONG_MAX */
34 #include <unistd.h>  /* usleep */
35 #endif
36
37 #if defined(_WIN32_WCE)
38 #   include <Aygshell.h>
39 #   ifdef FREEGLUT_LIB_PRAGMAS
40 #       pragma comment( lib, "Aygshell.lib" )
41 #   endif
42 #endif /* defined(_WIN32_WCE) */
43
44
45 #if TARGET_HOST_POSIX_X11
46 #ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB
47 #define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2
48 #endif
49
50 #ifndef GLX_CONTEXT_MAJOR_VERSION_ARB
51 #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
52 #endif
53
54 #ifndef GLX_CONTEXT_MINOR_VERSION_ARB
55 #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
56 #endif
57
58 #ifndef GLX_CONTEXT_FLAGS_ARB
59 #define GLX_CONTEXT_FLAGS_ARB 0x2094
60 #endif
61
62 #ifndef GLX_CONTEXT_PROFILE_MASK_ARB
63 #define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
64 #endif
65
66 #ifndef GLX_CONTEXT_DEBUG_BIT_ARB
67 #define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001
68 #endif
69
70 #ifndef GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
71 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
72 #endif
73
74 #ifndef GLX_CONTEXT_CORE_PROFILE_BIT_ARB
75 #define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
76 #endif
77
78 #ifndef GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
79 #define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
80 #endif
81
82 #ifndef GLX_RGBA_FLOAT_TYPE
83 #define GLX_RGBA_FLOAT_TYPE 0x20B9
84 #endif
85
86 #ifndef GLX_RGBA_FLOAT_BIT
87 #define GLX_RGBA_FLOAT_BIT 0x00000004
88 #endif
89 #endif  /* TARGET_HOST_POSIX_X11 */
90
91
92 #if TARGET_HOST_MS_WINDOWS
93 /* The following include file is available from SGI but is not standard:
94  *   #include <GL/wglext.h>
95  * So we copy the necessary parts out of it.
96  * XXX: should local definitions for extensions be put in a separate include file?
97  */
98 typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc);
99
100 typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
101
102 #define WGL_DRAW_TO_WINDOW_ARB         0x2001
103 #define WGL_ACCELERATION_ARB           0x2003
104 #define WGL_SUPPORT_OPENGL_ARB         0x2010
105 #define WGL_DOUBLE_BUFFER_ARB          0x2011
106 #define WGL_COLOR_BITS_ARB             0x2014
107 #define WGL_ALPHA_BITS_ARB             0x201B
108 #define WGL_DEPTH_BITS_ARB             0x2022
109 #define WGL_STENCIL_BITS_ARB           0x2023
110 #define WGL_FULL_ACCELERATION_ARB      0x2027
111
112 #define WGL_SAMPLE_BUFFERS_ARB         0x2041
113 #define WGL_SAMPLES_ARB                0x2042
114
115 #define WGL_TYPE_RGBA_FLOAT_ARB        0x21A0
116
117 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9
118
119 #ifndef WGL_ARB_create_context
120 #define WGL_ARB_create_context 1
121 #ifdef WGL_WGLEXT_PROTOTYPES
122 extern HGLRC WINAPI wglCreateContextAttribsARB (HDC, HGLRC, const int *);
123 #endif /* WGL_WGLEXT_PROTOTYPES */
124 typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList);
125
126 #define WGL_CONTEXT_MAJOR_VERSION_ARB  0x2091
127 #define WGL_CONTEXT_MINOR_VERSION_ARB  0x2092
128 #define WGL_CONTEXT_LAYER_PLANE_ARB    0x2093
129 #define WGL_CONTEXT_FLAGS_ARB          0x2094
130 #define WGL_CONTEXT_PROFILE_MASK_ARB   0x9126
131
132 #define WGL_CONTEXT_DEBUG_BIT_ARB      0x0001
133 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
134
135 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
136 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
137
138 #define ERROR_INVALID_VERSION_ARB      0x2095
139 #define ERROR_INVALID_PROFILE_ARB      0x2096
140 #endif
141
142 #endif  /* TARGET_HOST_MS_WINDOWS */
143
144 #ifdef WM_TOUCH
145         typedef BOOL (WINAPI *pRegisterTouchWindow)(HWND,ULONG);
146    static pRegisterTouchWindow fghRegisterTouchWindow = (pRegisterTouchWindow)0xDEADBEEF;
147 #endif
148
149 /* pushing attribute/value pairs into an array */
150 #define ATTRIB(a) attributes[where++]=(a)
151 #define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);}
152
153 /*
154  * TODO BEFORE THE STABLE RELEASE:
155  *
156  *  fgChooseFBConfig()      -- OK, but what about glutInitDisplayString()?
157  *  fgSetupPixelFormat      -- ignores the display mode settings
158  *  fgOpenWindow()          -- check the Win32 version, -iconic handling!
159  *  fgCloseWindow()         -- check the Win32 version
160  *  glutCreateWindow()      -- Check when default position and size is {-1,-1}
161  *  glutCreateSubWindow()   -- Check when default position and size is {-1,-1}
162  *  glutDestroyWindow()     -- check the Win32 version
163  *  glutSetWindow()         -- check the Win32 version
164  *  glutGetWindow()         -- OK
165  *  glutSetWindowTitle()    -- check the Win32 version
166  *  glutSetIconTitle()      -- check the Win32 version
167  *  glutShowWindow()        -- check the Win32 version
168  *  glutHideWindow()        -- check the Win32 version
169  *  glutIconifyWindow()     -- check the Win32 version
170  *  glutReshapeWindow()     -- check the Win32 version
171  *  glutPositionWindow()    -- check the Win32 version
172  *  glutPushWindow()        -- check the Win32 version
173  *  glutPopWindow()         -- check the Win32 version
174  */
175
176 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
177
178 static int fghIsLegacyContextVersionRequested( void )
179 {
180   return fgState.MajorVersion == 1 && fgState.MinorVersion == 0;
181 }
182
183 static int fghIsLegacyContextRequested( void )
184 {
185   return fghIsLegacyContextVersionRequested() &&
186          fgState.ContextFlags == 0 &&
187          fgState.ContextProfile == 0;
188 }
189
190 static int fghNumberOfAuxBuffersRequested( void )
191 {
192   if ( fgState.DisplayMode & GLUT_AUX4 ) {
193     return 4;
194   }
195   if ( fgState.DisplayMode & GLUT_AUX3 ) {
196     return 3;
197   }
198   if ( fgState.DisplayMode & GLUT_AUX2 ) {
199     return 2;
200   }
201   if ( fgState.DisplayMode & GLUT_AUX1 ) { /* NOTE: Same as GLUT_AUX! */
202     return fgState.AuxiliaryBufferNumber;
203   }
204   return 0;
205 }
206
207 static int fghMapBit( int mask, int from, int to )
208 {
209   return ( mask & from ) ? to : 0;
210
211 }
212
213 static void fghContextCreationError( void )
214 {
215     fgError( "Unable to create OpenGL %d.%d context (flags %x, profile %x)",
216              fgState.MajorVersion, fgState.MinorVersion, fgState.ContextFlags,
217              fgState.ContextProfile );
218 }
219
220
221 /* -- SYSTEM-DEPENDENT PRIVATE FUNCTIONS ------------------------------------ */
222
223 #if TARGET_HOST_POSIX_X11
224 /*
225  * Chooses a visual basing on the current display mode settings
226  */
227
228 GLXFBConfig* fgChooseFBConfig( int *numcfgs )
229 {
230   GLboolean wantIndexedMode = GL_FALSE;
231   int attributes[ 100 ];
232   int where = 0, numAuxBuffers;
233
234   /* First we have to process the display mode settings... */
235   if( fgState.DisplayMode & GLUT_INDEX ) {
236     ATTRIB_VAL( GLX_BUFFER_SIZE, 8 );
237     /*  Buffer size is selected later.  */
238
239     ATTRIB_VAL( GLX_RENDER_TYPE, GLX_COLOR_INDEX_BIT );
240     wantIndexedMode = GL_TRUE;
241   } else {
242     ATTRIB_VAL( GLX_RED_SIZE,   1 );
243     ATTRIB_VAL( GLX_GREEN_SIZE, 1 );
244     ATTRIB_VAL( GLX_BLUE_SIZE,  1 );
245     if( fgState.DisplayMode & GLUT_ALPHA ) {
246       ATTRIB_VAL( GLX_ALPHA_SIZE, 1 );
247     }
248   }
249
250   if( fgState.DisplayMode & GLUT_DOUBLE ) {
251     ATTRIB_VAL( GLX_DOUBLEBUFFER, True );
252   }
253
254   if( fgState.DisplayMode & GLUT_STEREO ) {
255     ATTRIB_VAL( GLX_STEREO, True );
256   }
257
258   if( fgState.DisplayMode & GLUT_DEPTH ) {
259     ATTRIB_VAL( GLX_DEPTH_SIZE, 1 );
260   }
261
262   if( fgState.DisplayMode & GLUT_STENCIL ) {
263     ATTRIB_VAL( GLX_STENCIL_SIZE, 1 );
264   }
265
266   if( fgState.DisplayMode & GLUT_ACCUM ) {
267     ATTRIB_VAL( GLX_ACCUM_RED_SIZE, 1 );
268     ATTRIB_VAL( GLX_ACCUM_GREEN_SIZE, 1 );
269     ATTRIB_VAL( GLX_ACCUM_BLUE_SIZE, 1 );
270     if( fgState.DisplayMode & GLUT_ALPHA ) {
271       ATTRIB_VAL( GLX_ACCUM_ALPHA_SIZE, 1 );
272     }
273   }
274
275   numAuxBuffers = fghNumberOfAuxBuffersRequested();
276   if ( numAuxBuffers > 0 ) {
277     ATTRIB_VAL( GLX_AUX_BUFFERS, numAuxBuffers );
278   }
279
280   if( fgState.DisplayMode & GLUT_SRGB ) {
281     ATTRIB_VAL( GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, True );
282   }
283
284   if (fgState.DisplayMode & GLUT_MULTISAMPLE) {
285     ATTRIB_VAL(GLX_SAMPLE_BUFFERS, 1);
286     ATTRIB_VAL(GLX_SAMPLES, fgState.SampleNumber);
287   }
288
289   /* Push a terminator at the end of the list */
290   ATTRIB( None );
291
292     {
293         GLXFBConfig * fbconfigArray;  /*  Array of FBConfigs  */
294         GLXFBConfig * fbconfig;       /*  The FBConfig we want  */
295         int fbconfigArraySize;        /*  Number of FBConfigs in the array  */
296
297
298         /*  Get all FBConfigs that match "attributes".  */
299         fbconfigArray = glXChooseFBConfig( fgDisplay.Display,
300                                            fgDisplay.Screen,
301                                            attributes,
302                                            &fbconfigArraySize );
303
304         if (fbconfigArray != NULL)
305         {
306             int result;  /* Returned by glXGetFBConfigAttrib, not checked. */
307
308
309             if( wantIndexedMode )
310             {
311                 /*
312                  * In index mode, we want the largest buffer size, i.e. visual
313                  * depth.  Here, FBConfigs are sorted by increasing buffer size
314                  * first, so FBConfigs with the largest size come last.
315                  */
316
317                 int bufferSizeMin, bufferSizeMax;
318
319                 /*  Get bufferSizeMin.  */
320                 result =
321                   glXGetFBConfigAttrib( fgDisplay.Display,
322                                         fbconfigArray[0],
323                                         GLX_BUFFER_SIZE,
324                                         &bufferSizeMin );
325                 /*  Get bufferSizeMax.  */
326                 result =
327                   glXGetFBConfigAttrib( fgDisplay.Display,
328                                         fbconfigArray[fbconfigArraySize - 1],
329                                         GLX_BUFFER_SIZE,
330                                         &bufferSizeMax );
331
332                 if (bufferSizeMax > bufferSizeMin)
333                 {
334                     /* 
335                      * Free and reallocate fbconfigArray, keeping only FBConfigs
336                      * with the largest buffer size.
337                      */
338                     XFree(fbconfigArray);
339
340                     /*  Add buffer size token at the end of the list.  */
341                     where--;
342                     ATTRIB_VAL( GLX_BUFFER_SIZE, bufferSizeMax );
343                     ATTRIB( None );
344
345                     fbconfigArray = glXChooseFBConfig( fgDisplay.Display,
346                                                        fgDisplay.Screen,
347                                                        attributes,
348                                                        &fbconfigArraySize );
349                 }
350             }
351
352             /*
353              * We now have an array of FBConfigs, the first one being the "best"
354              * one.  So we should return only this FBConfig:
355              *
356              * int fbconfigXID;
357              *
358              *  - pick the XID of the FBConfig we want
359              * result = glXGetFBConfigAttrib( fgDisplay.Display,
360              *                                fbconfigArray[0],
361              *                                GLX_FBCONFIG_ID,
362              *                                &fbconfigXID );
363              *
364              * - free the array
365              * XFree(fbconfigArray);
366              *
367              * - reset "attributes" with the XID
368              * where = 0;
369              * ATTRIB_VAL( GLX_FBCONFIG_ID, fbconfigXID );
370              * ATTRIB( None );
371              *
372              * - get our FBConfig only
373              * fbconfig = glXChooseFBConfig( fgDisplay.Display,
374              *                               fgDisplay.Screen,
375              *                               attributes,
376              *                               &fbconfigArraySize );
377              *
378              * However, for some configurations (for instance multisampling with
379              * Mesa 6.5.2 and ATI drivers), this does not work:
380              * glXChooseFBConfig returns NULL, whereas fbconfigXID is a valid
381              * XID.  Further investigation is needed.
382              *
383              * So, for now, we return the whole array of FBConfigs.  This should
384              * not produce any side effects elsewhere.
385              */
386             fbconfig = fbconfigArray;
387         }
388         else
389         {
390            fbconfig = NULL;
391         }
392
393         if (numcfgs)
394                 *numcfgs = fbconfigArraySize;
395
396         return fbconfig;
397     }
398 }
399
400
401 static void fghFillContextAttributes( int *attributes ) {
402   int where = 0, contextFlags, contextProfile;
403
404   if ( !fghIsLegacyContextVersionRequested() ) {
405     ATTRIB_VAL( GLX_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion );
406     ATTRIB_VAL( GLX_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion );
407   }
408
409   contextFlags =
410     fghMapBit( fgState.ContextFlags, GLUT_DEBUG, GLX_CONTEXT_DEBUG_BIT_ARB ) |
411     fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB );
412   if ( contextFlags != 0 ) {
413     ATTRIB_VAL( GLX_CONTEXT_FLAGS_ARB, contextFlags );
414   }
415
416   contextProfile =
417     fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB ) |
418     fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB );
419   if ( contextProfile != 0 ) {
420     ATTRIB_VAL( GLX_CONTEXT_PROFILE_MASK_ARB, contextProfile );
421   }
422
423   ATTRIB( 0 );
424 }
425
426 typedef GLXContext (*CreateContextAttribsProc)(Display *dpy, GLXFBConfig config,
427                                                GLXContext share_list, Bool direct,
428                                                const int *attrib_list);
429
430 static GLXContext fghCreateNewContext( SFG_Window* window )
431 {
432   /* for color model calculation */
433   int menu = ( window->IsMenu && !fgStructure.MenuContext );
434   int index_mode = ( fgState.DisplayMode & GLUT_INDEX );
435
436   /* "classic" context creation */
437   Display *dpy = fgDisplay.Display;
438   GLXFBConfig config = *(window->Window.FBConfig);
439   int render_type = ( !menu && index_mode ) ? GLX_COLOR_INDEX_TYPE : GLX_RGBA_TYPE;
440   GLXContext share_list = NULL;
441   Bool direct = ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT );
442   GLXContext context;
443
444   /* new context creation */
445   int attributes[9];
446   CreateContextAttribsProc createContextAttribs;
447
448   /* If nothing fancy has been required, simply use the old context creation GLX API entry */
449   if ( fghIsLegacyContextRequested() )
450   {
451     context = glXCreateNewContext( dpy, config, render_type, share_list, direct );
452     if ( context == NULL ) {
453       fghContextCreationError();
454     }
455     return context;
456   }
457
458   /* color index mode is not available anymore with OpenGL 3.0 */
459   if ( render_type == GLX_COLOR_INDEX_TYPE ) {
460     fgWarning( "color index mode is deprecated, using RGBA mode" );
461   }
462
463   fghFillContextAttributes( attributes );
464
465   createContextAttribs = (CreateContextAttribsProc) fghGetProcAddress( "glXCreateContextAttribsARB" );
466   if ( createContextAttribs == NULL ) {
467     fgError( "glXCreateContextAttribsARB not found" );
468   }
469
470   context = createContextAttribs( dpy, config, share_list, direct, attributes );
471   if ( context == NULL ) {
472     fghContextCreationError();
473   }
474   return context;
475 }
476
477
478 #define _NET_WM_STATE_TOGGLE    2
479 static int fghResizeFullscrToggle(void)
480 {
481     XWindowAttributes attributes;
482
483     if(glutGet(GLUT_FULL_SCREEN)) {
484         /* restore original window size */
485         SFG_Window *win = fgStructure.CurrentWindow;
486         fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE;
487         fgStructure.CurrentWindow->State.Width  = win->State.OldWidth;
488         fgStructure.CurrentWindow->State.Height = win->State.OldHeight;
489
490     } else {
491         /* resize the window to cover the entire screen */
492         XGetWindowAttributes(fgDisplay.Display,
493                 fgStructure.CurrentWindow->Window.Handle,
494                 &attributes);
495         
496         /*
497          * The "x" and "y" members of "attributes" are the window's coordinates
498          * relative to its parent, i.e. to the decoration window.
499          */
500         XMoveResizeWindow(fgDisplay.Display,
501                 fgStructure.CurrentWindow->Window.Handle,
502                 -attributes.x,
503                 -attributes.y,
504                 fgDisplay.ScreenWidth,
505                 fgDisplay.ScreenHeight);
506     }
507     return 0;
508 }
509
510 static int fghEwmhFullscrToggle(void)
511 {
512     XEvent xev;
513     long evmask = SubstructureRedirectMask | SubstructureNotifyMask;
514
515     if(!fgDisplay.State || !fgDisplay.StateFullScreen) {
516         return -1;
517     }
518
519     xev.type = ClientMessage;
520     xev.xclient.window = fgStructure.CurrentWindow->Window.Handle;
521     xev.xclient.message_type = fgDisplay.State;
522     xev.xclient.format = 32;
523     xev.xclient.data.l[0] = _NET_WM_STATE_TOGGLE;
524     xev.xclient.data.l[1] = fgDisplay.StateFullScreen;
525     xev.xclient.data.l[2] = 0;  /* no second property to toggle */
526     xev.xclient.data.l[3] = 1;  /* source indication: application */
527     xev.xclient.data.l[4] = 0;  /* unused */
528
529     if(!XSendEvent(fgDisplay.Display, fgDisplay.RootWindow, 0, evmask, &xev)) {
530         return -1;
531     }
532     return 0;
533 }
534
535 static int fghToggleFullscreen(void)
536 {
537     /* first try the EWMH (_NET_WM_STATE) method ... */
538     if(fghEwmhFullscrToggle() != -1) {
539         return 0;
540     }
541
542     /* fall back to resizing the window */
543     if(fghResizeFullscrToggle() != -1) {
544         return 0;
545     }
546     return -1;
547 }
548
549
550 #endif  /* TARGET_HOST_POSIX_X11 */
551
552
553 #if TARGET_HOST_MS_WINDOWS
554 /*
555  * Setup the pixel format for a Win32 window
556  */
557
558 #if defined(_WIN32_WCE)
559 static wchar_t* fghWstrFromStr(const char* str)
560 {
561     int i,len=strlen(str);
562     wchar_t* wstr = (wchar_t*)malloc(2*len+2);
563     for(i=0; i<len; i++)
564         wstr[i] = str[i];
565     wstr[len] = 0;
566     return wstr;
567 }
568 #endif /* defined(_WIN32_WCE) */
569
570
571 static void fghFillContextAttributes( int *attributes ) {
572   int where = 0, contextFlags, contextProfile;
573
574   if ( !fghIsLegacyContextVersionRequested() ) {
575     ATTRIB_VAL( WGL_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion );
576     ATTRIB_VAL( WGL_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion );
577   }
578
579   contextFlags =
580     fghMapBit( fgState.ContextFlags, GLUT_DEBUG, WGL_CONTEXT_DEBUG_BIT_ARB ) |
581     fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB );
582   if ( contextFlags != 0 ) {
583     ATTRIB_VAL( WGL_CONTEXT_FLAGS_ARB, contextFlags );
584   }
585
586   contextProfile =
587     fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, WGL_CONTEXT_CORE_PROFILE_BIT_ARB ) |
588     fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB );
589   if ( contextProfile != 0 ) {
590     ATTRIB_VAL( WGL_CONTEXT_PROFILE_MASK_ARB, contextProfile );
591   }
592
593   ATTRIB( 0 );
594 }
595
596 static int fghIsExtensionSupported( HDC hdc, const char *extension ) {
597     const char *pWglExtString;
598     PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetEntensionsStringARB =
599       (PFNWGLGETEXTENSIONSSTRINGARBPROC) wglGetProcAddress("wglGetExtensionsStringARB");
600     if ( wglGetEntensionsStringARB == NULL )
601     {
602       return FALSE;
603     }
604     pWglExtString = wglGetEntensionsStringARB( hdc );
605     return ( pWglExtString != NULL ) && ( strstr(pWglExtString, extension) != NULL );
606 }
607
608 void fgNewWGLCreateContext( SFG_Window* window )
609 {
610     HGLRC context;
611     int attributes[9];
612     PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
613
614     /* If nothing fancy has been required, leave the context as it is */
615     if ( fghIsLegacyContextRequested() )
616     {
617         return;
618     }
619
620     wglMakeCurrent( window->Window.Device, window->Window.Context );
621
622     if ( !fghIsExtensionSupported( window->Window.Device, "WGL_ARB_create_context" ) )
623     {
624         return;
625     }
626
627     /* new context creation */
628     fghFillContextAttributes( attributes );
629
630     wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress( "wglCreateContextAttribsARB" );
631     if ( wglCreateContextAttribsARB == NULL )
632     {
633         fgError( "wglCreateContextAttribsARB not found" );
634     }
635
636     context = wglCreateContextAttribsARB( window->Window.Device, 0, attributes );
637     if ( context == NULL )
638     {
639         fghContextCreationError();
640     }
641
642     wglMakeCurrent( NULL, NULL );
643     wglDeleteContext( window->Window.Context );
644     window->Window.Context = context;
645 }
646
647 #if !defined(_WIN32_WCE)
648
649 static void fghFillPFD( PIXELFORMATDESCRIPTOR *ppfd, HDC hdc, unsigned char layer_type )
650 {
651   int flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
652   if ( fgState.DisplayMode & GLUT_DOUBLE ) {
653         flags |= PFD_DOUBLEBUFFER;
654   }
655   if ( fgState.DisplayMode & GLUT_STEREO ) {
656     flags |= PFD_STEREO;
657   }
658
659 #if defined(_MSC_VER)
660 #pragma message( "fgSetupPixelFormat(): there is still some work to do here!" )
661 #endif
662
663   /* Specify which pixel format do we opt for... */
664   ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
665   ppfd->nVersion = 1;
666   ppfd->dwFlags = flags;
667
668   if( fgState.DisplayMode & GLUT_INDEX ) {
669     ppfd->iPixelType = PFD_TYPE_COLORINDEX;
670     ppfd->cRedBits = 0;
671     ppfd->cGreenBits = 0;
672     ppfd->cBlueBits = 0;
673     ppfd->cAlphaBits = 0;
674   } else {
675     ppfd->iPixelType = PFD_TYPE_RGBA;
676     ppfd->cRedBits = 8;
677     ppfd->cGreenBits = 8;
678     ppfd->cBlueBits = 8;
679     ppfd->cAlphaBits = ( fgState.DisplayMode & GLUT_ALPHA ) ? 8 : 0;
680   }
681
682   ppfd->cColorBits = 24;
683   ppfd->cRedShift = 0;
684   ppfd->cGreenShift = 0;
685   ppfd->cBlueShift = 0;
686   ppfd->cAlphaShift = 0;
687   ppfd->cAccumBits = ( fgState.DisplayMode & GLUT_ACCUM ) ? 1 : 0;
688   ppfd->cAccumRedBits = 0;
689   ppfd->cAccumGreenBits = 0;
690   ppfd->cAccumBlueBits = 0;
691   ppfd->cAccumAlphaBits = 0;
692
693   /* Hmmm, or 32/0 instead of 24/8? */
694   ppfd->cDepthBits = 24;
695   ppfd->cStencilBits = 8;
696
697   ppfd->cAuxBuffers = fghNumberOfAuxBuffersRequested();
698   ppfd->iLayerType = layer_type;
699   ppfd->bReserved = 0;
700   ppfd->dwLayerMask = 0;
701   ppfd->dwVisibleMask = 0;
702   ppfd->dwDamageMask = 0;
703   
704   ppfd->cColorBits = (BYTE) GetDeviceCaps( hdc, BITSPIXEL );
705 }
706
707 static void fghFillPixelFormatAttributes( int *attributes, const PIXELFORMATDESCRIPTOR *ppfd )
708 {
709   int where = 0;
710
711   ATTRIB_VAL( WGL_DRAW_TO_WINDOW_ARB, GL_TRUE );
712   ATTRIB_VAL( WGL_SUPPORT_OPENGL_ARB, GL_TRUE );
713   ATTRIB_VAL( WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB );
714
715   ATTRIB_VAL( WGL_COLOR_BITS_ARB, ppfd->cColorBits );
716   ATTRIB_VAL( WGL_ALPHA_BITS_ARB, ppfd->cAlphaBits );
717   ATTRIB_VAL( WGL_DEPTH_BITS_ARB, ppfd->cDepthBits );
718   ATTRIB_VAL( WGL_STENCIL_BITS_ARB, ppfd->cStencilBits );
719
720   ATTRIB_VAL( WGL_DOUBLE_BUFFER_ARB, ( fgState.DisplayMode & GLUT_DOUBLE ) != 0 );
721
722   if ( fgState.DisplayMode & GLUT_SRGB ) {
723     ATTRIB_VAL( WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, TRUE );
724   }
725
726   ATTRIB_VAL( WGL_SAMPLE_BUFFERS_ARB, GL_TRUE );
727   ATTRIB_VAL( WGL_SAMPLES_ARB, fgState.SampleNumber );
728   ATTRIB( 0 );
729 }
730 #endif
731
732 GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
733                               unsigned char layer_type )
734 {
735 #if defined(_WIN32_WCE)
736     return GL_TRUE;
737 #else
738     PIXELFORMATDESCRIPTOR pfd;
739     PIXELFORMATDESCRIPTOR* ppfd = &pfd;
740     int pixelformat;
741     HDC current_hDC;
742     GLboolean success;
743
744     if (checkOnly)
745       current_hDC = CreateDC(TEXT("DISPLAY"), NULL ,NULL ,NULL);
746     else
747       current_hDC = window->Window.Device;
748
749     fghFillPFD( ppfd, current_hDC, layer_type );
750     pixelformat = ChoosePixelFormat( current_hDC, ppfd );
751
752     /* windows hack for multismapling/sRGB */
753     if ( ( fgState.DisplayMode & GLUT_MULTISAMPLE ) ||
754          ( fgState.DisplayMode & GLUT_SRGB ) )
755     {        
756         HGLRC rc, rc_before=wglGetCurrentContext();
757         HWND hWnd;
758         HDC hDC, hDC_before=wglGetCurrentDC();
759         WNDCLASS wndCls;
760
761         /* create a dummy window */
762         ZeroMemory(&wndCls, sizeof(wndCls));
763         wndCls.lpfnWndProc = DefWindowProc;
764         wndCls.hInstance = fgDisplay.Instance;
765         wndCls.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
766         wndCls.lpszClassName = _T("FREEGLUT_dummy");
767         RegisterClass( &wndCls );
768
769         hWnd=CreateWindow(_T("FREEGLUT_dummy"), _T(""), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW , 0,0,0,0, 0, 0, fgDisplay.Instance, 0 );
770         hDC=GetDC(hWnd);
771         SetPixelFormat( hDC, pixelformat, ppfd );
772
773         rc = wglCreateContext( hDC );
774         wglMakeCurrent(hDC, rc);
775
776         if ( fghIsExtensionSupported( hDC, "WGL_ARB_multisample" ) )
777         {
778             PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARBProc =
779               (PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatARB");
780             if ( wglChoosePixelFormatARBProc )
781             {
782                 int attributes[100];
783                 int iPixelFormat;
784                 BOOL bValid;
785                 float fAttributes[] = { 0, 0 };
786                 UINT numFormats;
787                 fghFillPixelFormatAttributes( attributes, ppfd );
788                 bValid = wglChoosePixelFormatARBProc(hDC, attributes, fAttributes, 1, &iPixelFormat, &numFormats);
789
790                 if ( bValid && numFormats > 0 )
791                 {
792                     pixelformat = iPixelFormat;
793                 }
794             }
795         }
796
797         wglMakeCurrent( hDC_before, rc_before);
798         wglDeleteContext(rc);
799         ReleaseDC(hWnd, hDC);
800         DestroyWindow(hWnd);
801         UnregisterClass(_T("FREEGLUT_dummy"), fgDisplay.Instance);
802     }
803
804     success = ( pixelformat != 0 ) && ( checkOnly || SetPixelFormat( current_hDC, pixelformat, ppfd ) );
805
806     if (checkOnly)
807         DeleteDC(current_hDC);
808
809     return success;
810 #endif /* defined(_WIN32_WCE) */
811 }
812
813 #endif  /* TARGET_HOST_MS_WINDOWS */
814
815 /*
816  * Sets the OpenGL context and the fgStructure "Current Window" pointer to
817  * the window structure passed in.
818  */
819 void fgSetWindow ( SFG_Window *window )
820 {
821 #if TARGET_HOST_POSIX_X11
822     if ( window )
823     {
824         glXMakeContextCurrent(
825             fgDisplay.Display,
826             window->Window.Handle,
827             window->Window.Handle,
828             window->Window.Context
829         );
830     }
831 #elif TARGET_HOST_MS_WINDOWS
832     if ( window != fgStructure.CurrentWindow )
833     {
834         if( fgStructure.CurrentWindow )
835             ReleaseDC( fgStructure.CurrentWindow->Window.Handle,
836                        fgStructure.CurrentWindow->Window.Device );
837
838         if ( window )
839         {
840             window->Window.Device = GetDC( window->Window.Handle );
841             wglMakeCurrent(
842                 window->Window.Device,
843                 window->Window.Context
844             );
845         }
846     }
847 #endif
848     fgStructure.CurrentWindow = window;
849 }
850
851 #if TARGET_HOST_MS_WINDOWS
852
853 /* Computes position of corners of window Rect (outer position including
854  * decorations) based on the provided client rect and based on the style
855  * of the window in question.
856  * If posIsOutside is set to true, the input client Rect is taken to follow
857  * freeGLUT's window specification convention in which the top-left corner
858  * is at the outside of the window, while the size
859  * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
860  * area.
861  */
862 void fghComputeWindowRectFromClientArea_UseStyle( const DWORD windowStyle, RECT *clientRect, BOOL posIsOutside )
863 {
864     int xBorderWidth = 0, yBorderWidth = 0;
865
866     /* If window has title bar, correct rect for it */
867     if (windowStyle & WS_MAXIMIZEBOX) /* Need to query for WS_MAXIMIZEBOX to see if we have a title bar, the WS_CAPTION query is also true for a WS_DLGFRAME only... */
868         if (posIsOutside)
869             clientRect->bottom += GetSystemMetrics( SM_CYCAPTION );
870         else
871             clientRect->top -= GetSystemMetrics( SM_CYCAPTION );
872
873     /* get width of window's borders (frame), correct rect for it.
874      * Note, borders can be of zero width if style does not specify borders
875      */
876     fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth);
877     if (posIsOutside)
878     {
879         clientRect->right  += xBorderWidth * 2;
880         clientRect->bottom += yBorderWidth * 2;
881     }
882     else
883     {
884         clientRect->left   -= xBorderWidth;
885         clientRect->right  += xBorderWidth;
886         clientRect->top    -= yBorderWidth;
887         clientRect->bottom += yBorderWidth;
888     }
889 }
890
891 /* Computes position of corners of window Rect (outer position including
892  * decorations) based on the provided client rect and based on the style
893  * of the window in question. If the window pointer or the window handle
894  * is NULL, a fully decorated window (caption and border) is assumed.
895  * Furthermore, if posIsOutside is set to true, the input client Rect is
896  * taken to follow freeGLUT's window specification convention in which the
897  * top-left corner is at the outside of the window, while the size
898  * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
899  * area.
900 */
901 void fghComputeWindowRectFromClientArea_QueryWindow( const SFG_Window *window, RECT *clientRect, BOOL posIsOutside )
902 {
903     DWORD windowStyle = 0;
904
905     if (window && window->Window.Handle)
906         windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE);
907     else
908         windowStyle = WS_OVERLAPPEDWINDOW;
909
910     fghComputeWindowRectFromClientArea_UseStyle(windowStyle, clientRect, posIsOutside);
911 }
912
913 /* Computes position of corners of client area (drawable area) of a window
914  * based on the provided window Rect (outer position including decorations)
915  * and based on the style of the window in question. If the window pointer
916  * or the window handle is NULL, a fully decorated window (caption and
917  * border) is assumed.
918  * Furthermore, if wantPosOutside is set to true, the output client Rect
919  * will follow freeGLUT's window specification convention in which the
920  * top-left corner is at the outside of the window, the size
921  * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
922  * area.
923  */
924 void fghComputeClientAreaFromWindowRect( const SFG_Window *window, RECT *windowRect, BOOL wantPosOutside )
925 {
926     DWORD windowStyle = 0;
927     int xBorderWidth = 0, yBorderWidth = 0;
928
929     if (window && window->Window.Handle)
930         windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE);
931     else
932         windowStyle = WS_OVERLAPPEDWINDOW;
933
934     /* If window has title bar, correct rect for it */
935     if (windowStyle & WS_MAXIMIZEBOX) /* Need to query for WS_MAXIMIZEBOX to see if we have a title bar, the WS_CAPTION query is also true for a WS_DLGFRAME only... */
936         if (wantPosOutside)
937             windowRect->bottom -= GetSystemMetrics( SM_CYCAPTION );
938         else
939             windowRect->top    += GetSystemMetrics( SM_CYCAPTION );
940
941     /* get width of window's borders (frame), correct rect for it.
942      * Note, borders can be of zero width if style does not specify borders
943      */
944     fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth);
945     if (wantPosOutside)
946     {
947         windowRect->right  -= xBorderWidth * 2;
948         windowRect->bottom -= yBorderWidth * 2;
949     }
950     else
951     {
952         windowRect->left   += xBorderWidth;
953         windowRect->right  -= xBorderWidth;
954         windowRect->top    += yBorderWidth;
955         windowRect->bottom -= yBorderWidth;
956     }
957 }
958
959 /* Gets the rect describing the client area (drawable area) of the
960  * specified window.
961  * Returns an empty rect if window pointer or window handle is NULL.
962  * If wantPosOutside is set to true, the output client Rect
963  * will follow freeGLUT's window specification convention in which the
964  * top-left corner is at the outside of the window, while the size
965  * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
966  * area.
967  */
968 RECT fghGetClientArea( const SFG_Window *window, BOOL wantPosOutside )
969 {
970     RECT windowRect = {0,0,0,0};
971
972     freeglut_return_val_if_fail((window && window->Window.Handle),windowRect);
973     
974     /*
975      * call GetWindowRect()
976      * (this returns the pixel coordinates of the outside of the window)
977      */
978     GetWindowRect( window->Window.Handle, &windowRect );
979
980     /* Then correct the results */
981     fghComputeClientAreaFromWindowRect(window, &windowRect, wantPosOutside);
982
983     return windowRect;
984 }
985
986 /* Returns the width of the window borders based on the window's style.
987  */
988 void fghGetBorderWidth(const DWORD windowStyle, int* xBorderWidth, int* yBorderWidth)
989 {
990     if (windowStyle & WS_THICKFRAME)
991     {
992         *xBorderWidth = GetSystemMetrics(SM_CXSIZEFRAME);
993         *yBorderWidth = GetSystemMetrics(SM_CYSIZEFRAME);
994     }
995     else if (windowStyle & WS_DLGFRAME)
996     {
997         *xBorderWidth = GetSystemMetrics(SM_CXFIXEDFRAME);
998         *yBorderWidth = GetSystemMetrics(SM_CYFIXEDFRAME);
999     }
1000     else
1001     {
1002         *xBorderWidth = 0;
1003         *yBorderWidth = 0;
1004     }
1005 }
1006
1007 #if(WINVER >= 0x500)
1008 typedef struct
1009 {
1010       int *x;
1011       int *y;
1012       const char *name;
1013 } m_proc_t;
1014
1015 static BOOL CALLBACK m_proc(HMONITOR mon,
1016                             HDC hdc,
1017                             LPRECT rect,
1018                             LPARAM data)
1019 {
1020       m_proc_t *dp=(m_proc_t *)data;
1021       MONITORINFOEX info;
1022       BOOL res;
1023       info.cbSize=sizeof(info);
1024       res=GetMonitorInfo(mon,(LPMONITORINFO)&info);
1025       if( res )
1026       {
1027           if( strcmp(dp->name,info.szDevice)==0 )
1028           {
1029               *(dp->x)=info.rcMonitor.left;
1030               *(dp->y)=info.rcMonitor.top;
1031               return FALSE;
1032           }
1033       }
1034       return TRUE;
1035 }
1036
1037 /* 
1038  * this function returns the origin of the screen identified by
1039  * fgDisplay.DisplayName, and 0 otherwise.
1040  * This is used in fgOpenWindow to open the gamemode window on the screen
1041  * identified by the -display command line argument. The function should
1042  * not be called otherwise.
1043  */
1044
1045 static void get_display_origin(int *xp,int *yp)
1046 {
1047     *xp = 0;
1048     *yp = 0;
1049
1050     if( fgDisplay.DisplayName )
1051     {
1052         m_proc_t st;
1053         st.x=xp;
1054         st.y=yp;
1055         st.name=fgDisplay.DisplayName;
1056         EnumDisplayMonitors(0,0,m_proc,(LPARAM)&st);
1057     }
1058 }
1059 #else
1060 #pragma message( "-display parameter only works if compiled with WINVER >= 0x0500")
1061
1062 static void get_display_origin(int *xp,int *yp)
1063 {
1064     *xp = 0;
1065     *yp = 0;
1066
1067     if( fgDisplay.DisplayName )
1068     {
1069         fgWarning( "for working -display support FreeGLUT must be compiled with WINVER >= 0x0500");
1070     }
1071 }
1072 #endif
1073 #endif
1074
1075
1076 #if TARGET_HOST_POSIX_X11
1077 static Bool fghWindowIsVisible( Display *display, XEvent *event, XPointer arg)
1078 {
1079     Window window = (Window)arg;
1080     return (event->type == MapNotify) && (event->xmap.window == window);
1081 }
1082 #endif
1083
1084
1085 /*
1086  * Opens a window. Requires a SFG_Window object created and attached
1087  * to the freeglut structure. OpenGL context is created here.
1088  */
1089 void fgOpenWindow( SFG_Window* window, const char* title,
1090                    GLboolean positionUse, int x, int y,
1091                    GLboolean sizeUse, int w, int h,
1092                    GLboolean gameMode, GLboolean isSubWindow )
1093 {
1094 #if TARGET_HOST_POSIX_X11
1095     XVisualInfo * visualInfo = NULL;
1096     XSetWindowAttributes winAttr;
1097     XTextProperty textProperty;
1098     XSizeHints sizeHints;
1099     XWMHints wmHints;
1100     XEvent eventReturnBuffer; /* return buffer required for a call */
1101     unsigned long mask;
1102     int num_FBConfigs, i;
1103     unsigned int current_DisplayMode = fgState.DisplayMode ;
1104
1105     /* Save the display mode if we are creating a menu window */
1106     if( window->IsMenu && ( ! fgStructure.MenuContext ) )
1107         fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ;
1108
1109     window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs );
1110
1111     if( window->IsMenu && ( ! fgStructure.MenuContext ) )
1112         fgState.DisplayMode = current_DisplayMode ;
1113
1114     if( ! window->Window.FBConfig )
1115     {
1116         /*
1117          * The "fgChooseFBConfig" returned a null meaning that the visual
1118          * context is not available.
1119          * Try a couple of variations to see if they will work.
1120          */
1121         if( !( fgState.DisplayMode & GLUT_DOUBLE ) )
1122         {
1123             fgState.DisplayMode |= GLUT_DOUBLE ;
1124             window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs );
1125             fgState.DisplayMode &= ~GLUT_DOUBLE;
1126         }
1127
1128         if( fgState.DisplayMode & GLUT_MULTISAMPLE )
1129         {
1130             fgState.DisplayMode &= ~GLUT_MULTISAMPLE ;
1131             window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs );
1132             fgState.DisplayMode |= GLUT_MULTISAMPLE;
1133         }
1134     }
1135
1136     FREEGLUT_INTERNAL_ERROR_EXIT( window->Window.FBConfig != NULL,
1137                                   "FBConfig with necessary capabilities not found", "fgOpenWindow" );
1138
1139     /*  Get the X visual.  */
1140     for (i = 0; i < num_FBConfigs; i++) {
1141             visualInfo = glXGetVisualFromFBConfig( fgDisplay.Display,
1142                                                    window->Window.FBConfig[i] );
1143             if (visualInfo)
1144                 break;
1145     }
1146
1147     FREEGLUT_INTERNAL_ERROR_EXIT( visualInfo != NULL,
1148                                   "visualInfo could not be retrieved from FBConfig", "fgOpenWindow" );
1149
1150     /*
1151      * XXX HINT: the masks should be updated when adding/removing callbacks.
1152      * XXX       This might speed up message processing. Is that true?
1153      * XXX
1154      * XXX A: Not appreciably, but it WILL make it easier to debug.
1155      * XXX    Try tracing old GLUT and try tracing freeglut.  Old GLUT
1156      * XXX    turns off events that it doesn't need and is a whole lot
1157      * XXX    more pleasant to trace.  (Think mouse-motion!  Tons of
1158      * XXX    ``bonus'' GUI events stream in.)
1159      */
1160     winAttr.event_mask        =
1161         StructureNotifyMask | SubstructureNotifyMask | ExposureMask |
1162         ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
1163         VisibilityChangeMask | EnterWindowMask | LeaveWindowMask |
1164         PointerMotionMask | ButtonMotionMask;
1165     winAttr.background_pixmap = None;
1166     winAttr.background_pixel  = 0;
1167     winAttr.border_pixel      = 0;
1168
1169     winAttr.colormap = XCreateColormap(
1170         fgDisplay.Display, fgDisplay.RootWindow,
1171         visualInfo->visual, AllocNone
1172     );
1173
1174     mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
1175
1176     if( window->IsMenu || ( gameMode == GL_TRUE ) )
1177     {
1178         winAttr.override_redirect = True;
1179         mask |= CWOverrideRedirect;
1180     }
1181
1182     if( ! positionUse )
1183         x = y = -1; /* default window position */
1184     if( ! sizeUse )
1185         w = h = 300; /* default window size */
1186
1187     window->Window.Handle = XCreateWindow(
1188         fgDisplay.Display,
1189         window->Parent == NULL ? fgDisplay.RootWindow :
1190         window->Parent->Window.Handle,
1191         x, y, w, h, 0,
1192         visualInfo->depth, InputOutput,
1193         visualInfo->visual, mask,
1194         &winAttr
1195     );
1196
1197     /*
1198      * The GLX context creation, possibly trying the direct context rendering
1199      *  or else use the current context if the user has so specified
1200      */
1201
1202     if( window->IsMenu )
1203     {
1204         /*
1205          * If there isn't already an OpenGL rendering context for menu
1206          * windows, make one
1207          */
1208         if( !fgStructure.MenuContext )
1209         {
1210             fgStructure.MenuContext =
1211                 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
1212             fgStructure.MenuContext->MContext = fghCreateNewContext( window );
1213         }
1214
1215         /* window->Window.Context = fgStructure.MenuContext->MContext; */
1216         window->Window.Context = fghCreateNewContext( window );
1217     }
1218     else if( fgState.UseCurrentContext )
1219     {
1220         window->Window.Context = glXGetCurrentContext( );
1221
1222         if( ! window->Window.Context )
1223             window->Window.Context = fghCreateNewContext( window );
1224     }
1225     else
1226         window->Window.Context = fghCreateNewContext( window );
1227
1228 #if !defined( __FreeBSD__ ) && !defined( __NetBSD__ )
1229     if(  !glXIsDirect( fgDisplay.Display, window->Window.Context ) )
1230     {
1231       if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT )
1232         fgError( "Unable to force direct context rendering for window '%s'",
1233                  title );
1234     }
1235 #endif
1236
1237     /*
1238      * XXX Assume the new window is visible by default
1239      * XXX Is this a  safe assumption?
1240      */
1241     window->State.Visible = GL_TRUE;
1242
1243     sizeHints.flags = 0;
1244     if ( positionUse )
1245         sizeHints.flags |= USPosition;
1246     if ( sizeUse )
1247         sizeHints.flags |= USSize;
1248
1249     /*
1250      * Fill in the size hints values now (the x, y, width and height
1251      * settings are obsolete, are there any more WMs that support them?)
1252      * Unless the X servers actually stop supporting these, we should
1253      * continue to fill them in.  It is *not* our place to tell the user
1254      * that they should replace a window manager that they like, and which
1255      * works, just because *we* think that it's not "modern" enough.
1256      */
1257     sizeHints.x      = x;
1258     sizeHints.y      = y;
1259     sizeHints.width  = w;
1260     sizeHints.height = h;
1261
1262     wmHints.flags = StateHint;
1263     wmHints.initial_state = fgState.ForceIconic ? IconicState : NormalState;
1264     /* Prepare the window and iconified window names... */
1265     XStringListToTextProperty( (char **) &title, 1, &textProperty );
1266
1267     XSetWMProperties(
1268         fgDisplay.Display,
1269         window->Window.Handle,
1270         &textProperty,
1271         &textProperty,
1272         0,
1273         0,
1274         &sizeHints,
1275         &wmHints,
1276         NULL
1277     );
1278     XFree( textProperty.value );
1279
1280     XSetWMProtocols( fgDisplay.Display, window->Window.Handle,
1281                      &fgDisplay.DeleteWindow, 1 );
1282
1283     glXMakeContextCurrent(
1284         fgDisplay.Display,
1285         window->Window.Handle,
1286         window->Window.Handle,
1287         window->Window.Context
1288     );
1289
1290     /* register extension events _before_ window is mapped */
1291     #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
1292        fgRegisterDevices( fgDisplay.Display, &(window->Window.Handle) );
1293     #endif
1294
1295     XMapWindow( fgDisplay.Display, window->Window.Handle );
1296
1297     XFree(visualInfo);
1298
1299     if( !isSubWindow)
1300         XPeekIfEvent( fgDisplay.Display, &eventReturnBuffer, &fghWindowIsVisible, (XPointer)(window->Window.Handle) );
1301
1302 #elif TARGET_HOST_MS_WINDOWS
1303
1304     WNDCLASS wc;
1305     DWORD flags   = 0;
1306     DWORD exFlags = 0;
1307     ATOM atom;
1308
1309     /* Grab the window class we have registered on glutInit(): */
1310     atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc );
1311     FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Info Not Found",
1312                                    "fgOpenWindow" );
1313
1314     /* Determine window style flags*/
1315     if( gameMode )
1316     {
1317         FREEGLUT_INTERNAL_ERROR_EXIT ( window->Parent == NULL,
1318                                        "Game mode being invoked on a subwindow",
1319                                        "fgOpenWindow" );
1320
1321         /*
1322          * Set the window creation flags appropriately to make the window
1323          * entirely visible:
1324          */
1325         flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
1326     }
1327     else
1328     {
1329         flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
1330
1331         /*
1332          * There's a small difference between creating the top, child and
1333          * menu windows
1334          */
1335         if ( window->IsMenu )
1336         {
1337             flags |= WS_POPUP;
1338             exFlags |= WS_EX_TOOLWINDOW;
1339         }
1340 #if defined(_WIN32_WCE)
1341         /* no decorations for windows CE */
1342 #else
1343         /* if this is not a subwindow (child), set its style based on the requested display mode */
1344         else if( window->Parent == NULL )
1345             if ( fgState.DisplayMode & GLUT_BORDERLESS )
1346             {
1347                 /* no window decorations needed */
1348             }
1349             else if ( fgState.DisplayMode & GLUT_CAPTIONLESS )
1350                 /* only window decoration is a border, no title bar or buttons */
1351                 flags |= WS_DLGFRAME;
1352             else
1353                 /* window decoration are a border, title bar and buttons.
1354                  * NB: we later query whether the window has a title bar or
1355                  * not by testing for the maximize button, as the test for
1356                  * WS_CAPTION can be true without the window having a title
1357                  * bar. This style WS_OVERLAPPEDWINDOW gives you a maximize
1358                  * button. */
1359                 flags |= WS_OVERLAPPEDWINDOW;
1360 #endif
1361         else
1362             /* subwindows always have no decoration, but are marked as a child window to the OS */
1363             flags |= WS_CHILD;
1364     }
1365
1366     /* determine window size and position */
1367     if( gameMode )
1368     {
1369         /* if in gamemode, query the origin of specified by the -display
1370          * command line parameter (if any) and offset the upper-left corner
1371          * of the window so we create the window on that screen.
1372          * The -display argument doesn't do anything if not trying to enter
1373          * gamemode.
1374          */
1375         int xoff=0, yoff=0;
1376         get_display_origin(&xoff,&yoff);
1377         x += xoff;
1378         y += yoff;
1379     }
1380     if( !positionUse )
1381     {
1382         x = CW_USEDEFAULT;
1383         y = CW_USEDEFAULT;
1384     }
1385     if( !sizeUse )
1386     {
1387         if( ! window->IsMenu )
1388         {
1389             w = CW_USEDEFAULT;
1390             h = CW_USEDEFAULT;
1391         }
1392         else /* fail safe - Windows can make a window of size (0, 0) */
1393             w = h = 300; /* default window size */
1394     }
1395     /* store requested client area width and height */
1396     window->State.Width = w;
1397     window->State.Height = h;
1398
1399 #if !defined(_WIN32_WCE)    /* no decorations for windows CE */
1400     if( sizeUse )
1401     {
1402         RECT windowRect;
1403         /*
1404          * Update the window dimensions, taking the window decorations
1405          * into account.  FreeGLUT is to create the window with the
1406          * topleft outside corner at (x,y) and with client area
1407          * dimensions (w,h).
1408          * note: don't need to do this when w=h=CW_USEDEFAULT, so in the
1409          * if( sizeUse ) here is convenient.
1410          */
1411         windowRect.left     = x;
1412         windowRect.top      = y;
1413         windowRect.right    = x+w;
1414         windowRect.bottom   = y+h;
1415
1416         fghComputeWindowRectFromClientArea_UseStyle(flags,&windowRect,TRUE);
1417
1418         w = windowRect.right - windowRect.left;
1419         h = windowRect.bottom- windowRect.top;
1420     }
1421 #endif /* !defined(_WIN32_WCE) */
1422
1423 #if defined(_WIN32_WCE)
1424     {
1425         wchar_t* wstr = fghWstrFromStr(title);
1426
1427         window->Window.Handle = CreateWindow(
1428             _T("FREEGLUT"),
1429             wstr,
1430             WS_VISIBLE | WS_POPUP,
1431             0,0, 240,320,
1432             NULL,
1433             NULL,
1434             fgDisplay.Instance,
1435             (LPVOID) window
1436         );
1437
1438         free(wstr);
1439
1440         SHFullScreen(window->Window.Handle, SHFS_HIDESTARTICON);
1441         SHFullScreen(window->Window.Handle, SHFS_HIDESIPBUTTON);
1442         SHFullScreen(window->Window.Handle, SHFS_HIDETASKBAR);
1443         MoveWindow(window->Window.Handle, 0, 0, 240, 320, TRUE);
1444         ShowWindow(window->Window.Handle, SW_SHOW);
1445         UpdateWindow(window->Window.Handle);
1446     }
1447 #else
1448     window->Window.Handle = CreateWindowEx(
1449         exFlags,
1450         _T("FREEGLUT"),
1451         title,
1452         flags,
1453         x, y, w, h,
1454         (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle,
1455         (HMENU) NULL,
1456         fgDisplay.Instance,
1457         (LPVOID) window
1458     );
1459 #endif /* defined(_WIN32_WCE) */
1460
1461     if( !( window->Window.Handle ) )
1462         fgError( "Failed to create a window (%s)!", title );
1463
1464 #if !defined(_WIN32_WCE)
1465     /* Need to set requested style again, apparently Windows doesn't listen when requesting windows without title bar or borders */
1466     SetWindowLong(window->Window.Handle, GWL_STYLE, flags);
1467     SetWindowPos(window->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
1468 #endif /* defined(_WIN32_WCE) */
1469
1470     /* Make a menu window always on top - fix Feature Request 947118 */
1471     if( window->IsMenu || gameMode )
1472         SetWindowPos(
1473                         window->Window.Handle,
1474                         HWND_TOPMOST,
1475                         0, 0, 0, 0,
1476                         SWP_NOMOVE | SWP_NOSIZE
1477                     );
1478
1479     /* Enable multitouch: additional flag TWF_FINETOUCH, TWF_WANTPALM */
1480     #ifdef WM_TOUCH
1481         if (fghRegisterTouchWindow == (pRegisterTouchWindow)0xDEADBEEF) 
1482                         fghRegisterTouchWindow = (pRegisterTouchWindow)GetProcAddress(GetModuleHandle("user32"),"RegisterTouchWindow");
1483                 if (fghRegisterTouchWindow)
1484              fghRegisterTouchWindow( window->Window.Handle, TWF_FINETOUCH | TWF_WANTPALM );
1485     #endif
1486
1487 #if defined(_WIN32_WCE)
1488     ShowWindow( window->Window.Handle, SW_SHOW );
1489 #else
1490     ShowWindow( window->Window.Handle,
1491                 fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW );
1492 #endif /* defined(_WIN32_WCE) */
1493
1494     UpdateWindow( window->Window.Handle );
1495     ShowCursor( TRUE );  /* XXX Old comments say "hide cursor"! */
1496
1497 #endif
1498
1499     fgSetWindow( window );
1500
1501     window->Window.DoubleBuffered =
1502         ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0;
1503
1504     if ( ! window->Window.DoubleBuffered )
1505     {
1506         glDrawBuffer ( GL_FRONT );
1507         glReadBuffer ( GL_FRONT );
1508     }
1509 }
1510
1511 /*
1512  * Closes a window, destroying the frame and OpenGL context
1513  */
1514 void fgCloseWindow( SFG_Window* window )
1515 {
1516     /* if we're in gamemode and we're closing the gamemode window,
1517      * call glutLeaveGameMode first to make sure the gamemode is
1518      * properly closed before closing the window
1519      */
1520     if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==window->ID)
1521         glutLeaveGameMode();
1522
1523 #if TARGET_HOST_POSIX_X11
1524
1525     if( window->Window.Context )
1526         glXDestroyContext( fgDisplay.Display, window->Window.Context );
1527     XFree( window->Window.FBConfig );
1528
1529     if( window->Window.Handle ) {
1530         XDestroyWindow( fgDisplay.Display, window->Window.Handle );
1531     }
1532     /* XFlush( fgDisplay.Display ); */ /* XXX Shouldn't need this */
1533
1534 #elif TARGET_HOST_MS_WINDOWS
1535
1536     /* Make sure we don't close a window with current context active */
1537     if( fgStructure.CurrentWindow == window )
1538         wglMakeCurrent( NULL, NULL );
1539
1540     /*
1541      * Step through the list of windows.  If the rendering context
1542      * is not being used by another window, then we delete it.
1543      */
1544     {
1545         int used = FALSE ;
1546         SFG_Window *iter ;
1547
1548         for( iter = (SFG_Window *)fgStructure.Windows.First;
1549              iter;
1550              iter = (SFG_Window *)iter->Node.Next )
1551         {
1552             if( ( iter->Window.Context == window->Window.Context ) &&
1553                 ( iter != window ) )
1554                 used = TRUE;
1555         }
1556
1557         if( ! used )
1558             wglDeleteContext( window->Window.Context );
1559     }
1560
1561     DestroyWindow( window->Window.Handle );
1562 #endif
1563 }
1564
1565
1566 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
1567
1568 /*
1569  * Creates a new top-level freeglut window
1570  */
1571 int FGAPIENTRY glutCreateWindow( const char* title )
1572 {
1573     /* XXX GLUT does not exit; it simply calls "glutInit" quietly if the
1574      * XXX application has not already done so.  The "freeglut" community
1575      * XXX decided not to go this route (freeglut-developer e-mail from
1576      * XXX Steve Baker, 12/16/04, 4:22 PM CST, "Re: [Freeglut-developer]
1577      * XXX Desired 'freeglut' behaviour when there is no current window"
1578      */
1579     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateWindow" );
1580
1581     return fgCreateWindow( NULL, title, fgState.Position.Use,
1582                            fgState.Position.X, fgState.Position.Y,
1583                            fgState.Size.Use, fgState.Size.X, fgState.Size.Y,
1584                            GL_FALSE, GL_FALSE )->ID;
1585 }
1586
1587 #if TARGET_HOST_MS_WINDOWS
1588 int FGAPIENTRY __glutCreateWindowWithExit( const char *title, void (__cdecl *exit_function)(int) )
1589 {
1590   __glutExitFunc = exit_function;
1591   return glutCreateWindow( title );
1592 }
1593 #endif
1594
1595 /*
1596  * This function creates a sub window.
1597  */
1598 int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h )
1599 {
1600     int ret = 0;
1601     SFG_Window* window = NULL;
1602     SFG_Window* parent = NULL;
1603
1604     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateSubWindow" );
1605     parent = fgWindowByID( parentID );
1606     freeglut_return_val_if_fail( parent != NULL, 0 );
1607     if ( x < 0 )
1608     {
1609         x = parent->State.Width + x ;
1610         if ( w >= 0 ) x -= w ;
1611     }
1612
1613     if ( w < 0 ) w = parent->State.Width - x + w ;
1614     if ( w < 0 )
1615     {
1616         x += w ;
1617         w = -w ;
1618     }
1619
1620     if ( y < 0 )
1621     {
1622         y = parent->State.Height + y ;
1623         if ( h >= 0 ) y -= h ;
1624     }
1625
1626     if ( h < 0 ) h = parent->State.Height - y + h ;
1627     if ( h < 0 )
1628     {
1629         y += h ;
1630         h = -h ;
1631     }
1632
1633     window = fgCreateWindow( parent, "", GL_TRUE, x, y, GL_TRUE, w, h, GL_FALSE, GL_FALSE );
1634     ret = window->ID;
1635
1636     return ret;
1637 }
1638
1639 /*
1640  * Destroys a window and all of its subwindows
1641  */
1642 void FGAPIENTRY glutDestroyWindow( int windowID )
1643 {
1644     SFG_Window* window;
1645     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyWindow" );
1646     window = fgWindowByID( windowID );
1647     freeglut_return_if_fail( window != NULL );
1648     {
1649         fgExecutionState ExecState = fgState.ExecState;
1650         fgAddToWindowDestroyList( window );
1651         fgState.ExecState = ExecState;
1652     }
1653 }
1654
1655 /*
1656  * This function selects the current window
1657  */
1658 void FGAPIENTRY glutSetWindow( int ID )
1659 {
1660     SFG_Window* window = NULL;
1661
1662     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindow" );
1663     if( fgStructure.CurrentWindow != NULL )
1664         if( fgStructure.CurrentWindow->ID == ID )
1665             return;
1666
1667     window = fgWindowByID( ID );
1668     if( window == NULL )
1669     {
1670         fgWarning( "glutSetWindow(): window ID %d not found!", ID );
1671         return;
1672     }
1673
1674     fgSetWindow( window );
1675 }
1676
1677 /*
1678  * This function returns the ID number of the current window, 0 if none exists
1679  */
1680 int FGAPIENTRY glutGetWindow( void )
1681 {
1682     SFG_Window *win = fgStructure.CurrentWindow;
1683     /*
1684      * Since GLUT did not throw an error if this function was called without a prior call to
1685      * "glutInit", this function shouldn't do so here.  Instead let us return a zero.
1686      * See Feature Request "[ 1307049 ] glutInit check".
1687      */
1688     if ( ! fgState.Initialised )
1689         return 0;
1690
1691     while ( win && win->IsMenu )
1692         win = win->Parent;
1693     return win ? win->ID : 0;
1694 }
1695
1696 /*
1697  * This function makes the current window visible
1698  */
1699 void FGAPIENTRY glutShowWindow( void )
1700 {
1701     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutShowWindow" );
1702     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutShowWindow" );
1703
1704 #if TARGET_HOST_POSIX_X11
1705
1706     XMapWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle );
1707     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1708
1709 #elif TARGET_HOST_MS_WINDOWS
1710
1711     ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_SHOW );
1712
1713 #endif
1714
1715     fgStructure.CurrentWindow->State.Redisplay = GL_TRUE;
1716 }
1717
1718 /*
1719  * This function hides the current window
1720  */
1721 void FGAPIENTRY glutHideWindow( void )
1722 {
1723     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutHideWindow" );
1724     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutHideWindow" );
1725
1726 #if TARGET_HOST_POSIX_X11
1727
1728     if( fgStructure.CurrentWindow->Parent == NULL )
1729         XWithdrawWindow( fgDisplay.Display,
1730                          fgStructure.CurrentWindow->Window.Handle,
1731                          fgDisplay.Screen );
1732     else
1733         XUnmapWindow( fgDisplay.Display,
1734                       fgStructure.CurrentWindow->Window.Handle );
1735     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1736
1737 #elif TARGET_HOST_MS_WINDOWS
1738
1739     ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_HIDE );
1740
1741 #endif
1742
1743     fgStructure.CurrentWindow->State.Redisplay = GL_FALSE;
1744 }
1745
1746 /*
1747  * Iconify the current window (top-level windows only)
1748  */
1749 void FGAPIENTRY glutIconifyWindow( void )
1750 {
1751     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIconifyWindow" );
1752     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIconifyWindow" );
1753
1754     fgStructure.CurrentWindow->State.Visible   = GL_FALSE;
1755 #if TARGET_HOST_POSIX_X11
1756
1757     XIconifyWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
1758                     fgDisplay.Screen );
1759     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1760
1761 #elif TARGET_HOST_MS_WINDOWS
1762
1763     ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_MINIMIZE );
1764
1765 #endif
1766
1767     fgStructure.CurrentWindow->State.Redisplay = GL_FALSE;
1768 }
1769
1770 /*
1771  * Set the current window's title
1772  */
1773 void FGAPIENTRY glutSetWindowTitle( const char* title )
1774 {
1775     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowTitle" );
1776     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowTitle" );
1777     if( ! fgStructure.CurrentWindow->Parent )
1778     {
1779 #if TARGET_HOST_POSIX_X11
1780
1781         XTextProperty text;
1782
1783         text.value = (unsigned char *) title;
1784         text.encoding = XA_STRING;
1785         text.format = 8;
1786         text.nitems = strlen( title );
1787
1788         XSetWMName(
1789             fgDisplay.Display,
1790             fgStructure.CurrentWindow->Window.Handle,
1791             &text
1792         );
1793
1794         XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1795
1796 #elif TARGET_HOST_MS_WINDOWS
1797 #    ifdef _WIN32_WCE
1798         {
1799             wchar_t* wstr = fghWstrFromStr(title);
1800             SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr );
1801             free(wstr);
1802         }
1803 #    else
1804         SetWindowText( fgStructure.CurrentWindow->Window.Handle, title );
1805 #    endif
1806
1807 #endif
1808     }
1809 }
1810
1811 /*
1812  * Set the current window's iconified title
1813  */
1814 void FGAPIENTRY glutSetIconTitle( const char* title )
1815 {
1816     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetIconTitle" );
1817     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetIconTitle" );
1818
1819     if( ! fgStructure.CurrentWindow->Parent )
1820     {
1821 #if TARGET_HOST_POSIX_X11
1822
1823         XTextProperty text;
1824
1825         text.value = (unsigned char *) title;
1826         text.encoding = XA_STRING;
1827         text.format = 8;
1828         text.nitems = strlen( title );
1829
1830         XSetWMIconName(
1831             fgDisplay.Display,
1832             fgStructure.CurrentWindow->Window.Handle,
1833             &text
1834         );
1835
1836         XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1837
1838 #elif TARGET_HOST_MS_WINDOWS
1839 #    ifdef _WIN32_WCE
1840         {
1841             wchar_t* wstr = fghWstrFromStr(title);
1842             SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr );
1843             free(wstr);
1844         }
1845 #    else
1846         SetWindowText( fgStructure.CurrentWindow->Window.Handle, title );
1847 #    endif
1848
1849 #endif
1850     }
1851 }
1852
1853 /*
1854  * Change the current window's size
1855  */
1856 void FGAPIENTRY glutReshapeWindow( int width, int height )
1857 {
1858     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" );
1859     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" );
1860
1861     if (glutGet(GLUT_FULL_SCREEN))
1862     {
1863       /*  Leave full screen state before resizing. */
1864       glutLeaveFullScreen();
1865     }
1866
1867     fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE;
1868     fgStructure.CurrentWindow->State.Width  = width ;
1869     fgStructure.CurrentWindow->State.Height = height;
1870 }
1871
1872 /*
1873  * Change the current window's position
1874  */
1875 void FGAPIENTRY glutPositionWindow( int x, int y )
1876 {
1877     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" );
1878     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" );
1879
1880     if (glutGet(GLUT_FULL_SCREEN))
1881     {
1882       /*  Leave full screen state before moving. */
1883       glutLeaveFullScreen();
1884     }
1885
1886 #if TARGET_HOST_POSIX_X11
1887
1888     XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
1889                  x, y );
1890     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1891
1892 #elif TARGET_HOST_MS_WINDOWS
1893
1894     {
1895         RECT winRect;
1896
1897         /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
1898         GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect );
1899         MoveWindow(
1900             fgStructure.CurrentWindow->Window.Handle,
1901             x,
1902             y,
1903             winRect.right - winRect.left,
1904             winRect.bottom - winRect.top,
1905             TRUE
1906         );
1907     }
1908
1909 #endif
1910 }
1911
1912 /*
1913  * Lowers the current window (by Z order change)
1914  */
1915 void FGAPIENTRY glutPushWindow( void )
1916 {
1917     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" );
1918     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" );
1919
1920 #if TARGET_HOST_POSIX_X11
1921
1922     XLowerWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle );
1923
1924 #elif TARGET_HOST_MS_WINDOWS
1925
1926     SetWindowPos(
1927         fgStructure.CurrentWindow->Window.Handle,
1928         HWND_BOTTOM,
1929         0, 0, 0, 0,
1930         SWP_NOSIZE | SWP_NOMOVE
1931     );
1932
1933 #endif
1934 }
1935
1936 /*
1937  * Raises the current window (by Z order change)
1938  */
1939 void FGAPIENTRY glutPopWindow( void )
1940 {
1941     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" );
1942     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" );
1943
1944 #if TARGET_HOST_POSIX_X11
1945
1946     XRaiseWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle );
1947
1948 #elif TARGET_HOST_MS_WINDOWS
1949
1950     SetWindowPos(
1951         fgStructure.CurrentWindow->Window.Handle,
1952         HWND_TOP,
1953         0, 0, 0, 0,
1954         SWP_NOSIZE | SWP_NOMOVE
1955     );
1956
1957 #endif
1958 }
1959
1960 /*
1961  * Resize the current window so that it fits the whole screen
1962  */
1963 void FGAPIENTRY glutFullScreen( void )
1964 {
1965     SFG_Window *win;
1966
1967     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );
1968     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );
1969
1970     win = fgStructure.CurrentWindow;
1971
1972     if (win->Parent)
1973     {
1974         /* Child windows cannot be made fullscreen, consistent with GLUT's behavior
1975          * Also, what would it mean for a child window to be fullscreen, given that it
1976          * is confined to its parent?
1977          */
1978         fgWarning("glutFullScreen called on a child window, ignoring...");
1979         return;
1980     }
1981     else if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==win->ID)
1982     {
1983         /* Ignore fullscreen call on GameMode window, those are always fullscreen already */
1984         return;
1985     }
1986
1987 #if TARGET_HOST_POSIX_X11
1988     if(!glutGet(GLUT_FULL_SCREEN)) {
1989         if(fghToggleFullscreen() != -1) {
1990             win->State.IsFullscreen = GL_TRUE;
1991         }
1992     }
1993
1994 #elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */
1995
1996     if (glutGet(GLUT_FULL_SCREEN))
1997     {
1998         /*  Leave full screen state before entering fullscreen again (resizing?) */
1999         glutLeaveFullScreen();
2000     }
2001
2002     {
2003 #if(WINVER >= 0x0500) /* Windows 2000 or later */
2004         DWORD s;
2005         RECT rect;
2006         HMONITOR hMonitor;
2007         MONITORINFO mi;
2008
2009         /* For fullscreen mode, first remove all window decoration
2010          * and set style to popup so it will overlap the taskbar
2011          * then force to maximize on the screen on which it has the most
2012          * overlap.
2013          */
2014
2015         
2016         /* store current window rect */
2017         GetWindowRect( win->Window.Handle, &win->State.OldRect );
2018
2019         /* store current window style */
2020         win->State.OldStyle = s = GetWindowLong(win->Window.Handle, GWL_STYLE);
2021
2022         /* remove decorations from style and add popup style*/
2023         s &= ~WS_OVERLAPPEDWINDOW;
2024         s |= WS_POPUP;
2025         SetWindowLong(win->Window.Handle, GWL_STYLE, s);
2026         SetWindowPos(win->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
2027
2028         /* For fullscreen mode, find the monitor that is covered the most
2029          * by the window and get its rect as the resize target.
2030              */
2031         hMonitor= MonitorFromRect(&win->State.OldRect, MONITOR_DEFAULTTONEAREST);
2032         mi.cbSize = sizeof(mi);
2033         GetMonitorInfo(hMonitor, &mi);
2034         rect = mi.rcMonitor;
2035 #else   /* if (WINVER >= 0x0500) */
2036         RECT rect;
2037
2038         /* For fullscreen mode, force the top-left corner to 0,0
2039          * and adjust the window rectangle so that the client area
2040          * covers the whole screen.
2041          */
2042
2043         rect.left   = 0;
2044         rect.top    = 0;
2045         rect.right  = fgDisplay.ScreenWidth;
2046         rect.bottom = fgDisplay.ScreenHeight;
2047
2048         AdjustWindowRect ( &rect, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS |
2049                                   WS_CLIPCHILDREN, FALSE );
2050 #endif  /* (WINVER >= 0x0500) */
2051
2052         /*
2053          * then resize window
2054          * SWP_NOACTIVATE     Do not activate the window
2055          * SWP_NOOWNERZORDER  Do not change position in z-order
2056          * SWP_NOSENDCHANGING Suppress WM_WINDOWPOSCHANGING message
2057          * SWP_NOZORDER       Retains the current Z order (ignore 2nd param)
2058          */
2059         SetWindowPos( fgStructure.CurrentWindow->Window.Handle,
2060                       HWND_TOP,
2061                       rect.left,
2062                       rect.top,
2063                       rect.right  - rect.left,
2064                       rect.bottom - rect.top,
2065                       SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
2066                       SWP_NOZORDER
2067                     );
2068
2069         win->State.IsFullscreen = GL_TRUE;
2070     }
2071 #endif
2072 }
2073
2074 /*
2075  * If we are fullscreen, resize the current window back to its original size
2076  */
2077 void FGAPIENTRY glutLeaveFullScreen( void )
2078 {
2079     SFG_Window *win;
2080
2081     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );
2082     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );
2083
2084     win = fgStructure.CurrentWindow;
2085
2086 #if TARGET_HOST_POSIX_X11
2087     if(glutGet(GLUT_FULL_SCREEN)) {
2088         if(fghToggleFullscreen() != -1) {
2089             win->State.IsFullscreen = GL_FALSE;
2090         }
2091     }
2092
2093 #elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */
2094     if (!glutGet(GLUT_FULL_SCREEN))
2095     {
2096         /* nothing to do */
2097         return;
2098     }
2099
2100     /* restore style of window before making it fullscreen */
2101     SetWindowLong(win->Window.Handle, GWL_STYLE, win->State.OldStyle);
2102     SetWindowPos(win->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
2103
2104     /* Then resize */
2105     SetWindowPos(win->Window.Handle,
2106         HWND_TOP,
2107         win->State.OldRect.left,
2108         win->State.OldRect.top,
2109         win->State.OldRect.right  - win->State.OldRect.left,
2110         win->State.OldRect.bottom - win->State.OldRect.top,
2111         SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
2112         SWP_NOZORDER
2113         );
2114
2115     win->State.IsFullscreen = GL_FALSE;
2116 #endif
2117 }
2118
2119 /*
2120  * Toggle the window's full screen state.
2121  */
2122 void FGAPIENTRY glutFullScreenToggle( void )
2123 {
2124     SFG_Window *win;
2125
2126     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" );
2127     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" );
2128
2129     win = fgStructure.CurrentWindow;
2130
2131 #if TARGET_HOST_POSIX_X11
2132     if(fghToggleFullscreen() != -1) {
2133         win->State.IsFullscreen = !win->State.IsFullscreen;
2134     }
2135 #elif TARGET_HOST_MS_WINDOWS
2136     if (!win->State.IsFullscreen)
2137         glutFullScreen();
2138     else
2139         glutLeaveFullScreen();
2140 #endif
2141 }
2142
2143 /*
2144  * A.Donev: Set and retrieve the window's user data
2145  */
2146 void* FGAPIENTRY glutGetWindowData( void )
2147 {
2148     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" );
2149     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" );
2150     return fgStructure.CurrentWindow->UserData;
2151 }
2152
2153 void FGAPIENTRY glutSetWindowData(void* data)
2154 {
2155     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" );
2156     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" );
2157     fgStructure.CurrentWindow->UserData = data;
2158 }
2159
2160 /*** END OF FILE ***/