0542017bee12ef62831027a918913b0c36d865aa
[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 < 2 || (fgState.MajorVersion == 2 && fgState.MinorVersion <= 1);
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 = (CreateContextAttribsProc) fghGetProcAddress( "glXCreateContextAttribsARB" );
447  
448   /* glXCreateContextAttribsARB not found, yet the user has requested the new context creation */
449   if ( !createContextAttribs && !fghIsLegacyContextRequested() ) {
450     fgWarning( "OpenGL >2.1 context requested but glXCreateContextAttribsARB is not available! Falling back to legacy context creation" );
451         fgState.MajorVersion = 2;
452         fgState.MinorVersion = 1;
453   }
454
455   /* If nothing fancy has been required, simply use the old context creation GLX API entry */
456   if ( fghIsLegacyContextRequested() || !createContextAttribs )
457   {
458     context = glXCreateNewContext( dpy, config, render_type, share_list, direct );
459     if ( context == NULL ) {
460       fghContextCreationError();
461     }
462     return context;
463   }
464
465   /* color index mode is not available anymore with OpenGL 3.0 */
466   if ( render_type == GLX_COLOR_INDEX_TYPE ) {
467     fgWarning( "color index mode is deprecated, using RGBA mode" );
468   }
469
470   fghFillContextAttributes( attributes );
471
472   context = createContextAttribs( dpy, config, share_list, direct, attributes );
473   if ( context == NULL ) {
474     fghContextCreationError();
475   }
476   return context;
477 }
478
479
480 #define _NET_WM_STATE_TOGGLE    2
481 static int fghResizeFullscrToggle(void)
482 {
483     XWindowAttributes attributes;
484
485     if(glutGet(GLUT_FULL_SCREEN)) {
486         /* restore original window size */
487         SFG_Window *win = fgStructure.CurrentWindow;
488         fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE;
489         fgStructure.CurrentWindow->State.Width  = win->State.OldWidth;
490         fgStructure.CurrentWindow->State.Height = win->State.OldHeight;
491
492     } else {
493         /* resize the window to cover the entire screen */
494         XGetWindowAttributes(fgDisplay.Display,
495                 fgStructure.CurrentWindow->Window.Handle,
496                 &attributes);
497         
498         /*
499          * The "x" and "y" members of "attributes" are the window's coordinates
500          * relative to its parent, i.e. to the decoration window.
501          */
502         XMoveResizeWindow(fgDisplay.Display,
503                 fgStructure.CurrentWindow->Window.Handle,
504                 -attributes.x,
505                 -attributes.y,
506                 fgDisplay.ScreenWidth,
507                 fgDisplay.ScreenHeight);
508     }
509     return 0;
510 }
511
512 static int fghEwmhFullscrToggle(void)
513 {
514     XEvent xev;
515     long evmask = SubstructureRedirectMask | SubstructureNotifyMask;
516
517     if(!fgDisplay.State || !fgDisplay.StateFullScreen) {
518         return -1;
519     }
520
521     xev.type = ClientMessage;
522     xev.xclient.window = fgStructure.CurrentWindow->Window.Handle;
523     xev.xclient.message_type = fgDisplay.State;
524     xev.xclient.format = 32;
525     xev.xclient.data.l[0] = _NET_WM_STATE_TOGGLE;
526     xev.xclient.data.l[1] = fgDisplay.StateFullScreen;
527     xev.xclient.data.l[2] = 0;  /* no second property to toggle */
528     xev.xclient.data.l[3] = 1;  /* source indication: application */
529     xev.xclient.data.l[4] = 0;  /* unused */
530
531     if(!XSendEvent(fgDisplay.Display, fgDisplay.RootWindow, 0, evmask, &xev)) {
532         return -1;
533     }
534     return 0;
535 }
536
537 static int fghToggleFullscreen(void)
538 {
539     /* first try the EWMH (_NET_WM_STATE) method ... */
540     if(fghEwmhFullscrToggle() != -1) {
541         return 0;
542     }
543
544     /* fall back to resizing the window */
545     if(fghResizeFullscrToggle() != -1) {
546         return 0;
547     }
548     return -1;
549 }
550
551
552 #endif  /* TARGET_HOST_POSIX_X11 */
553
554
555 #if TARGET_HOST_MS_WINDOWS
556 /*
557  * Setup the pixel format for a Win32 window
558  */
559
560 #if defined(_WIN32_WCE)
561 static wchar_t* fghWstrFromStr(const char* str)
562 {
563     int i,len=strlen(str);
564     wchar_t* wstr = (wchar_t*)malloc(2*len+2);
565     for(i=0; i<len; i++)
566         wstr[i] = str[i];
567     wstr[len] = 0;
568     return wstr;
569 }
570 #endif /* defined(_WIN32_WCE) */
571
572
573 static void fghFillContextAttributes( int *attributes ) {
574   int where = 0, contextFlags, contextProfile;
575
576   if ( !fghIsLegacyContextVersionRequested() ) {
577     ATTRIB_VAL( WGL_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion );
578     ATTRIB_VAL( WGL_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion );
579   }
580
581   contextFlags =
582     fghMapBit( fgState.ContextFlags, GLUT_DEBUG, WGL_CONTEXT_DEBUG_BIT_ARB ) |
583     fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB );
584   if ( contextFlags != 0 ) {
585     ATTRIB_VAL( WGL_CONTEXT_FLAGS_ARB, contextFlags );
586   }
587
588   contextProfile =
589     fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, WGL_CONTEXT_CORE_PROFILE_BIT_ARB ) |
590     fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB );
591   if ( contextProfile != 0 ) {
592     ATTRIB_VAL( WGL_CONTEXT_PROFILE_MASK_ARB, contextProfile );
593   }
594
595   ATTRIB( 0 );
596 }
597
598 static int fghIsExtensionSupported( HDC hdc, const char *extension ) {
599     const char *pWglExtString;
600     PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetEntensionsStringARB =
601       (PFNWGLGETEXTENSIONSSTRINGARBPROC) wglGetProcAddress("wglGetExtensionsStringARB");
602     if ( wglGetEntensionsStringARB == NULL )
603     {
604       return FALSE;
605     }
606     pWglExtString = wglGetEntensionsStringARB( hdc );
607     return ( pWglExtString != NULL ) && ( strstr(pWglExtString, extension) != NULL );
608 }
609
610 void fgNewWGLCreateContext( SFG_Window* window )
611 {
612     HGLRC context;
613     int attributes[9];
614     PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
615
616     /* If nothing fancy has been required, leave the context as it is */
617     if ( fghIsLegacyContextRequested() )
618     {
619         return;
620     }
621
622     wglMakeCurrent( window->Window.Device, window->Window.Context );
623
624     if ( !fghIsExtensionSupported( window->Window.Device, "WGL_ARB_create_context" ) )
625     {
626         return;
627     }
628
629     /* new context creation */
630     fghFillContextAttributes( attributes );
631
632     wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress( "wglCreateContextAttribsARB" );
633     if ( wglCreateContextAttribsARB == NULL )
634     {
635         fgError( "wglCreateContextAttribsARB not found" );
636     }
637
638     context = wglCreateContextAttribsARB( window->Window.Device, 0, attributes );
639     if ( context == NULL )
640     {
641         fghContextCreationError();
642     }
643
644     wglMakeCurrent( NULL, NULL );
645     wglDeleteContext( window->Window.Context );
646     window->Window.Context = context;
647 }
648
649 #if !defined(_WIN32_WCE)
650
651 static void fghFillPFD( PIXELFORMATDESCRIPTOR *ppfd, HDC hdc, unsigned char layer_type )
652 {
653   int flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
654   if ( fgState.DisplayMode & GLUT_DOUBLE ) {
655         flags |= PFD_DOUBLEBUFFER;
656   }
657   if ( fgState.DisplayMode & GLUT_STEREO ) {
658     flags |= PFD_STEREO;
659   }
660
661 #if defined(_MSC_VER)
662 #pragma message( "fgSetupPixelFormat(): there is still some work to do here!" )
663 #endif
664
665   /* Specify which pixel format do we opt for... */
666   ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
667   ppfd->nVersion = 1;
668   ppfd->dwFlags = flags;
669
670   if( fgState.DisplayMode & GLUT_INDEX ) {
671     ppfd->iPixelType = PFD_TYPE_COLORINDEX;
672     ppfd->cRedBits = 0;
673     ppfd->cGreenBits = 0;
674     ppfd->cBlueBits = 0;
675     ppfd->cAlphaBits = 0;
676   } else {
677     ppfd->iPixelType = PFD_TYPE_RGBA;
678     ppfd->cRedBits = 8;
679     ppfd->cGreenBits = 8;
680     ppfd->cBlueBits = 8;
681     ppfd->cAlphaBits = ( fgState.DisplayMode & GLUT_ALPHA ) ? 8 : 0;
682   }
683
684   ppfd->cColorBits = 24;
685   ppfd->cRedShift = 0;
686   ppfd->cGreenShift = 0;
687   ppfd->cBlueShift = 0;
688   ppfd->cAlphaShift = 0;
689   ppfd->cAccumBits = ( fgState.DisplayMode & GLUT_ACCUM ) ? 1 : 0;
690   ppfd->cAccumRedBits = 0;
691   ppfd->cAccumGreenBits = 0;
692   ppfd->cAccumBlueBits = 0;
693   ppfd->cAccumAlphaBits = 0;
694
695   /* Hmmm, or 32/0 instead of 24/8? */
696   ppfd->cDepthBits = 24;
697   ppfd->cStencilBits = 8;
698
699   ppfd->cAuxBuffers = fghNumberOfAuxBuffersRequested();
700   ppfd->iLayerType = layer_type;
701   ppfd->bReserved = 0;
702   ppfd->dwLayerMask = 0;
703   ppfd->dwVisibleMask = 0;
704   ppfd->dwDamageMask = 0;
705   
706   ppfd->cColorBits = (BYTE) GetDeviceCaps( hdc, BITSPIXEL );
707 }
708
709 static void fghFillPixelFormatAttributes( int *attributes, const PIXELFORMATDESCRIPTOR *ppfd )
710 {
711   int where = 0;
712
713   ATTRIB_VAL( WGL_DRAW_TO_WINDOW_ARB, GL_TRUE );
714   ATTRIB_VAL( WGL_SUPPORT_OPENGL_ARB, GL_TRUE );
715   ATTRIB_VAL( WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB );
716
717   ATTRIB_VAL( WGL_COLOR_BITS_ARB, ppfd->cColorBits );
718   ATTRIB_VAL( WGL_ALPHA_BITS_ARB, ppfd->cAlphaBits );
719   ATTRIB_VAL( WGL_DEPTH_BITS_ARB, ppfd->cDepthBits );
720   ATTRIB_VAL( WGL_STENCIL_BITS_ARB, ppfd->cStencilBits );
721
722   ATTRIB_VAL( WGL_DOUBLE_BUFFER_ARB, ( fgState.DisplayMode & GLUT_DOUBLE ) != 0 );
723
724   if ( fgState.DisplayMode & GLUT_SRGB ) {
725     ATTRIB_VAL( WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, TRUE );
726   }
727
728   ATTRIB_VAL( WGL_SAMPLE_BUFFERS_ARB, GL_TRUE );
729   ATTRIB_VAL( WGL_SAMPLES_ARB, fgState.SampleNumber );
730   ATTRIB( 0 );
731 }
732 #endif
733
734 GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
735                               unsigned char layer_type )
736 {
737 #if defined(_WIN32_WCE)
738     return GL_TRUE;
739 #else
740     PIXELFORMATDESCRIPTOR pfd;
741     PIXELFORMATDESCRIPTOR* ppfd = &pfd;
742     int pixelformat;
743     HDC current_hDC;
744     GLboolean success;
745
746     if (checkOnly)
747       current_hDC = CreateDC(TEXT("DISPLAY"), NULL ,NULL ,NULL);
748     else
749       current_hDC = window->Window.Device;
750
751     fghFillPFD( ppfd, current_hDC, layer_type );
752     pixelformat = ChoosePixelFormat( current_hDC, ppfd );
753
754     /* windows hack for multismapling/sRGB */
755     if ( ( fgState.DisplayMode & GLUT_MULTISAMPLE ) ||
756          ( fgState.DisplayMode & GLUT_SRGB ) )
757     {        
758         HGLRC rc, rc_before=wglGetCurrentContext();
759         HWND hWnd;
760         HDC hDC, hDC_before=wglGetCurrentDC();
761         WNDCLASS wndCls;
762
763         /* create a dummy window */
764         ZeroMemory(&wndCls, sizeof(wndCls));
765         wndCls.lpfnWndProc = DefWindowProc;
766         wndCls.hInstance = fgDisplay.Instance;
767         wndCls.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
768         wndCls.lpszClassName = _T("FREEGLUT_dummy");
769         RegisterClass( &wndCls );
770
771         hWnd=CreateWindow(_T("FREEGLUT_dummy"), _T(""), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW , 0,0,0,0, 0, 0, fgDisplay.Instance, 0 );
772         hDC=GetDC(hWnd);
773         SetPixelFormat( hDC, pixelformat, ppfd );
774
775         rc = wglCreateContext( hDC );
776         wglMakeCurrent(hDC, rc);
777
778         if ( fghIsExtensionSupported( hDC, "WGL_ARB_multisample" ) )
779         {
780             PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARBProc =
781               (PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatARB");
782             if ( wglChoosePixelFormatARBProc )
783             {
784                 int attributes[100];
785                 int iPixelFormat;
786                 BOOL bValid;
787                 float fAttributes[] = { 0, 0 };
788                 UINT numFormats;
789                 fghFillPixelFormatAttributes( attributes, ppfd );
790                 bValid = wglChoosePixelFormatARBProc(hDC, attributes, fAttributes, 1, &iPixelFormat, &numFormats);
791
792                 if ( bValid && numFormats > 0 )
793                 {
794                     pixelformat = iPixelFormat;
795                 }
796             }
797         }
798
799         wglMakeCurrent( hDC_before, rc_before);
800         wglDeleteContext(rc);
801         ReleaseDC(hWnd, hDC);
802         DestroyWindow(hWnd);
803         UnregisterClass(_T("FREEGLUT_dummy"), fgDisplay.Instance);
804     }
805
806     success = ( pixelformat != 0 ) && ( checkOnly || SetPixelFormat( current_hDC, pixelformat, ppfd ) );
807
808     if (checkOnly)
809         DeleteDC(current_hDC);
810
811     return success;
812 #endif /* defined(_WIN32_WCE) */
813 }
814
815 #endif  /* TARGET_HOST_MS_WINDOWS */
816
817 /*
818  * Sets the OpenGL context and the fgStructure "Current Window" pointer to
819  * the window structure passed in.
820  */
821 void fgSetWindow ( SFG_Window *window )
822 {
823 #if TARGET_HOST_POSIX_X11
824     if ( window )
825     {
826         glXMakeContextCurrent(
827             fgDisplay.Display,
828             window->Window.Handle,
829             window->Window.Handle,
830             window->Window.Context
831         );
832     }
833 #elif TARGET_HOST_MS_WINDOWS
834     if ( window != fgStructure.CurrentWindow )
835     {
836         if( fgStructure.CurrentWindow )
837             ReleaseDC( fgStructure.CurrentWindow->Window.Handle,
838                        fgStructure.CurrentWindow->Window.Device );
839
840         if ( window )
841         {
842             window->Window.Device = GetDC( window->Window.Handle );
843             wglMakeCurrent(
844                 window->Window.Device,
845                 window->Window.Context
846             );
847         }
848     }
849 #endif
850     fgStructure.CurrentWindow = window;
851 }
852
853 #if TARGET_HOST_MS_WINDOWS
854
855 /* Computes position of corners of window Rect (outer position including
856  * decorations) based on the provided client rect and based on the style
857  * of the window in question.
858  * If posIsOutside is set to true, the input client Rect is taken to follow
859  * freeGLUT's window specification convention in which the top-left corner
860  * is at the outside of the window, while the size
861  * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
862  * area.
863  */
864 void fghComputeWindowRectFromClientArea_UseStyle( const DWORD windowStyle, RECT *clientRect, BOOL posIsOutside )
865 {
866     int xBorderWidth = 0, yBorderWidth = 0;
867
868     /* If window has title bar, correct rect for it */
869     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... */
870         if (posIsOutside)
871             clientRect->bottom += GetSystemMetrics( SM_CYCAPTION );
872         else
873             clientRect->top -= GetSystemMetrics( SM_CYCAPTION );
874
875     /* get width of window's borders (frame), correct rect for it.
876      * Note, borders can be of zero width if style does not specify borders
877      */
878     fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth);
879     if (posIsOutside)
880     {
881         clientRect->right  += xBorderWidth * 2;
882         clientRect->bottom += yBorderWidth * 2;
883     }
884     else
885     {
886         clientRect->left   -= xBorderWidth;
887         clientRect->right  += xBorderWidth;
888         clientRect->top    -= yBorderWidth;
889         clientRect->bottom += yBorderWidth;
890     }
891 }
892
893 /* Computes position of corners of window Rect (outer position including
894  * decorations) based on the provided client rect and based on the style
895  * of the window in question. If the window pointer or the window handle
896  * is NULL, a fully decorated window (caption and border) is assumed.
897  * Furthermore, if posIsOutside is set to true, the input client Rect is
898  * taken to follow freeGLUT's window specification convention in which the
899  * top-left corner is at the outside of the window, while the size
900  * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
901  * area.
902 */
903 void fghComputeWindowRectFromClientArea_QueryWindow( const SFG_Window *window, RECT *clientRect, BOOL posIsOutside )
904 {
905     DWORD windowStyle = 0;
906
907     if (window && window->Window.Handle)
908         windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE);
909     else
910         windowStyle = WS_OVERLAPPEDWINDOW;
911
912     fghComputeWindowRectFromClientArea_UseStyle(windowStyle, clientRect, posIsOutside);
913 }
914
915 /* Computes position of corners of client area (drawable area) of a window
916  * based on the provided window Rect (outer position including decorations)
917  * and based on the style of the window in question. If the window pointer
918  * or the window handle is NULL, a fully decorated window (caption and
919  * border) is assumed.
920  * Furthermore, if wantPosOutside is set to true, the output client Rect
921  * will follow freeGLUT's window specification convention in which the
922  * top-left corner is at the outside of the window, the size
923  * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
924  * area.
925  */
926 void fghComputeClientAreaFromWindowRect( const SFG_Window *window, RECT *windowRect, BOOL wantPosOutside )
927 {
928     DWORD windowStyle = 0;
929     int xBorderWidth = 0, yBorderWidth = 0;
930
931     if (window && window->Window.Handle)
932         windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE);
933     else
934         windowStyle = WS_OVERLAPPEDWINDOW;
935
936     /* If window has title bar, correct rect for it */
937     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... */
938         if (wantPosOutside)
939             windowRect->bottom -= GetSystemMetrics( SM_CYCAPTION );
940         else
941             windowRect->top    += GetSystemMetrics( SM_CYCAPTION );
942
943     /* get width of window's borders (frame), correct rect for it.
944      * Note, borders can be of zero width if style does not specify borders
945      */
946     fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth);
947     if (wantPosOutside)
948     {
949         windowRect->right  -= xBorderWidth * 2;
950         windowRect->bottom -= yBorderWidth * 2;
951     }
952     else
953     {
954         windowRect->left   += xBorderWidth;
955         windowRect->right  -= xBorderWidth;
956         windowRect->top    += yBorderWidth;
957         windowRect->bottom -= yBorderWidth;
958     }
959 }
960
961 /* Gets the rect describing the client area (drawable area) of the
962  * specified window.
963  * Returns an empty rect if window pointer or window handle is NULL.
964  * If wantPosOutside is set to true, the output client Rect
965  * will follow freeGLUT's window specification convention in which the
966  * top-left corner is at the outside of the window, while the size
967  * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
968  * area.
969  */
970 RECT fghGetClientArea( const SFG_Window *window, BOOL wantPosOutside )
971 {
972     RECT windowRect = {0,0,0,0};
973
974     freeglut_return_val_if_fail((window && window->Window.Handle),windowRect);
975     
976     /*
977      * call GetWindowRect()
978      * (this returns the pixel coordinates of the outside of the window)
979      */
980     GetWindowRect( window->Window.Handle, &windowRect );
981
982     /* Then correct the results */
983     fghComputeClientAreaFromWindowRect(window, &windowRect, wantPosOutside);
984
985     return windowRect;
986 }
987
988 /* Returns the width of the window borders based on the window's style.
989  */
990 void fghGetBorderWidth(const DWORD windowStyle, int* xBorderWidth, int* yBorderWidth)
991 {
992     if (windowStyle & WS_THICKFRAME)
993     {
994         *xBorderWidth = GetSystemMetrics(SM_CXSIZEFRAME);
995         *yBorderWidth = GetSystemMetrics(SM_CYSIZEFRAME);
996     }
997     else if (windowStyle & WS_DLGFRAME)
998     {
999         *xBorderWidth = GetSystemMetrics(SM_CXFIXEDFRAME);
1000         *yBorderWidth = GetSystemMetrics(SM_CYFIXEDFRAME);
1001     }
1002     else
1003     {
1004         *xBorderWidth = 0;
1005         *yBorderWidth = 0;
1006     }
1007 }
1008
1009 #if(WINVER >= 0x500)
1010 typedef struct
1011 {
1012       int *x;
1013       int *y;
1014       const char *name;
1015 } m_proc_t;
1016
1017 static BOOL CALLBACK m_proc(HMONITOR mon,
1018                             HDC hdc,
1019                             LPRECT rect,
1020                             LPARAM data)
1021 {
1022       m_proc_t *dp=(m_proc_t *)data;
1023       MONITORINFOEX info;
1024       BOOL res;
1025       info.cbSize=sizeof(info);
1026       res=GetMonitorInfo(mon,(LPMONITORINFO)&info);
1027       if( res )
1028       {
1029           if( strcmp(dp->name,info.szDevice)==0 )
1030           {
1031               *(dp->x)=info.rcMonitor.left;
1032               *(dp->y)=info.rcMonitor.top;
1033               return FALSE;
1034           }
1035       }
1036       return TRUE;
1037 }
1038
1039 /* 
1040  * this function returns the origin of the screen identified by
1041  * fgDisplay.DisplayName, and 0 otherwise.
1042  * This is used in fgOpenWindow to open the gamemode window on the screen
1043  * identified by the -display command line argument. The function should
1044  * not be called otherwise.
1045  */
1046
1047 static void get_display_origin(int *xp,int *yp)
1048 {
1049     *xp = 0;
1050     *yp = 0;
1051
1052     if( fgDisplay.DisplayName )
1053     {
1054         m_proc_t st;
1055         st.x=xp;
1056         st.y=yp;
1057         st.name=fgDisplay.DisplayName;
1058         EnumDisplayMonitors(0,0,m_proc,(LPARAM)&st);
1059     }
1060 }
1061 #else
1062 #pragma message( "-display parameter only works if compiled with WINVER >= 0x0500")
1063
1064 static void get_display_origin(int *xp,int *yp)
1065 {
1066     *xp = 0;
1067     *yp = 0;
1068
1069     if( fgDisplay.DisplayName )
1070     {
1071         fgWarning( "for working -display support FreeGLUT must be compiled with WINVER >= 0x0500");
1072     }
1073 }
1074 #endif
1075 #endif
1076
1077
1078 #if TARGET_HOST_POSIX_X11
1079 static Bool fghWindowIsVisible( Display *display, XEvent *event, XPointer arg)
1080 {
1081     Window window = (Window)arg;
1082     return (event->type == MapNotify) && (event->xmap.window == window);
1083 }
1084 #endif
1085
1086
1087 /*
1088  * Opens a window. Requires a SFG_Window object created and attached
1089  * to the freeglut structure. OpenGL context is created here.
1090  */
1091 void fgOpenWindow( SFG_Window* window, const char* title,
1092                    GLboolean positionUse, int x, int y,
1093                    GLboolean sizeUse, int w, int h,
1094                    GLboolean gameMode, GLboolean isSubWindow )
1095 {
1096 #if TARGET_HOST_POSIX_X11
1097     XVisualInfo * visualInfo = NULL;
1098     XSetWindowAttributes winAttr;
1099     XTextProperty textProperty;
1100     XSizeHints sizeHints;
1101     XWMHints wmHints;
1102     XEvent eventReturnBuffer; /* return buffer required for a call */
1103     unsigned long mask;
1104     int num_FBConfigs, i;
1105     unsigned int current_DisplayMode = fgState.DisplayMode ;
1106
1107     /* Save the display mode if we are creating a menu window */
1108     if( window->IsMenu && ( ! fgStructure.MenuContext ) )
1109         fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ;
1110
1111     window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs );
1112
1113     if( window->IsMenu && ( ! fgStructure.MenuContext ) )
1114         fgState.DisplayMode = current_DisplayMode ;
1115
1116     if( ! window->Window.FBConfig )
1117     {
1118         /*
1119          * The "fgChooseFBConfig" returned a null meaning that the visual
1120          * context is not available.
1121          * Try a couple of variations to see if they will work.
1122          */
1123         if( !( fgState.DisplayMode & GLUT_DOUBLE ) )
1124         {
1125             fgState.DisplayMode |= GLUT_DOUBLE ;
1126             window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs );
1127             fgState.DisplayMode &= ~GLUT_DOUBLE;
1128         }
1129
1130         if( fgState.DisplayMode & GLUT_MULTISAMPLE )
1131         {
1132             fgState.DisplayMode &= ~GLUT_MULTISAMPLE ;
1133             window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs );
1134             fgState.DisplayMode |= GLUT_MULTISAMPLE;
1135         }
1136     }
1137
1138     FREEGLUT_INTERNAL_ERROR_EXIT( window->Window.FBConfig != NULL,
1139                                   "FBConfig with necessary capabilities not found", "fgOpenWindow" );
1140
1141     /*  Get the X visual.  */
1142     for (i = 0; i < num_FBConfigs; i++) {
1143             visualInfo = glXGetVisualFromFBConfig( fgDisplay.Display,
1144                                                    window->Window.FBConfig[i] );
1145             if (visualInfo)
1146                 break;
1147     }
1148
1149     FREEGLUT_INTERNAL_ERROR_EXIT( visualInfo != NULL,
1150                                   "visualInfo could not be retrieved from FBConfig", "fgOpenWindow" );
1151
1152     /*
1153      * XXX HINT: the masks should be updated when adding/removing callbacks.
1154      * XXX       This might speed up message processing. Is that true?
1155      * XXX
1156      * XXX A: Not appreciably, but it WILL make it easier to debug.
1157      * XXX    Try tracing old GLUT and try tracing freeglut.  Old GLUT
1158      * XXX    turns off events that it doesn't need and is a whole lot
1159      * XXX    more pleasant to trace.  (Think mouse-motion!  Tons of
1160      * XXX    ``bonus'' GUI events stream in.)
1161      */
1162     winAttr.event_mask        =
1163         StructureNotifyMask | SubstructureNotifyMask | ExposureMask |
1164         ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
1165         VisibilityChangeMask | EnterWindowMask | LeaveWindowMask |
1166         PointerMotionMask | ButtonMotionMask;
1167     winAttr.background_pixmap = None;
1168     winAttr.background_pixel  = 0;
1169     winAttr.border_pixel      = 0;
1170
1171     winAttr.colormap = XCreateColormap(
1172         fgDisplay.Display, fgDisplay.RootWindow,
1173         visualInfo->visual, AllocNone
1174     );
1175
1176     mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
1177
1178     if( window->IsMenu || ( gameMode == GL_TRUE ) )
1179     {
1180         winAttr.override_redirect = True;
1181         mask |= CWOverrideRedirect;
1182     }
1183
1184     if( ! positionUse )
1185         x = y = -1; /* default window position */
1186     if( ! sizeUse )
1187         w = h = 300; /* default window size */
1188
1189     window->Window.Handle = XCreateWindow(
1190         fgDisplay.Display,
1191         window->Parent == NULL ? fgDisplay.RootWindow :
1192         window->Parent->Window.Handle,
1193         x, y, w, h, 0,
1194         visualInfo->depth, InputOutput,
1195         visualInfo->visual, mask,
1196         &winAttr
1197     );
1198
1199     /*
1200      * The GLX context creation, possibly trying the direct context rendering
1201      *  or else use the current context if the user has so specified
1202      */
1203
1204     if( window->IsMenu )
1205     {
1206         /*
1207          * If there isn't already an OpenGL rendering context for menu
1208          * windows, make one
1209          */
1210         if( !fgStructure.MenuContext )
1211         {
1212             fgStructure.MenuContext =
1213                 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
1214             fgStructure.MenuContext->MContext = fghCreateNewContext( window );
1215         }
1216
1217         /* window->Window.Context = fgStructure.MenuContext->MContext; */
1218         window->Window.Context = fghCreateNewContext( window );
1219     }
1220     else if( fgState.UseCurrentContext )
1221     {
1222         window->Window.Context = glXGetCurrentContext( );
1223
1224         if( ! window->Window.Context )
1225             window->Window.Context = fghCreateNewContext( window );
1226     }
1227     else
1228         window->Window.Context = fghCreateNewContext( window );
1229
1230 #if !defined( __FreeBSD__ ) && !defined( __NetBSD__ )
1231     if(  !glXIsDirect( fgDisplay.Display, window->Window.Context ) )
1232     {
1233       if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT )
1234         fgError( "Unable to force direct context rendering for window '%s'",
1235                  title );
1236     }
1237 #endif
1238
1239     /*
1240      * XXX Assume the new window is visible by default
1241      * XXX Is this a  safe assumption?
1242      */
1243     window->State.Visible = GL_TRUE;
1244
1245     sizeHints.flags = 0;
1246     if ( positionUse )
1247         sizeHints.flags |= USPosition;
1248     if ( sizeUse )
1249         sizeHints.flags |= USSize;
1250
1251     /*
1252      * Fill in the size hints values now (the x, y, width and height
1253      * settings are obsolete, are there any more WMs that support them?)
1254      * Unless the X servers actually stop supporting these, we should
1255      * continue to fill them in.  It is *not* our place to tell the user
1256      * that they should replace a window manager that they like, and which
1257      * works, just because *we* think that it's not "modern" enough.
1258      */
1259     sizeHints.x      = x;
1260     sizeHints.y      = y;
1261     sizeHints.width  = w;
1262     sizeHints.height = h;
1263
1264     wmHints.flags = StateHint;
1265     wmHints.initial_state = fgState.ForceIconic ? IconicState : NormalState;
1266     /* Prepare the window and iconified window names... */
1267     XStringListToTextProperty( (char **) &title, 1, &textProperty );
1268
1269     XSetWMProperties(
1270         fgDisplay.Display,
1271         window->Window.Handle,
1272         &textProperty,
1273         &textProperty,
1274         0,
1275         0,
1276         &sizeHints,
1277         &wmHints,
1278         NULL
1279     );
1280     XFree( textProperty.value );
1281
1282     XSetWMProtocols( fgDisplay.Display, window->Window.Handle,
1283                      &fgDisplay.DeleteWindow, 1 );
1284
1285     glXMakeContextCurrent(
1286         fgDisplay.Display,
1287         window->Window.Handle,
1288         window->Window.Handle,
1289         window->Window.Context
1290     );
1291
1292     /* register extension events _before_ window is mapped */
1293     #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
1294        fgRegisterDevices( fgDisplay.Display, &(window->Window.Handle) );
1295     #endif
1296
1297     XMapWindow( fgDisplay.Display, window->Window.Handle );
1298
1299     XFree(visualInfo);
1300
1301     if( !isSubWindow)
1302         XPeekIfEvent( fgDisplay.Display, &eventReturnBuffer, &fghWindowIsVisible, (XPointer)(window->Window.Handle) );
1303
1304 #elif TARGET_HOST_MS_WINDOWS
1305
1306     WNDCLASS wc;
1307     DWORD flags   = 0;
1308     DWORD exFlags = 0;
1309     ATOM atom;
1310
1311     /* Grab the window class we have registered on glutInit(): */
1312     atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc );
1313     FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Info Not Found",
1314                                    "fgOpenWindow" );
1315
1316     /* Determine window style flags*/
1317     if( gameMode )
1318     {
1319         FREEGLUT_INTERNAL_ERROR_EXIT ( window->Parent == NULL,
1320                                        "Game mode being invoked on a subwindow",
1321                                        "fgOpenWindow" );
1322
1323         /*
1324          * Set the window creation flags appropriately to make the window
1325          * entirely visible:
1326          */
1327         flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
1328     }
1329     else
1330     {
1331         flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
1332
1333         /*
1334          * There's a small difference between creating the top, child and
1335          * menu windows
1336          */
1337         if ( window->IsMenu )
1338         {
1339             flags |= WS_POPUP;
1340             exFlags |= WS_EX_TOOLWINDOW;
1341         }
1342 #if defined(_WIN32_WCE)
1343         /* no decorations for windows CE */
1344 #else
1345         /* if this is not a subwindow (child), set its style based on the requested display mode */
1346         else if( window->Parent == NULL )
1347             if ( fgState.DisplayMode & GLUT_BORDERLESS )
1348             {
1349                 /* no window decorations needed */
1350             }
1351             else if ( fgState.DisplayMode & GLUT_CAPTIONLESS )
1352                 /* only window decoration is a border, no title bar or buttons */
1353                 flags |= WS_DLGFRAME;
1354             else
1355                 /* window decoration are a border, title bar and buttons.
1356                  * NB: we later query whether the window has a title bar or
1357                  * not by testing for the maximize button, as the test for
1358                  * WS_CAPTION can be true without the window having a title
1359                  * bar. This style WS_OVERLAPPEDWINDOW gives you a maximize
1360                  * button. */
1361                 flags |= WS_OVERLAPPEDWINDOW;
1362 #endif
1363         else
1364             /* subwindows always have no decoration, but are marked as a child window to the OS */
1365             flags |= WS_CHILD;
1366     }
1367
1368     /* determine window size and position */
1369     if( gameMode )
1370     {
1371         /* if in gamemode, query the origin of specified by the -display
1372          * command line parameter (if any) and offset the upper-left corner
1373          * of the window so we create the window on that screen.
1374          * The -display argument doesn't do anything if not trying to enter
1375          * gamemode.
1376          */
1377         int xoff=0, yoff=0;
1378         get_display_origin(&xoff,&yoff);
1379         x += xoff;
1380         y += yoff;
1381     }
1382     if( !positionUse )
1383     {
1384         x = CW_USEDEFAULT;
1385         y = CW_USEDEFAULT;
1386     }
1387     if( !sizeUse )
1388     {
1389         if( ! window->IsMenu )
1390         {
1391             w = CW_USEDEFAULT;
1392             h = CW_USEDEFAULT;
1393         }
1394         else /* fail safe - Windows can make a window of size (0, 0) */
1395             w = h = 300; /* default window size */
1396     }
1397     /* store requested client area width and height */
1398     window->State.Width = w;
1399     window->State.Height = h;
1400
1401 #if !defined(_WIN32_WCE)    /* no decorations for windows CE */
1402     if( sizeUse )
1403     {
1404         RECT windowRect;
1405         /*
1406          * Update the window dimensions, taking the window decorations
1407          * into account.  FreeGLUT is to create the window with the
1408          * topleft outside corner at (x,y) and with client area
1409          * dimensions (w,h).
1410          * note: don't need to do this when w=h=CW_USEDEFAULT, so in the
1411          * if( sizeUse ) here is convenient.
1412          */
1413         windowRect.left     = x;
1414         windowRect.top      = y;
1415         windowRect.right    = x+w;
1416         windowRect.bottom   = y+h;
1417
1418         fghComputeWindowRectFromClientArea_UseStyle(flags,&windowRect,TRUE);
1419
1420         w = windowRect.right - windowRect.left;
1421         h = windowRect.bottom- windowRect.top;
1422     }
1423 #endif /* !defined(_WIN32_WCE) */
1424
1425 #if defined(_WIN32_WCE)
1426     {
1427         wchar_t* wstr = fghWstrFromStr(title);
1428
1429         window->Window.Handle = CreateWindow(
1430             _T("FREEGLUT"),
1431             wstr,
1432             WS_VISIBLE | WS_POPUP,
1433             0,0, 240,320,
1434             NULL,
1435             NULL,
1436             fgDisplay.Instance,
1437             (LPVOID) window
1438         );
1439
1440         free(wstr);
1441
1442         SHFullScreen(window->Window.Handle, SHFS_HIDESTARTICON);
1443         SHFullScreen(window->Window.Handle, SHFS_HIDESIPBUTTON);
1444         SHFullScreen(window->Window.Handle, SHFS_HIDETASKBAR);
1445         MoveWindow(window->Window.Handle, 0, 0, 240, 320, TRUE);
1446         ShowWindow(window->Window.Handle, SW_SHOW);
1447         UpdateWindow(window->Window.Handle);
1448     }
1449 #else
1450     window->Window.Handle = CreateWindowEx(
1451         exFlags,
1452         _T("FREEGLUT"),
1453         title,
1454         flags,
1455         x, y, w, h,
1456         (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle,
1457         (HMENU) NULL,
1458         fgDisplay.Instance,
1459         (LPVOID) window
1460     );
1461 #endif /* defined(_WIN32_WCE) */
1462
1463     if( !( window->Window.Handle ) )
1464         fgError( "Failed to create a window (%s)!", title );
1465
1466 #if !defined(_WIN32_WCE)
1467     /* Need to set requested style again, apparently Windows doesn't listen when requesting windows without title bar or borders */
1468     SetWindowLong(window->Window.Handle, GWL_STYLE, flags);
1469     SetWindowPos(window->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
1470 #endif /* defined(_WIN32_WCE) */
1471
1472     /* Make a menu window always on top - fix Feature Request 947118 */
1473     if( window->IsMenu || gameMode )
1474         SetWindowPos(
1475                         window->Window.Handle,
1476                         HWND_TOPMOST,
1477                         0, 0, 0, 0,
1478                         SWP_NOMOVE | SWP_NOSIZE
1479                     );
1480
1481     /* Enable multitouch: additional flag TWF_FINETOUCH, TWF_WANTPALM */
1482     #ifdef WM_TOUCH
1483         if (fghRegisterTouchWindow == (pRegisterTouchWindow)0xDEADBEEF) 
1484                         fghRegisterTouchWindow = (pRegisterTouchWindow)GetProcAddress(GetModuleHandle("user32"),"RegisterTouchWindow");
1485                 if (fghRegisterTouchWindow)
1486              fghRegisterTouchWindow( window->Window.Handle, TWF_FINETOUCH | TWF_WANTPALM );
1487     #endif
1488
1489 #if defined(_WIN32_WCE)
1490     ShowWindow( window->Window.Handle, SW_SHOW );
1491 #else
1492     ShowWindow( window->Window.Handle,
1493                 fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW );
1494 #endif /* defined(_WIN32_WCE) */
1495
1496     UpdateWindow( window->Window.Handle );
1497     ShowCursor( TRUE );  /* XXX Old comments say "hide cursor"! */
1498
1499 #endif
1500
1501     fgSetWindow( window );
1502
1503     window->Window.DoubleBuffered =
1504         ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0;
1505
1506     if ( ! window->Window.DoubleBuffered )
1507     {
1508         glDrawBuffer ( GL_FRONT );
1509         glReadBuffer ( GL_FRONT );
1510     }
1511 }
1512
1513 /*
1514  * Closes a window, destroying the frame and OpenGL context
1515  */
1516 void fgCloseWindow( SFG_Window* window )
1517 {
1518     /* if we're in gamemode and we're closing the gamemode window,
1519      * call glutLeaveGameMode first to make sure the gamemode is
1520      * properly closed before closing the window
1521      */
1522     if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==window->ID)
1523         glutLeaveGameMode();
1524
1525 #if TARGET_HOST_POSIX_X11
1526
1527     if( window->Window.Context )
1528         glXDestroyContext( fgDisplay.Display, window->Window.Context );
1529     XFree( window->Window.FBConfig );
1530
1531     if( window->Window.Handle ) {
1532         XDestroyWindow( fgDisplay.Display, window->Window.Handle );
1533     }
1534     /* XFlush( fgDisplay.Display ); */ /* XXX Shouldn't need this */
1535
1536 #elif TARGET_HOST_MS_WINDOWS
1537
1538     /* Make sure we don't close a window with current context active */
1539     if( fgStructure.CurrentWindow == window )
1540         wglMakeCurrent( NULL, NULL );
1541
1542     /*
1543      * Step through the list of windows.  If the rendering context
1544      * is not being used by another window, then we delete it.
1545      */
1546     {
1547         int used = FALSE ;
1548         SFG_Window *iter ;
1549
1550         for( iter = (SFG_Window *)fgStructure.Windows.First;
1551              iter;
1552              iter = (SFG_Window *)iter->Node.Next )
1553         {
1554             if( ( iter->Window.Context == window->Window.Context ) &&
1555                 ( iter != window ) )
1556                 used = TRUE;
1557         }
1558
1559         if( ! used )
1560             wglDeleteContext( window->Window.Context );
1561     }
1562
1563     DestroyWindow( window->Window.Handle );
1564 #endif
1565 }
1566
1567
1568 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
1569
1570 /*
1571  * Creates a new top-level freeglut window
1572  */
1573 int FGAPIENTRY glutCreateWindow( const char* title )
1574 {
1575     /* XXX GLUT does not exit; it simply calls "glutInit" quietly if the
1576      * XXX application has not already done so.  The "freeglut" community
1577      * XXX decided not to go this route (freeglut-developer e-mail from
1578      * XXX Steve Baker, 12/16/04, 4:22 PM CST, "Re: [Freeglut-developer]
1579      * XXX Desired 'freeglut' behaviour when there is no current window"
1580      */
1581     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateWindow" );
1582
1583     return fgCreateWindow( NULL, title, fgState.Position.Use,
1584                            fgState.Position.X, fgState.Position.Y,
1585                            fgState.Size.Use, fgState.Size.X, fgState.Size.Y,
1586                            GL_FALSE, GL_FALSE )->ID;
1587 }
1588
1589 #if TARGET_HOST_MS_WINDOWS
1590 int FGAPIENTRY __glutCreateWindowWithExit( const char *title, void (__cdecl *exit_function)(int) )
1591 {
1592   __glutExitFunc = exit_function;
1593   return glutCreateWindow( title );
1594 }
1595 #endif
1596
1597 /*
1598  * This function creates a sub window.
1599  */
1600 int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h )
1601 {
1602     int ret = 0;
1603     SFG_Window* window = NULL;
1604     SFG_Window* parent = NULL;
1605
1606     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateSubWindow" );
1607     parent = fgWindowByID( parentID );
1608     freeglut_return_val_if_fail( parent != NULL, 0 );
1609     if ( x < 0 )
1610     {
1611         x = parent->State.Width + x ;
1612         if ( w >= 0 ) x -= w ;
1613     }
1614
1615     if ( w < 0 ) w = parent->State.Width - x + w ;
1616     if ( w < 0 )
1617     {
1618         x += w ;
1619         w = -w ;
1620     }
1621
1622     if ( y < 0 )
1623     {
1624         y = parent->State.Height + y ;
1625         if ( h >= 0 ) y -= h ;
1626     }
1627
1628     if ( h < 0 ) h = parent->State.Height - y + h ;
1629     if ( h < 0 )
1630     {
1631         y += h ;
1632         h = -h ;
1633     }
1634
1635     window = fgCreateWindow( parent, "", GL_TRUE, x, y, GL_TRUE, w, h, GL_FALSE, GL_FALSE );
1636     ret = window->ID;
1637
1638     return ret;
1639 }
1640
1641 /*
1642  * Destroys a window and all of its subwindows
1643  */
1644 void FGAPIENTRY glutDestroyWindow( int windowID )
1645 {
1646     SFG_Window* window;
1647     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyWindow" );
1648     window = fgWindowByID( windowID );
1649     freeglut_return_if_fail( window != NULL );
1650     {
1651         fgExecutionState ExecState = fgState.ExecState;
1652         fgAddToWindowDestroyList( window );
1653         fgState.ExecState = ExecState;
1654     }
1655 }
1656
1657 /*
1658  * This function selects the current window
1659  */
1660 void FGAPIENTRY glutSetWindow( int ID )
1661 {
1662     SFG_Window* window = NULL;
1663
1664     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindow" );
1665     if( fgStructure.CurrentWindow != NULL )
1666         if( fgStructure.CurrentWindow->ID == ID )
1667             return;
1668
1669     window = fgWindowByID( ID );
1670     if( window == NULL )
1671     {
1672         fgWarning( "glutSetWindow(): window ID %d not found!", ID );
1673         return;
1674     }
1675
1676     fgSetWindow( window );
1677 }
1678
1679 /*
1680  * This function returns the ID number of the current window, 0 if none exists
1681  */
1682 int FGAPIENTRY glutGetWindow( void )
1683 {
1684     SFG_Window *win = fgStructure.CurrentWindow;
1685     /*
1686      * Since GLUT did not throw an error if this function was called without a prior call to
1687      * "glutInit", this function shouldn't do so here.  Instead let us return a zero.
1688      * See Feature Request "[ 1307049 ] glutInit check".
1689      */
1690     if ( ! fgState.Initialised )
1691         return 0;
1692
1693     while ( win && win->IsMenu )
1694         win = win->Parent;
1695     return win ? win->ID : 0;
1696 }
1697
1698 /*
1699  * This function makes the current window visible
1700  */
1701 void FGAPIENTRY glutShowWindow( void )
1702 {
1703     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutShowWindow" );
1704     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutShowWindow" );
1705
1706 #if TARGET_HOST_POSIX_X11
1707
1708     XMapWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle );
1709     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1710
1711 #elif TARGET_HOST_MS_WINDOWS
1712
1713     ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_SHOW );
1714
1715 #endif
1716
1717     fgStructure.CurrentWindow->State.Redisplay = GL_TRUE;
1718 }
1719
1720 /*
1721  * This function hides the current window
1722  */
1723 void FGAPIENTRY glutHideWindow( void )
1724 {
1725     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutHideWindow" );
1726     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutHideWindow" );
1727
1728 #if TARGET_HOST_POSIX_X11
1729
1730     if( fgStructure.CurrentWindow->Parent == NULL )
1731         XWithdrawWindow( fgDisplay.Display,
1732                          fgStructure.CurrentWindow->Window.Handle,
1733                          fgDisplay.Screen );
1734     else
1735         XUnmapWindow( fgDisplay.Display,
1736                       fgStructure.CurrentWindow->Window.Handle );
1737     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1738
1739 #elif TARGET_HOST_MS_WINDOWS
1740
1741     ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_HIDE );
1742
1743 #endif
1744
1745     fgStructure.CurrentWindow->State.Redisplay = GL_FALSE;
1746 }
1747
1748 /*
1749  * Iconify the current window (top-level windows only)
1750  */
1751 void FGAPIENTRY glutIconifyWindow( void )
1752 {
1753     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIconifyWindow" );
1754     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIconifyWindow" );
1755
1756     fgStructure.CurrentWindow->State.Visible   = GL_FALSE;
1757 #if TARGET_HOST_POSIX_X11
1758
1759     XIconifyWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
1760                     fgDisplay.Screen );
1761     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1762
1763 #elif TARGET_HOST_MS_WINDOWS
1764
1765     ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_MINIMIZE );
1766
1767 #endif
1768
1769     fgStructure.CurrentWindow->State.Redisplay = GL_FALSE;
1770 }
1771
1772 /*
1773  * Set the current window's title
1774  */
1775 void FGAPIENTRY glutSetWindowTitle( const char* title )
1776 {
1777     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowTitle" );
1778     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowTitle" );
1779     if( ! fgStructure.CurrentWindow->Parent )
1780     {
1781 #if TARGET_HOST_POSIX_X11
1782
1783         XTextProperty text;
1784
1785         text.value = (unsigned char *) title;
1786         text.encoding = XA_STRING;
1787         text.format = 8;
1788         text.nitems = strlen( title );
1789
1790         XSetWMName(
1791             fgDisplay.Display,
1792             fgStructure.CurrentWindow->Window.Handle,
1793             &text
1794         );
1795
1796         XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1797
1798 #elif TARGET_HOST_MS_WINDOWS
1799 #    ifdef _WIN32_WCE
1800         {
1801             wchar_t* wstr = fghWstrFromStr(title);
1802             SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr );
1803             free(wstr);
1804         }
1805 #    else
1806         SetWindowText( fgStructure.CurrentWindow->Window.Handle, title );
1807 #    endif
1808
1809 #endif
1810     }
1811 }
1812
1813 /*
1814  * Set the current window's iconified title
1815  */
1816 void FGAPIENTRY glutSetIconTitle( const char* title )
1817 {
1818     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetIconTitle" );
1819     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetIconTitle" );
1820
1821     if( ! fgStructure.CurrentWindow->Parent )
1822     {
1823 #if TARGET_HOST_POSIX_X11
1824
1825         XTextProperty text;
1826
1827         text.value = (unsigned char *) title;
1828         text.encoding = XA_STRING;
1829         text.format = 8;
1830         text.nitems = strlen( title );
1831
1832         XSetWMIconName(
1833             fgDisplay.Display,
1834             fgStructure.CurrentWindow->Window.Handle,
1835             &text
1836         );
1837
1838         XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1839
1840 #elif TARGET_HOST_MS_WINDOWS
1841 #    ifdef _WIN32_WCE
1842         {
1843             wchar_t* wstr = fghWstrFromStr(title);
1844             SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr );
1845             free(wstr);
1846         }
1847 #    else
1848         SetWindowText( fgStructure.CurrentWindow->Window.Handle, title );
1849 #    endif
1850
1851 #endif
1852     }
1853 }
1854
1855 /*
1856  * Change the current window's size
1857  */
1858 void FGAPIENTRY glutReshapeWindow( int width, int height )
1859 {
1860     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" );
1861     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" );
1862
1863     if (glutGet(GLUT_FULL_SCREEN))
1864     {
1865       /*  Leave full screen state before resizing. */
1866       glutLeaveFullScreen();
1867     }
1868
1869     fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE;
1870     fgStructure.CurrentWindow->State.Width  = width ;
1871     fgStructure.CurrentWindow->State.Height = height;
1872 }
1873
1874 /*
1875  * Change the current window's position
1876  */
1877 void FGAPIENTRY glutPositionWindow( int x, int y )
1878 {
1879     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" );
1880     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" );
1881
1882     if (glutGet(GLUT_FULL_SCREEN))
1883     {
1884       /*  Leave full screen state before moving. */
1885       glutLeaveFullScreen();
1886     }
1887
1888 #if TARGET_HOST_POSIX_X11
1889
1890     XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
1891                  x, y );
1892     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1893
1894 #elif TARGET_HOST_MS_WINDOWS
1895
1896     {
1897         RECT winRect;
1898
1899         /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
1900         GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect );
1901         MoveWindow(
1902             fgStructure.CurrentWindow->Window.Handle,
1903             x,
1904             y,
1905             winRect.right - winRect.left,
1906             winRect.bottom - winRect.top,
1907             TRUE
1908         );
1909     }
1910
1911 #endif
1912 }
1913
1914 /*
1915  * Lowers the current window (by Z order change)
1916  */
1917 void FGAPIENTRY glutPushWindow( void )
1918 {
1919     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" );
1920     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" );
1921
1922 #if TARGET_HOST_POSIX_X11
1923
1924     XLowerWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle );
1925
1926 #elif TARGET_HOST_MS_WINDOWS
1927
1928     SetWindowPos(
1929         fgStructure.CurrentWindow->Window.Handle,
1930         HWND_BOTTOM,
1931         0, 0, 0, 0,
1932         SWP_NOSIZE | SWP_NOMOVE
1933     );
1934
1935 #endif
1936 }
1937
1938 /*
1939  * Raises the current window (by Z order change)
1940  */
1941 void FGAPIENTRY glutPopWindow( void )
1942 {
1943     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" );
1944     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" );
1945
1946 #if TARGET_HOST_POSIX_X11
1947
1948     XRaiseWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle );
1949
1950 #elif TARGET_HOST_MS_WINDOWS
1951
1952     SetWindowPos(
1953         fgStructure.CurrentWindow->Window.Handle,
1954         HWND_TOP,
1955         0, 0, 0, 0,
1956         SWP_NOSIZE | SWP_NOMOVE
1957     );
1958
1959 #endif
1960 }
1961
1962 /*
1963  * Resize the current window so that it fits the whole screen
1964  */
1965 void FGAPIENTRY glutFullScreen( void )
1966 {
1967     SFG_Window *win;
1968
1969     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );
1970     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );
1971
1972     win = fgStructure.CurrentWindow;
1973
1974     if (win->Parent)
1975     {
1976         /* Child windows cannot be made fullscreen, consistent with GLUT's behavior
1977          * Also, what would it mean for a child window to be fullscreen, given that it
1978          * is confined to its parent?
1979          */
1980         fgWarning("glutFullScreen called on a child window, ignoring...");
1981         return;
1982     }
1983     else if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==win->ID)
1984     {
1985         /* Ignore fullscreen call on GameMode window, those are always fullscreen already */
1986         return;
1987     }
1988
1989 #if TARGET_HOST_POSIX_X11
1990     if(!glutGet(GLUT_FULL_SCREEN)) {
1991         if(fghToggleFullscreen() != -1) {
1992             win->State.IsFullscreen = GL_TRUE;
1993         }
1994     }
1995
1996 #elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */
1997
1998     if (glutGet(GLUT_FULL_SCREEN))
1999     {
2000         /*  Leave full screen state before entering fullscreen again (resizing?) */
2001         glutLeaveFullScreen();
2002     }
2003
2004     {
2005 #if(WINVER >= 0x0500) /* Windows 2000 or later */
2006         DWORD s;
2007         RECT rect;
2008         HMONITOR hMonitor;
2009         MONITORINFO mi;
2010
2011         /* For fullscreen mode, first remove all window decoration
2012          * and set style to popup so it will overlap the taskbar
2013          * then force to maximize on the screen on which it has the most
2014          * overlap.
2015          */
2016
2017         
2018         /* store current window rect */
2019         GetWindowRect( win->Window.Handle, &win->State.OldRect );
2020
2021         /* store current window style */
2022         win->State.OldStyle = s = GetWindowLong(win->Window.Handle, GWL_STYLE);
2023
2024         /* remove decorations from style and add popup style*/
2025         s &= ~WS_OVERLAPPEDWINDOW;
2026         s |= WS_POPUP;
2027         SetWindowLong(win->Window.Handle, GWL_STYLE, s);
2028         SetWindowPos(win->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
2029
2030         /* For fullscreen mode, find the monitor that is covered the most
2031          * by the window and get its rect as the resize target.
2032              */
2033         hMonitor= MonitorFromRect(&win->State.OldRect, MONITOR_DEFAULTTONEAREST);
2034         mi.cbSize = sizeof(mi);
2035         GetMonitorInfo(hMonitor, &mi);
2036         rect = mi.rcMonitor;
2037 #else   /* if (WINVER >= 0x0500) */
2038         RECT rect;
2039
2040         /* For fullscreen mode, force the top-left corner to 0,0
2041          * and adjust the window rectangle so that the client area
2042          * covers the whole screen.
2043          */
2044
2045         rect.left   = 0;
2046         rect.top    = 0;
2047         rect.right  = fgDisplay.ScreenWidth;
2048         rect.bottom = fgDisplay.ScreenHeight;
2049
2050         AdjustWindowRect ( &rect, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS |
2051                                   WS_CLIPCHILDREN, FALSE );
2052 #endif  /* (WINVER >= 0x0500) */
2053
2054         /*
2055          * then resize window
2056          * SWP_NOACTIVATE     Do not activate the window
2057          * SWP_NOOWNERZORDER  Do not change position in z-order
2058          * SWP_NOSENDCHANGING Suppress WM_WINDOWPOSCHANGING message
2059          * SWP_NOZORDER       Retains the current Z order (ignore 2nd param)
2060          */
2061         SetWindowPos( fgStructure.CurrentWindow->Window.Handle,
2062                       HWND_TOP,
2063                       rect.left,
2064                       rect.top,
2065                       rect.right  - rect.left,
2066                       rect.bottom - rect.top,
2067                       SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
2068                       SWP_NOZORDER
2069                     );
2070
2071         win->State.IsFullscreen = GL_TRUE;
2072     }
2073 #endif
2074 }
2075
2076 /*
2077  * If we are fullscreen, resize the current window back to its original size
2078  */
2079 void FGAPIENTRY glutLeaveFullScreen( void )
2080 {
2081     SFG_Window *win;
2082
2083     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );
2084     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );
2085
2086     win = fgStructure.CurrentWindow;
2087
2088 #if TARGET_HOST_POSIX_X11
2089     if(glutGet(GLUT_FULL_SCREEN)) {
2090         if(fghToggleFullscreen() != -1) {
2091             win->State.IsFullscreen = GL_FALSE;
2092         }
2093     }
2094
2095 #elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */
2096     if (!glutGet(GLUT_FULL_SCREEN))
2097     {
2098         /* nothing to do */
2099         return;
2100     }
2101
2102     /* restore style of window before making it fullscreen */
2103     SetWindowLong(win->Window.Handle, GWL_STYLE, win->State.OldStyle);
2104     SetWindowPos(win->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
2105
2106     /* Then resize */
2107     SetWindowPos(win->Window.Handle,
2108         HWND_TOP,
2109         win->State.OldRect.left,
2110         win->State.OldRect.top,
2111         win->State.OldRect.right  - win->State.OldRect.left,
2112         win->State.OldRect.bottom - win->State.OldRect.top,
2113         SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
2114         SWP_NOZORDER
2115         );
2116
2117     win->State.IsFullscreen = GL_FALSE;
2118 #endif
2119 }
2120
2121 /*
2122  * Toggle the window's full screen state.
2123  */
2124 void FGAPIENTRY glutFullScreenToggle( void )
2125 {
2126     SFG_Window *win;
2127
2128     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" );
2129     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" );
2130
2131     win = fgStructure.CurrentWindow;
2132
2133 #if TARGET_HOST_POSIX_X11
2134     if(fghToggleFullscreen() != -1) {
2135         win->State.IsFullscreen = !win->State.IsFullscreen;
2136     }
2137 #elif TARGET_HOST_MS_WINDOWS
2138     if (!win->State.IsFullscreen)
2139         glutFullScreen();
2140     else
2141         glutLeaveFullScreen();
2142 #endif
2143 }
2144
2145 /*
2146  * A.Donev: Set and retrieve the window's user data
2147  */
2148 void* FGAPIENTRY glutGetWindowData( void )
2149 {
2150     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" );
2151     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" );
2152     return fgStructure.CurrentWindow->UserData;
2153 }
2154
2155 void FGAPIENTRY glutSetWindowData(void* data)
2156 {
2157     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" );
2158     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" );
2159     fgStructure.CurrentWindow->UserData = data;
2160 }
2161
2162 /*** END OF FILE ***/