7b87792cf9ade6c67823bdaa1f485fe3a7daf4f7
[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 #include <GL/freeglut.h>
29 #include "freeglut_internal.h"
30
31 #if TARGET_HOST_POSIX_X11
32 #include <limits.h>  /* LONG_MAX */
33 #endif
34
35 #if defined(_WIN32_WCE)
36 #   include <Aygshell.h>
37 #   ifdef FREEGLUT_LIB_PRAGMAS
38 #       pragma comment( lib, "Aygshell.lib" )
39 #   endif
40
41 static wchar_t* fghWstrFromStr(const char* str)
42 {
43     int i,len=strlen(str);
44     wchar_t* wstr = (wchar_t*)malloc(2*len+2);
45     for(i=0; i<len; i++)
46         wstr[i] = str[i];
47     wstr[len] = 0;
48     return wstr;
49 }
50
51 #endif /* defined(_WIN32_WCE) */
52
53 /*
54  * TODO BEFORE THE STABLE RELEASE:
55  *
56  *  fgChooseFBConfig()      -- OK, but what about glutInitDisplayString()?
57  *  fgSetupPixelFormat      -- ignores the display mode settings
58  *  fgOpenWindow()          -- check the Win32 version, -iconic handling!
59  *  fgCloseWindow()         -- check the Win32 version
60  *  glutCreateWindow()      -- Check when default position and size is {-1,-1}
61  *  glutCreateSubWindow()   -- Check when default position and size is {-1,-1}
62  *  glutDestroyWindow()     -- check the Win32 version
63  *  glutSetWindow()         -- check the Win32 version
64  *  glutGetWindow()         -- OK
65  *  glutSetWindowTitle()    -- check the Win32 version
66  *  glutSetIconTitle()      -- check the Win32 version
67  *  glutShowWindow()        -- check the Win32 version
68  *  glutHideWindow()        -- check the Win32 version
69  *  glutIconifyWindow()     -- check the Win32 version
70  *  glutReshapeWindow()     -- check the Win32 version
71  *  glutPositionWindow()    -- check the Win32 version
72  *  glutPushWindow()        -- check the Win32 version
73  *  glutPopWindow()         -- check the Win32 version
74  */
75
76 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
77
78 /*
79  * Chooses a visual basing on the current display mode settings
80  */
81 #if TARGET_HOST_POSIX_X11
82
83 GLXFBConfig* fgChooseFBConfig( void )
84 {
85     GLboolean wantIndexedMode = GL_FALSE;
86     int attributes[ 32 ];
87     int where = 0;
88
89     /* First we have to process the display mode settings... */
90 /*
91  * XXX Why is there a semi-colon in this #define?  The code
92  * XXX that uses the macro seems to always add more semicolons...
93  */
94 #define ATTRIB(a) attributes[where++]=a;
95 #define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);}
96
97     if( fgState.DisplayMode & GLUT_INDEX )
98     {
99         ATTRIB_VAL( GLX_BUFFER_SIZE, 8 );
100         /*  Buffer size is selected later.  */
101
102         ATTRIB_VAL( GLX_RENDER_TYPE, GLX_COLOR_INDEX_BIT );
103         wantIndexedMode = GL_TRUE;
104     }
105     else
106     {
107         ATTRIB_VAL( GLX_RED_SIZE,   1 );
108         ATTRIB_VAL( GLX_GREEN_SIZE, 1 );
109         ATTRIB_VAL( GLX_BLUE_SIZE,  1 );
110         if( fgState.DisplayMode & GLUT_ALPHA )
111             ATTRIB_VAL( GLX_ALPHA_SIZE, 1 );
112     }
113
114     if( fgState.DisplayMode & GLUT_DOUBLE )
115         ATTRIB_VAL( GLX_DOUBLEBUFFER, True );
116
117     if( fgState.DisplayMode & GLUT_STEREO )
118         ATTRIB_VAL( GLX_STEREO, True );
119
120     if( fgState.DisplayMode & GLUT_DEPTH )
121         ATTRIB_VAL( GLX_DEPTH_SIZE, 1 );
122
123     if( fgState.DisplayMode & GLUT_STENCIL )
124         ATTRIB_VAL( GLX_STENCIL_SIZE, 1 );
125
126     if( fgState.DisplayMode & GLUT_ACCUM )
127     {
128         ATTRIB_VAL( GLX_ACCUM_RED_SIZE,   1 );
129         ATTRIB_VAL( GLX_ACCUM_GREEN_SIZE, 1 );
130         ATTRIB_VAL( GLX_ACCUM_BLUE_SIZE,  1 );
131         if( fgState.DisplayMode & GLUT_ALPHA )
132             ATTRIB_VAL( GLX_ACCUM_ALPHA_SIZE, 1 );
133     }
134
135     if ((fgState.DisplayMode & GLUT_AUX)
136      || (fgState.DisplayMode & GLUT_AUX1)
137      || (fgState.DisplayMode & GLUT_AUX2)
138      || (fgState.DisplayMode & GLUT_AUX3)
139      || (fgState.DisplayMode & GLUT_AUX4))
140       {
141         ATTRIB_VAL(GLX_AUX_BUFFERS, fgState.AuxiliaryBufferNumber)
142       }
143
144     if (fgState.DisplayMode & GLUT_MULTISAMPLE)
145       {
146         ATTRIB_VAL(GLX_SAMPLE_BUFFERS, 1)
147         ATTRIB_VAL(GLX_SAMPLES, fgState.SampleNumber)
148       }
149
150     /* Push a null at the end of the list */
151     ATTRIB( None );
152
153     {
154         GLXFBConfig * fbconfigArray;  /*  Array of FBConfigs  */
155         GLXFBConfig * fbconfig;       /*  The FBConfig we want  */
156         int fbconfigArraySize;        /*  Number of FBConfigs in the array  */
157
158
159         /*  Get all FBConfigs that match "attributes".  */
160         fbconfigArray = glXChooseFBConfig( fgDisplay.Display,
161                                            fgDisplay.Screen,
162                                            attributes,
163                                            &fbconfigArraySize );
164
165         if (fbconfigArray != NULL)
166         {
167             int result;  /* Returned by glXGetFBConfigAttrib, not checked. */
168
169
170             if( wantIndexedMode )
171             {
172                 /*
173                  * In index mode, we want the largest buffer size, i.e. visual
174                  * depth.  Here, FBConfigs are sorted by increasing buffer size
175                  * first, so FBConfigs with the largest size come last.
176                  */
177
178                 int bufferSizeMin, bufferSizeMax;
179
180                 /*  Get bufferSizeMin.  */
181                 result =
182                   glXGetFBConfigAttrib( fgDisplay.Display,
183                                         fbconfigArray[0],
184                                         GLX_BUFFER_SIZE,
185                                         &bufferSizeMin );
186                 /*  Get bufferSizeMax.  */
187                 result =
188                   glXGetFBConfigAttrib( fgDisplay.Display,
189                                         fbconfigArray[fbconfigArraySize - 1],
190                                         GLX_BUFFER_SIZE,
191                                         &bufferSizeMax );
192
193                 if (bufferSizeMax > bufferSizeMin)
194                 {
195                     /* 
196                      * Free and reallocate fbconfigArray, keeping only FBConfigs
197                      * with the largest buffer size.
198                      */
199                     XFree(fbconfigArray);
200
201                     /*  Add buffer size token at the end of the list.  */
202                     where--;
203                     ATTRIB_VAL( GLX_BUFFER_SIZE, bufferSizeMax );
204                     ATTRIB( None );
205
206                     fbconfigArray = glXChooseFBConfig( fgDisplay.Display,
207                                                        fgDisplay.Screen,
208                                                        attributes,
209                                                        &fbconfigArraySize );
210                 }
211             }
212
213             /*
214              * We now have an array of FBConfigs, the first one being the "best"
215              * one.  So we should return only this FBConfig:
216              *
217              * int fbconfigXID;
218              *
219              *  - pick the XID of the FBConfig we want
220              * result = glXGetFBConfigAttrib( fgDisplay.Display,
221              *                                fbconfigArray[0],
222              *                                GLX_FBCONFIG_ID,
223              *                                &fbconfigXID );
224              *
225              * - free the array
226              * XFree(fbconfigArray);
227              *
228              * - reset "attributes" with the XID
229              * where = 0;
230              * ATTRIB_VAL( GLX_FBCONFIG_ID, fbconfigXID );
231              * ATTRIB( None );
232              *
233              * - get our FBConfig only
234              * fbconfig = glXChooseFBConfig( fgDisplay.Display,
235              *                               fgDisplay.Screen,
236              *                               attributes,
237              *                               &fbconfigArraySize );
238              *
239              * However, for some configurations (for instance multisampling with
240              * Mesa 6.5.2 and ATI drivers), this does not work:
241              * glXChooseFBConfig returns NULL, whereas fbconfigXID is a valid
242              * XID.  Further investigation is needed.
243              *
244              * So, for now, we return the whole array of FBConfigs.  This should
245              * not produce any side effects elsewhere.
246              */
247             fbconfig = fbconfigArray;
248         }
249         else
250         {
251            fbconfig = NULL;
252         }
253
254         return fbconfig;
255     }
256 }
257 #endif /* TARGET_HOST_POSIX_X11 */
258
259 /*
260  * Setup the pixel format for a Win32 window
261  */
262 #if TARGET_HOST_MS_WINDOWS
263 /* The following include file is available from SGI but is not standard:
264  *   #include <GL/wglext.h>
265  * So we copy the necessary parts out of it.
266  * XXX: should local definitions for extensions be put in a separate include file?
267  */
268 typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc);
269
270 typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
271
272 #define WGL_DRAW_TO_WINDOW_ARB         0x2001
273 #define WGL_ACCELERATION_ARB           0x2003
274 #define WGL_SUPPORT_OPENGL_ARB         0x2010
275 #define WGL_DOUBLE_BUFFER_ARB          0x2011
276 #define WGL_COLOR_BITS_ARB             0x2014
277 #define WGL_ALPHA_BITS_ARB             0x201B
278 #define WGL_DEPTH_BITS_ARB             0x2022
279 #define WGL_STENCIL_BITS_ARB           0x2023
280 #define WGL_FULL_ACCELERATION_ARB      0x2027
281
282 #define WGL_SAMPLE_BUFFERS_ARB         0x2041
283 #define WGL_SAMPLES_ARB                0x2042
284
285
286 #ifndef WGL_ARB_create_context
287 #define WGL_ARB_create_context 1
288 #ifdef WGL_WGLEXT_PROTOTYPES
289 extern HGLRC WINAPI wglCreateContextAttribsARB (HDC, HGLRC, const int *);
290 #endif /* WGL_WGLEXT_PROTOTYPES */
291 typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList);
292
293 #define WGL_CONTEXT_DEBUG_BIT_ARB      0x0001
294 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
295 #define WGL_CONTEXT_MAJOR_VERSION_ARB  0x2091
296 #define WGL_CONTEXT_MINOR_VERSION_ARB  0x2092
297 #define WGL_CONTEXT_LAYER_PLANE_ARB    0x2093
298 #define WGL_CONTEXT_FLAGS_ARB          0x2094
299 #define ERROR_INVALID_VERSION_ARB      0x2095
300 #endif
301
302
303 GLboolean fgNewWGLCreateContext( SFG_Window* window )
304 {
305     PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetEntensionsStringARB;
306
307     if( (fgState.ContextFlags & GLUT_FORWARD_COMPATIBLE) &&
308         (fgState.MajorVersion > 2) )
309     {
310         return GL_TRUE;
311     }
312
313     wglMakeCurrent( window->Window.Device,
314                     window->Window.Context );
315
316     wglGetEntensionsStringARB=(PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
317     if ( wglGetEntensionsStringARB == NULL )
318     {
319         return GL_TRUE;
320     }
321
322     const char * pWglExtString=wglGetEntensionsStringARB(window->Window.Device);
323     if ( pWglExtString == NULL )
324     {
325         return GL_TRUE;
326     }
327
328     if ( strstr(pWglExtString, "WGL_ARB_create_context") == NULL )
329     {
330         return GL_TRUE;
331     }
332
333     /* new context creation */
334     HGLRC context;
335     int attribs[7];
336     PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
337
338     attribs[0] = WGL_CONTEXT_MAJOR_VERSION_ARB;
339     attribs[1] = fgState.MajorVersion;
340     attribs[2] = WGL_CONTEXT_MINOR_VERSION_ARB;
341     attribs[3] = fgState.MinorVersion;
342     attribs[4] = WGL_CONTEXT_FLAGS_ARB;
343     attribs[5] = ((fgState.ContextFlags & GLUT_DEBUG) ? WGL_CONTEXT_DEBUG_BIT_ARB : 0) |
344         ((fgState.ContextFlags & GLUT_FORWARD_COMPATIBLE) ? WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB : 0);
345     attribs[6] = 0;
346
347     wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress( "wglCreateContextAttribsARB" );
348     if ( wglCreateContextAttribsARB == NULL )
349     {
350         fgError( "wglCreateContextAttribsARB not found" );
351     }
352
353     context = wglCreateContextAttribsARB( window->Window.Device, 0, attribs );
354     if ( context == NULL )
355     {
356         fgError( "Unable to create OpenGL %d.%d context (flags %x)",
357             fgState.MajorVersion, fgState.MinorVersion, fgState.ContextFlags );
358     }
359     else
360     {
361         fgWarning( "Success 3.0" );
362         wglMakeCurrent( NULL, NULL );
363         wglDeleteContext( window->Window.Context );
364         window->Window.Context = context;
365     }
366
367     return GL_TRUE;
368 }
369
370
371 GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
372                               unsigned char layer_type )
373 {
374 #if defined(_WIN32_WCE)
375     return GL_TRUE;
376 #else
377     PIXELFORMATDESCRIPTOR* ppfd, pfd;
378     int flags, pixelformat;
379
380     freeglut_return_val_if_fail( window != NULL, 0 );
381     flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
382     if( fgState.DisplayMode & GLUT_DOUBLE )
383         flags |= PFD_DOUBLEBUFFER;
384
385     if( fgState.DisplayMode & GLUT_STEREO )
386         flags |= PFD_STEREO;
387
388 #if defined(_MSC_VER)
389 #pragma message( "fgSetupPixelFormat(): there is still some work to do here!" )
390 #endif
391
392     /* Specify which pixel format do we opt for... */
393     pfd.nSize           = sizeof(PIXELFORMATDESCRIPTOR);
394     pfd.nVersion        = 1;
395     pfd.dwFlags         = flags;
396
397     if( fgState.DisplayMode & GLUT_INDEX )
398     {
399         pfd.iPixelType = PFD_TYPE_COLORINDEX;
400         pfd.cRedBits                = 0;
401         pfd.cGreenBits            = 0;
402         pfd.cBlueBits             = 0;
403         pfd.cAlphaBits            = 0;
404     }
405     else
406     {
407         pfd.iPixelType      = PFD_TYPE_RGBA;
408         pfd.cRedBits                = 8;
409         pfd.cGreenBits            = 8;
410         pfd.cBlueBits             = 8;
411         if ( fgState.DisplayMode & GLUT_ALPHA )
412             pfd.cAlphaBits            = 8;
413         else
414             pfd.cAlphaBits            = 0;
415     }
416
417     pfd.cColorBits      = 24;
418     pfd.cRedShift       = 0;
419     pfd.cGreenShift     = 0;
420     pfd.cBlueShift      = 0;
421     pfd.cAlphaShift     = 0;
422     pfd.cAccumBits      = 0;
423     pfd.cAccumRedBits   = 0;
424     pfd.cAccumGreenBits = 0;
425     pfd.cAccumBlueBits  = 0;
426     pfd.cAccumAlphaBits = 0;
427 #if 0
428     pfd.cDepthBits      = 32;
429     pfd.cStencilBits    = 0;
430 #else
431     pfd.cDepthBits      = 24;
432     pfd.cStencilBits    = 8;
433 #endif
434     if( fgState.DisplayMode & GLUT_AUX4 )
435         pfd.cAuxBuffers = 4;
436     else if( fgState.DisplayMode & GLUT_AUX3 )
437         pfd.cAuxBuffers = 3;
438     else if( fgState.DisplayMode & GLUT_AUX2 )
439         pfd.cAuxBuffers = 2;
440     else if( fgState.DisplayMode & GLUT_AUX1 )
441         pfd.cAuxBuffers = 1;
442     else
443         pfd.cAuxBuffers = 0;
444
445     pfd.iLayerType      = layer_type;
446     pfd.bReserved       = 0;
447     pfd.dwLayerMask     = 0;
448     pfd.dwVisibleMask   = 0;
449     pfd.dwDamageMask    = 0;
450
451     pfd.cColorBits = (BYTE) GetDeviceCaps( window->Window.Device, BITSPIXEL );
452     ppfd = &pfd;
453
454     pixelformat = ChoosePixelFormat( window->Window.Device, ppfd );
455
456     /* windows hack for multismapling */
457     if (fgState.DisplayMode&GLUT_MULTISAMPLE)
458     {        
459         PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetEntensionsStringARB=NULL;
460         HGLRC rc, rc_before=wglGetCurrentContext();
461         HWND hWnd;
462         HDC hDC, hDC_before=wglGetCurrentDC();
463         WNDCLASS wndCls;
464
465         /* create a dummy window */
466         ZeroMemory(&wndCls, sizeof(wndCls));
467         wndCls.lpfnWndProc = DefWindowProc;
468         wndCls.hInstance = fgDisplay.Instance;
469         wndCls.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
470         wndCls.lpszClassName = _T("FREEGLUT_dummy");
471         RegisterClass( &wndCls );
472
473         hWnd=CreateWindow(_T("FREEGLUT_dummy"), _T(""), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW , 0,0,0,0, 0, 0, fgDisplay.Instance, 0 );
474         hDC=GetDC(hWnd);
475         SetPixelFormat( hDC, pixelformat, ppfd );
476         
477         rc = wglCreateContext( hDC );
478         wglMakeCurrent(hDC, rc);
479         
480         wglGetEntensionsStringARB=(PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
481         if (wglGetEntensionsStringARB)
482         {
483             const char * pWglExtString=wglGetEntensionsStringARB(hDC);
484             if (pWglExtString)
485             {
486                 if (strstr(pWglExtString, "WGL_ARB_multisample"))
487                 {
488                     int pAttributes[100];
489                     int iCounter=0;
490                     int iPixelFormat;
491                     BOOL bValid;
492                     float fAttributes[] = {0,0};
493                     UINT numFormats;
494                     PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARBProc=NULL;
495
496                     wglChoosePixelFormatARBProc=(PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
497                     if ( wglChoosePixelFormatARBProc )
498                     {
499                         pAttributes[iCounter++]=WGL_DRAW_TO_WINDOW_ARB;        pAttributes[iCounter++]=GL_TRUE;
500                         pAttributes[iCounter++]=WGL_SUPPORT_OPENGL_ARB;        pAttributes[iCounter++]=GL_TRUE;
501                         pAttributes[iCounter++]=WGL_ACCELERATION_ARB;        pAttributes[iCounter++]=WGL_FULL_ACCELERATION_ARB;
502
503                         pAttributes[iCounter++]=WGL_COLOR_BITS_ARB;            pAttributes[iCounter++]=pfd.cColorBits ;
504                         pAttributes[iCounter++]=WGL_ALPHA_BITS_ARB;            pAttributes[iCounter++]=pfd.cAlphaBits;
505                         pAttributes[iCounter++]=WGL_DEPTH_BITS_ARB;            pAttributes[iCounter++]=pfd.cDepthBits;
506                         pAttributes[iCounter++]=WGL_STENCIL_BITS_ARB;        pAttributes[iCounter++]=pfd.cStencilBits;
507
508                         pAttributes[iCounter++]=WGL_DOUBLE_BUFFER_ARB;        pAttributes[iCounter++]=(fgState.DisplayMode & GLUT_DOUBLE)!=0;
509                         pAttributes[iCounter++]=WGL_SAMPLE_BUFFERS_ARB;        pAttributes[iCounter++]=GL_TRUE;
510                         pAttributes[iCounter++]=WGL_SAMPLES_ARB;            pAttributes[iCounter++]=4;
511                         pAttributes[iCounter++]=0;                            pAttributes[iCounter++]=0;    /* terminator */
512
513                         bValid = wglChoosePixelFormatARBProc(window->Window.Device,pAttributes,fAttributes,1,&iPixelFormat,&numFormats);
514
515                         if (bValid && numFormats>0)
516                             pixelformat=iPixelFormat;
517                     }
518                 }
519                 wglMakeCurrent( hDC_before, rc_before);
520                 wglDeleteContext(rc);
521                 ReleaseDC(hWnd, hDC);
522                 DestroyWindow(hWnd);
523                 UnregisterClass(_T("FREEGLUT_dummy"), fgDisplay.Instance);
524             }
525         }
526     }
527
528     if( pixelformat == 0 )
529         return GL_FALSE;
530
531     if( checkOnly )
532         return GL_TRUE;
533     return SetPixelFormat( window->Window.Device, pixelformat, ppfd );
534 #endif /* defined(_WIN32_WCE) */
535 }
536 #endif /* TARGET_HOST_MS_WINDOWS */
537
538 /*
539  * Sets the OpenGL context and the fgStructure "Current Window" pointer to
540  * the window structure passed in.
541  */
542 void fgSetWindow ( SFG_Window *window )
543 {
544 #if TARGET_HOST_POSIX_X11
545     if ( window )
546         glXMakeContextCurrent(
547             fgDisplay.Display,
548             window->Window.Handle,
549             window->Window.Handle,
550             window->Window.Context
551         );
552 #elif TARGET_HOST_MS_WINDOWS
553     if( fgStructure.CurrentWindow )
554         ReleaseDC( fgStructure.CurrentWindow->Window.Handle,
555                    fgStructure.CurrentWindow->Window.Device );
556
557     if ( window )
558     {
559         window->Window.Device = GetDC( window->Window.Handle );
560         wglMakeCurrent(
561             window->Window.Device,
562             window->Window.Context
563         );
564     }
565 #endif
566     fgStructure.CurrentWindow = window;
567 }
568
569
570
571 #if TARGET_HOST_POSIX_X11
572
573 #ifndef GLX_CONTEXT_MAJOR_VERSION_ARB
574 #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
575 #endif
576
577 #ifndef GLX_CONTEXT_MINOR_VERSION_ARB
578 #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
579 #endif
580
581 #ifndef GLX_CONTEXT_FLAGS_ARB
582 #define GLX_CONTEXT_FLAGS_ARB 0x2094
583 #endif
584
585 #ifndef GLX_CONTEXT_DEBUG_BIT_ARB
586 #define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001
587 #endif
588
589 #ifndef GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
590 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
591 #endif
592
593 typedef GLXContext (*CreateContextAttribsProc)(Display *dpy, GLXFBConfig config,
594                                                GLXContext share_list, Bool direct,
595                                                const int *attrib_list);
596
597 static GLXContext fghCreateNewContext( SFG_Window* window )
598 {
599   /* for color model calculation */
600   int menu = ( window->IsMenu && !fgStructure.MenuContext );
601   int index_mode = ( fgState.DisplayMode & GLUT_INDEX );
602
603   /* "classic" context creation */
604   Display *dpy = fgDisplay.Display;
605   GLXFBConfig config = *(window->Window.FBConfig);
606   int render_type = ( !menu && index_mode ) ? GLX_COLOR_INDEX_TYPE : GLX_RGBA_TYPE;
607   GLXContext share_list = NULL;
608   Bool direct = ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT );
609   GLXContext context;
610
611   /* new context creation */
612   int attribs[7];
613   CreateContextAttribsProc createContextAttribs;
614
615   /* If nothing fancy has been required, simply use the old context creation GLX API entry */
616   if ( fgState.MajorVersion == 1 && fgState.MinorVersion == 0 && fgState.ContextFlags == 0)
617   {
618     context = glXCreateNewContext( dpy, config, render_type, share_list, direct );
619     if ( context == NULL ) {
620       fgError( "could not create new OpenGL context" );
621     }
622     return context;
623   }
624
625   /* color index mode is not available anymore with OpenGL 3.0 */
626   if ( render_type == GLX_COLOR_INDEX_TYPE ) {
627     fgWarning( "color index mode is deprecated, using RGBA mode" );
628   }
629
630   attribs[0] = GLX_CONTEXT_MAJOR_VERSION_ARB;
631   attribs[1] = fgState.MajorVersion;
632   attribs[2] = GLX_CONTEXT_MINOR_VERSION_ARB;
633   attribs[3] = fgState.MinorVersion;
634   attribs[4] = GLX_CONTEXT_FLAGS_ARB;
635   attribs[5] = ((fgState.ContextFlags & GLUT_DEBUG) ? GLX_CONTEXT_DEBUG_BIT_ARB : 0) |
636     ((fgState.ContextFlags & GLUT_FORWARD_COMPATIBLE) ? GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB : 0);
637   attribs[6] = 0;
638
639   createContextAttribs = (CreateContextAttribsProc) fghGetProcAddress( "glXCreateContextAttribsARB" );
640   if ( createContextAttribs == NULL ) {
641     fgError( "glXCreateContextAttribsARB not found" );
642   }
643
644   context = createContextAttribs( dpy, config, share_list, direct, attribs );
645   if ( context == NULL ) {
646     fgError( "could not create new OpenGL %d.%d context (flags %x)",
647              fgState.MajorVersion, fgState.MinorVersion, fgState.ContextFlags );
648   }
649   return context;
650 }
651 #endif
652
653
654 /*
655  * Opens a window. Requires a SFG_Window object created and attached
656  * to the freeglut structure. OpenGL context is created here.
657  */
658 void fgOpenWindow( SFG_Window* window, const char* title,
659                    GLboolean positionUse, int x, int y,
660                    GLboolean sizeUse, int w, int h,
661                    GLboolean gameMode, GLboolean isSubWindow )
662 {
663 #if TARGET_HOST_POSIX_X11
664     XVisualInfo * visualInfo;
665     XSetWindowAttributes winAttr;
666     XTextProperty textProperty;
667     XSizeHints sizeHints;
668     XWMHints wmHints;
669     unsigned long mask;
670     unsigned int current_DisplayMode = fgState.DisplayMode ;
671
672     /* Save the display mode if we are creating a menu window */
673     if( window->IsMenu && ( ! fgStructure.MenuContext ) )
674         fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ;
675
676     window->Window.FBConfig = fgChooseFBConfig( );
677
678     if( window->IsMenu && ( ! fgStructure.MenuContext ) )
679         fgState.DisplayMode = current_DisplayMode ;
680
681     if( ! window->Window.FBConfig )
682     {
683         /*
684          * The "fgChooseFBConfig" returned a null meaning that the visual
685          * context is not available.
686          * Try a couple of variations to see if they will work.
687          */
688         if( !( fgState.DisplayMode & GLUT_DOUBLE ) )
689         {
690             fgState.DisplayMode |= GLUT_DOUBLE ;
691             window->Window.FBConfig = fgChooseFBConfig( );
692             fgState.DisplayMode &= ~GLUT_DOUBLE;
693         }
694
695         if( fgState.DisplayMode & GLUT_MULTISAMPLE )
696         {
697             fgState.DisplayMode &= ~GLUT_MULTISAMPLE ;
698             window->Window.FBConfig = fgChooseFBConfig( );
699             fgState.DisplayMode |= GLUT_MULTISAMPLE;
700         }
701     }
702
703     FREEGLUT_INTERNAL_ERROR_EXIT( window->Window.FBConfig != NULL,
704                                   "FBConfig with necessary capabilities not found", "fgOpenWindow" );
705
706     /*  Get the X visual.  */
707     visualInfo = glXGetVisualFromFBConfig( fgDisplay.Display,
708                                            *(window->Window.FBConfig) );
709
710     /*
711      * XXX HINT: the masks should be updated when adding/removing callbacks.
712      * XXX       This might speed up message processing. Is that true?
713      * XXX
714      * XXX A: Not appreciably, but it WILL make it easier to debug.
715      * XXX    Try tracing old GLUT and try tracing freeglut.  Old GLUT
716      * XXX    turns off events that it doesn't need and is a whole lot
717      * XXX    more pleasant to trace.  (Think mouse-motion!  Tons of
718      * XXX    ``bonus'' GUI events stream in.)
719      */
720     winAttr.event_mask        =
721         StructureNotifyMask | SubstructureNotifyMask | ExposureMask |
722         ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
723         VisibilityChangeMask | EnterWindowMask | LeaveWindowMask |
724         PointerMotionMask | ButtonMotionMask;
725     winAttr.background_pixmap = None;
726     winAttr.background_pixel  = 0;
727     winAttr.border_pixel      = 0;
728
729     winAttr.colormap = XCreateColormap(
730         fgDisplay.Display, fgDisplay.RootWindow,
731         visualInfo->visual, AllocNone
732     );
733
734     mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
735
736     if( window->IsMenu || ( gameMode == GL_TRUE ) )
737     {
738         winAttr.override_redirect = True;
739         mask |= CWOverrideRedirect;
740     }
741
742     if( ! positionUse )
743         x = y = -1; /* default window position */
744     if( ! sizeUse )
745         w = h = 300; /* default window size */
746
747     window->Window.Handle = XCreateWindow(
748         fgDisplay.Display,
749         window->Parent == NULL ? fgDisplay.RootWindow :
750         window->Parent->Window.Handle,
751         x, y, w, h, 0,
752         visualInfo->depth, InputOutput,
753         visualInfo->visual, mask,
754         &winAttr
755     );
756
757     /*
758      * The GLX context creation, possibly trying the direct context rendering
759      *  or else use the current context if the user has so specified
760      */
761
762     if( window->IsMenu )
763     {
764         /*
765          * If there isn't already an OpenGL rendering context for menu
766          * windows, make one
767          */
768         if( !fgStructure.MenuContext )
769         {
770             fgStructure.MenuContext =
771                 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
772             fgStructure.MenuContext->MContext = fghCreateNewContext( window );
773         }
774
775         /* window->Window.Context = fgStructure.MenuContext->MContext; */
776         window->Window.Context = fghCreateNewContext( window );
777     }
778     else if( fgState.UseCurrentContext )
779     {
780         window->Window.Context = glXGetCurrentContext( );
781
782         if( ! window->Window.Context )
783             window->Window.Context = fghCreateNewContext( window );
784     }
785     else
786         window->Window.Context = fghCreateNewContext( window );
787
788 #if !defined( __FreeBSD__ ) && !defined( __NetBSD__ )
789     if(  !glXIsDirect( fgDisplay.Display, window->Window.Context ) )
790     {
791       if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT )
792         fgError( "Unable to force direct context rendering for window '%s'",
793                  title );
794     }
795 #endif
796
797     /*
798      * XXX Assume the new window is visible by default
799      * XXX Is this a  safe assumption?
800      */
801     window->State.Visible = GL_TRUE;
802
803     sizeHints.flags = 0;
804     if ( positionUse )
805         sizeHints.flags |= USPosition;
806     if ( sizeUse )
807         sizeHints.flags |= USSize;
808
809     /*
810      * Fill in the size hints values now (the x, y, width and height
811      * settings are obsolete, are there any more WMs that support them?)
812      * Unless the X servers actually stop supporting these, we should
813      * continue to fill them in.  It is *not* our place to tell the user
814      * that they should replace a window manager that they like, and which
815      * works, just because *we* think that it's not "modern" enough.
816      */
817     sizeHints.x      = x;
818     sizeHints.y      = y;
819     sizeHints.width  = w;
820     sizeHints.height = h;
821
822     wmHints.flags = StateHint;
823     wmHints.initial_state = fgState.ForceIconic ? IconicState : NormalState;
824     /* Prepare the window and iconified window names... */
825     XStringListToTextProperty( (char **) &title, 1, &textProperty );
826
827     XSetWMProperties(
828         fgDisplay.Display,
829         window->Window.Handle,
830         &textProperty,
831         &textProperty,
832         0,
833         0,
834         &sizeHints,
835         &wmHints,
836         NULL
837     );
838     XFree( textProperty.value );
839
840     XSetWMProtocols( fgDisplay.Display, window->Window.Handle,
841                      &fgDisplay.DeleteWindow, 1 );
842
843     glXMakeContextCurrent(
844         fgDisplay.Display,
845         window->Window.Handle,
846         window->Window.Handle,
847         window->Window.Context
848     );
849
850     XMapWindow( fgDisplay.Display, window->Window.Handle );
851
852     XFree(visualInfo);
853
854 #elif TARGET_HOST_MS_WINDOWS
855
856     WNDCLASS wc;
857     DWORD flags;
858     DWORD exFlags = 0;
859     ATOM atom;
860     int WindowStyle = 0;
861
862     /* Grab the window class we have registered on glutInit(): */
863     atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc );
864     FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Info Not Found",
865                                    "fgOpenWindow" );
866
867     if( gameMode )
868     {
869         FREEGLUT_INTERNAL_ERROR_EXIT ( window->Parent == NULL,
870                                        "Game mode being invoked on a subwindow",
871                                        "fgOpenWindow" );
872
873         /*
874          * Set the window creation flags appropriately to make the window
875          * entirely visible:
876          */
877         flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
878     }
879     else
880     {
881         int worig = w, horig = h;
882
883 #if !defined(_WIN32_WCE)
884         if ( ( ! isSubWindow ) && ( ! window->IsMenu ) )
885         {
886             /*
887              * Update the window dimensions, taking account of window
888              * decorations.  "freeglut" is to create the window with the
889              * outside of its border at (x,y) and with dimensions (w,h).
890              */
891             w += (GetSystemMetrics( SM_CXSIZEFRAME ) )*2;
892             h += (GetSystemMetrics( SM_CYSIZEFRAME ) )*2 +
893                 GetSystemMetrics( SM_CYCAPTION );
894         }
895 #endif /* defined(_WIN32_WCE) */
896
897         if( ! positionUse )
898         {
899             x = CW_USEDEFAULT;
900             y = CW_USEDEFAULT;
901         }
902         /* setting State.Width/Height to call resize callback later */
903         if( ! sizeUse )
904         {
905             if( ! window->IsMenu )
906             {
907                 w = CW_USEDEFAULT;
908                 h = CW_USEDEFAULT;
909             }
910             else /* fail safe - Windows can make a window of size (0, 0) */
911                 w = h = 300; /* default window size */
912             window->State.Width = window->State.Height = -1;
913         }
914         else
915         {
916             window->State.Width = worig;
917             window->State.Height = horig;
918         }
919
920         /*
921          * There's a small difference between creating the top, child and
922          * game mode windows
923          */
924         flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
925
926         if ( window->IsMenu )
927         {
928             flags |= WS_POPUP;
929             exFlags |= WS_EX_TOOLWINDOW;
930         }
931 #if !defined(_WIN32_WCE)
932         else if( window->Parent == NULL )
933             flags |= WS_OVERLAPPEDWINDOW;
934 #endif
935         else
936             flags |= WS_CHILD;
937     }
938
939 #if defined(_WIN32_WCE)
940     {
941         wchar_t* wstr = fghWstrFromStr(title);
942
943         window->Window.Handle = CreateWindow(
944             _T("FREEGLUT"),
945             wstr,
946             WS_VISIBLE | WS_POPUP,
947             0,0, 240,320,
948             NULL,
949             NULL,
950             fgDisplay.Instance,
951             (LPVOID) window
952         );
953
954         free(wstr);
955
956         SHFullScreen(window->Window.Handle, SHFS_HIDESTARTICON);
957         SHFullScreen(window->Window.Handle, SHFS_HIDESIPBUTTON);
958         SHFullScreen(window->Window.Handle, SHFS_HIDETASKBAR);
959         MoveWindow(window->Window.Handle, 0, 0, 240, 320, TRUE);
960         ShowWindow(window->Window.Handle, SW_SHOW);
961         UpdateWindow(window->Window.Handle);
962     }
963 #else
964     window->Window.Handle = CreateWindowEx(
965         exFlags,
966         _T("FREEGLUT"),
967         title,
968         flags,
969         x, y, w, h,
970         (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle,
971         (HMENU) NULL,
972         fgDisplay.Instance,
973         (LPVOID) window
974     );
975 #endif /* defined(_WIN32_WCE) */
976
977     if( !( window->Window.Handle ) )
978         fgError( "Failed to create a window (%s)!", title );
979
980     /* Make a menu window always on top - fix Feature Request 947118 */
981     if( window->IsMenu || gameMode )
982         SetWindowPos(
983                         window->Window.Handle,
984                         HWND_TOPMOST,
985                         0, 0, 0, 0,
986                         SWP_NOMOVE | SWP_NOSIZE
987                     );
988
989     /* Hack to remove the caption (title bar) and/or border
990      * and all the system menu controls.
991      */
992     WindowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE);
993     if ( fgState.DisplayMode & GLUT_CAPTIONLESS )
994     {
995         SetWindowLong ( window->Window.Handle, GWL_STYLE,
996                         WindowStyle & ~(WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX));
997     }
998     else if ( fgState.DisplayMode & GLUT_BORDERLESS )
999     {
1000         SetWindowLong ( window->Window.Handle, GWL_STYLE,
1001                         WindowStyle & ~(WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX));
1002     }
1003 /*  SetWindowPos(window->Window.Handle, NULL, 0, 0, 0, 0,
1004      SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); */
1005
1006
1007 #if defined(_WIN32_WCE)
1008     ShowWindow( window->Window.Handle, SW_SHOW );
1009 #else
1010     ShowWindow( window->Window.Handle,
1011                 fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW );
1012 #endif /* defined(_WIN32_WCE) */
1013
1014     UpdateWindow( window->Window.Handle );
1015     ShowCursor( TRUE );  /* XXX Old comments say "hide cursor"! */
1016
1017 #endif
1018
1019     fgSetWindow( window );
1020
1021     window->Window.DoubleBuffered =
1022         ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0;
1023
1024     if ( ! window->Window.DoubleBuffered )
1025     {
1026         glDrawBuffer ( GL_FRONT );
1027         glReadBuffer ( GL_FRONT );
1028     }
1029 }
1030
1031 /*
1032  * Closes a window, destroying the frame and OpenGL context
1033  */
1034 void fgCloseWindow( SFG_Window* window )
1035 {
1036 #if TARGET_HOST_POSIX_X11
1037
1038     glXDestroyContext( fgDisplay.Display, window->Window.Context );
1039     XFree( window->Window.FBConfig );
1040     XDestroyWindow( fgDisplay.Display, window->Window.Handle );
1041     /* XFlush( fgDisplay.Display ); */ /* XXX Shouldn't need this */
1042
1043 #elif TARGET_HOST_MS_WINDOWS
1044
1045     /* Make sure we don't close a window with current context active */
1046     if( fgStructure.CurrentWindow == window )
1047         wglMakeCurrent( NULL, NULL );
1048
1049     /*
1050      * Step through the list of windows.  If the rendering context
1051      * is not being used by another window, then we delete it.
1052      */
1053     {
1054         int used = FALSE ;
1055         SFG_Window *iter ;
1056
1057         for( iter = (SFG_Window *)fgStructure.Windows.First;
1058              iter;
1059              iter = (SFG_Window *)iter->Node.Next )
1060         {
1061             if( ( iter->Window.Context == window->Window.Context ) &&
1062                 ( iter != window ) )
1063                 used = TRUE;
1064         }
1065
1066         if( ! used )
1067             wglDeleteContext( window->Window.Context );
1068     }
1069
1070     DestroyWindow( window->Window.Handle );
1071 #endif
1072 }
1073
1074
1075 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
1076
1077 /*
1078  * Creates a new top-level freeglut window
1079  */
1080 int FGAPIENTRY glutCreateWindow( const char* title )
1081 {
1082     /* XXX GLUT does not exit; it simply calls "glutInit" quietly if the
1083      * XXX application has not already done so.  The "freeglut" community
1084      * XXX decided not to go this route (freeglut-developer e-mail from
1085      * XXX Steve Baker, 12/16/04, 4:22 PM CST, "Re: [Freeglut-developer]
1086      * XXX Desired 'freeglut' behaviour when there is no current window"
1087      */
1088     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateWindow" );
1089
1090     return fgCreateWindow( NULL, title, fgState.Position.Use,
1091                            fgState.Position.X, fgState.Position.Y,
1092                            fgState.Size.Use, fgState.Size.X, fgState.Size.Y,
1093                            GL_FALSE, GL_FALSE )->ID;
1094 }
1095
1096 /*
1097  * This function creates a sub window.
1098  */
1099 int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h )
1100 {
1101     int ret = 0;
1102     SFG_Window* window = NULL;
1103     SFG_Window* parent = NULL;
1104
1105     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateSubWindow" );
1106     parent = fgWindowByID( parentID );
1107     freeglut_return_val_if_fail( parent != NULL, 0 );
1108     if ( x < 0 )
1109     {
1110         x = parent->State.Width + x ;
1111         if ( w >= 0 ) x -= w ;
1112     }
1113
1114     if ( w < 0 ) w = parent->State.Width - x + w ;
1115     if ( w < 0 )
1116     {
1117         x += w ;
1118         w = -w ;
1119     }
1120
1121     if ( y < 0 )
1122     {
1123         y = parent->State.Height + y ;
1124         if ( h >= 0 ) y -= h ;
1125     }
1126
1127     if ( h < 0 ) h = parent->State.Height - y + h ;
1128     if ( h < 0 )
1129     {
1130         y += h ;
1131         h = -h ;
1132     }
1133
1134     window = fgCreateWindow( parent, "", GL_TRUE, x, y, GL_TRUE, w, h, GL_FALSE, GL_FALSE );
1135     ret = window->ID;
1136
1137     return ret;
1138 }
1139
1140 /*
1141  * Destroys a window and all of its subwindows
1142  */
1143 void FGAPIENTRY glutDestroyWindow( int windowID )
1144 {
1145     SFG_Window* window;
1146     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyWindow" );
1147     window = fgWindowByID( windowID );
1148     freeglut_return_if_fail( window != NULL );
1149     {
1150         fgExecutionState ExecState = fgState.ExecState;
1151         fgAddToWindowDestroyList( window );
1152         fgState.ExecState = ExecState;
1153     }
1154 }
1155
1156 /*
1157  * This function selects the current window
1158  */
1159 void FGAPIENTRY glutSetWindow( int ID )
1160 {
1161     SFG_Window* window = NULL;
1162
1163     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindow" );
1164     if( fgStructure.CurrentWindow != NULL )
1165         if( fgStructure.CurrentWindow->ID == ID )
1166             return;
1167
1168     window = fgWindowByID( ID );
1169     if( window == NULL )
1170     {
1171         fgWarning( "glutSetWindow(): window ID %d not found!", ID );
1172         return;
1173     }
1174
1175     fgSetWindow( window );
1176 }
1177
1178 /*
1179  * This function returns the ID number of the current window, 0 if none exists
1180  */
1181 int FGAPIENTRY glutGetWindow( void )
1182 {
1183     SFG_Window *win = fgStructure.CurrentWindow;
1184     /*
1185      * Since GLUT did not throw an error if this function was called without a prior call to
1186      * "glutInit", this function shouldn't do so here.  Instead let us return a zero.
1187      * See Feature Request "[ 1307049 ] glutInit check".
1188      */
1189     if ( ! fgState.Initialised )
1190         return 0;
1191
1192     while ( win && win->IsMenu )
1193         win = win->Parent;
1194     return win ? win->ID : 0;
1195 }
1196
1197 /*
1198  * This function makes the current window visible
1199  */
1200 void FGAPIENTRY glutShowWindow( void )
1201 {
1202     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutShowWindow" );
1203     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutShowWindow" );
1204
1205 #if TARGET_HOST_POSIX_X11
1206
1207     XMapWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle );
1208     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1209
1210 #elif TARGET_HOST_MS_WINDOWS
1211
1212     ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_SHOW );
1213
1214 #endif
1215
1216     fgStructure.CurrentWindow->State.Redisplay = GL_TRUE;
1217 }
1218
1219 /*
1220  * This function hides the current window
1221  */
1222 void FGAPIENTRY glutHideWindow( void )
1223 {
1224     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutHideWindow" );
1225     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutHideWindow" );
1226
1227 #if TARGET_HOST_POSIX_X11
1228
1229     if( fgStructure.CurrentWindow->Parent == NULL )
1230         XWithdrawWindow( fgDisplay.Display,
1231                          fgStructure.CurrentWindow->Window.Handle,
1232                          fgDisplay.Screen );
1233     else
1234         XUnmapWindow( fgDisplay.Display,
1235                       fgStructure.CurrentWindow->Window.Handle );
1236     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1237
1238 #elif TARGET_HOST_MS_WINDOWS
1239
1240     ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_HIDE );
1241
1242 #endif
1243
1244     fgStructure.CurrentWindow->State.Redisplay = GL_FALSE;
1245 }
1246
1247 /*
1248  * Iconify the current window (top-level windows only)
1249  */
1250 void FGAPIENTRY glutIconifyWindow( void )
1251 {
1252     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIconifyWindow" );
1253     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIconifyWindow" );
1254
1255     fgStructure.CurrentWindow->State.Visible   = GL_FALSE;
1256 #if TARGET_HOST_POSIX_X11
1257
1258     XIconifyWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
1259                     fgDisplay.Screen );
1260     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1261
1262 #elif TARGET_HOST_MS_WINDOWS
1263
1264     ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_MINIMIZE );
1265
1266 #endif
1267
1268     fgStructure.CurrentWindow->State.Redisplay = GL_FALSE;
1269 }
1270
1271 /*
1272  * Set the current window's title
1273  */
1274 void FGAPIENTRY glutSetWindowTitle( const char* title )
1275 {
1276     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowTitle" );
1277     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowTitle" );
1278     if( ! fgStructure.CurrentWindow->Parent )
1279     {
1280 #if TARGET_HOST_POSIX_X11
1281
1282         XTextProperty text;
1283
1284         text.value = (unsigned char *) title;
1285         text.encoding = XA_STRING;
1286         text.format = 8;
1287         text.nitems = strlen( title );
1288
1289         XSetWMName(
1290             fgDisplay.Display,
1291             fgStructure.CurrentWindow->Window.Handle,
1292             &text
1293         );
1294
1295         XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1296
1297 #elif TARGET_HOST_MS_WINDOWS
1298 #    ifdef _WIN32_WCE
1299         {
1300             wchar_t* wstr = fghWstrFromStr(title);
1301             SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr );
1302             free(wstr);
1303         }
1304 #    else
1305         SetWindowText( fgStructure.CurrentWindow->Window.Handle, title );
1306 #    endif
1307
1308 #endif
1309     }
1310 }
1311
1312 /*
1313  * Set the current window's iconified title
1314  */
1315 void FGAPIENTRY glutSetIconTitle( const char* title )
1316 {
1317     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetIconTitle" );
1318     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetIconTitle" );
1319
1320     if( ! fgStructure.CurrentWindow->Parent )
1321     {
1322 #if TARGET_HOST_POSIX_X11
1323
1324         XTextProperty text;
1325
1326         text.value = (unsigned char *) title;
1327         text.encoding = XA_STRING;
1328         text.format = 8;
1329         text.nitems = strlen( title );
1330
1331         XSetWMIconName(
1332             fgDisplay.Display,
1333             fgStructure.CurrentWindow->Window.Handle,
1334             &text
1335         );
1336
1337         XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1338
1339 #elif TARGET_HOST_MS_WINDOWS
1340 #    ifdef _WIN32_WCE
1341         {
1342             wchar_t* wstr = fghWstrFromStr(title);
1343             SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr );
1344             free(wstr);
1345         }
1346 #    else
1347         SetWindowText( fgStructure.CurrentWindow->Window.Handle, title );
1348 #    endif
1349
1350 #endif
1351     }
1352 }
1353
1354 /*
1355  * Change the current window's size
1356  */
1357 void FGAPIENTRY glutReshapeWindow( int width, int height )
1358 {
1359     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" );
1360     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" );
1361
1362     if (glutGet(GLUT_FULL_SCREEN))
1363     {
1364       /*  Leave full screen state before resizing. */
1365       glutFullScreenToggle();
1366     }
1367
1368     fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE;
1369     fgStructure.CurrentWindow->State.Width  = width ;
1370     fgStructure.CurrentWindow->State.Height = height;
1371 }
1372
1373 /*
1374  * Change the current window's position
1375  */
1376 void FGAPIENTRY glutPositionWindow( int x, int y )
1377 {
1378     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" );
1379     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" );
1380
1381     if (glutGet(GLUT_FULL_SCREEN))
1382     {
1383       /*  Leave full screen state before moving. */
1384       glutFullScreenToggle();
1385     }
1386
1387 #if TARGET_HOST_POSIX_X11
1388
1389     XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
1390                  x, y );
1391     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1392
1393 #elif TARGET_HOST_MS_WINDOWS
1394
1395     {
1396         RECT winRect;
1397
1398         /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
1399         GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect );
1400         MoveWindow(
1401             fgStructure.CurrentWindow->Window.Handle,
1402             x,
1403             y,
1404             winRect.right - winRect.left,
1405             winRect.bottom - winRect.top,
1406             TRUE
1407         );
1408     }
1409
1410 #endif
1411 }
1412
1413 /*
1414  * Lowers the current window (by Z order change)
1415  */
1416 void FGAPIENTRY glutPushWindow( void )
1417 {
1418     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" );
1419     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" );
1420
1421 #if TARGET_HOST_POSIX_X11
1422
1423     XLowerWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle );
1424
1425 #elif TARGET_HOST_MS_WINDOWS
1426
1427     SetWindowPos(
1428         fgStructure.CurrentWindow->Window.Handle,
1429         HWND_BOTTOM,
1430         0, 0, 0, 0,
1431         SWP_NOSIZE | SWP_NOMOVE
1432     );
1433
1434 #endif
1435 }
1436
1437 /*
1438  * Raises the current window (by Z order change)
1439  */
1440 void FGAPIENTRY glutPopWindow( void )
1441 {
1442     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" );
1443     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" );
1444
1445 #if TARGET_HOST_POSIX_X11
1446
1447     XRaiseWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle );
1448
1449 #elif TARGET_HOST_MS_WINDOWS
1450
1451     SetWindowPos(
1452         fgStructure.CurrentWindow->Window.Handle,
1453         HWND_TOP,
1454         0, 0, 0, 0,
1455         SWP_NOSIZE | SWP_NOMOVE
1456     );
1457
1458 #endif
1459 }
1460
1461 /*
1462  * Resize the current window so that it fits the whole screen
1463  */
1464 void FGAPIENTRY glutFullScreen( void )
1465 {
1466     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );
1467     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );
1468
1469     if (glutGet(GLUT_FULL_SCREEN))
1470     {
1471       /*  Leave full screen state before resizing. */
1472       glutFullScreenToggle();
1473     }
1474
1475     {
1476 #if TARGET_HOST_POSIX_X11
1477
1478         Status status;  /* Returned by XGetWindowAttributes(), not checked. */
1479         XWindowAttributes attributes;
1480
1481         status = XGetWindowAttributes(fgDisplay.Display,
1482                                       fgStructure.CurrentWindow->Window.Handle,
1483                                       &attributes);
1484         /*
1485          * The "x" and "y" members of "attributes" are the window's coordinates
1486          * relative to its parent, i.e. to the decoration window.
1487          */
1488         XMoveResizeWindow(fgDisplay.Display,
1489                           fgStructure.CurrentWindow->Window.Handle,
1490                           -attributes.x,
1491                           -attributes.y,
1492                           fgDisplay.ScreenWidth,
1493                           fgDisplay.ScreenHeight);
1494
1495 #elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */
1496         RECT rect;
1497
1498         /* For fullscreen mode, force the top-left corner to 0,0
1499          * and adjust the window rectangle so that the client area
1500          * covers the whole screen.
1501          */
1502
1503         rect.left   = 0;
1504         rect.top    = 0;
1505         rect.right  = fgDisplay.ScreenWidth;
1506         rect.bottom = fgDisplay.ScreenHeight;
1507
1508         AdjustWindowRect ( &rect, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS |
1509                                   WS_CLIPCHILDREN, FALSE );
1510
1511         /*
1512          * SWP_NOACTIVATE     Do not activate the window
1513          * SWP_NOOWNERZORDER  Do not change position in z-order
1514          * SWP_NOSENDCHANGING Supress WM_WINDOWPOSCHANGING message
1515          * SWP_NOZORDER       Retains the current Z order (ignore 2nd param)
1516          */
1517
1518         SetWindowPos( fgStructure.CurrentWindow->Window.Handle,
1519                       HWND_TOP,
1520                       rect.left,
1521                       rect.top,
1522                       rect.right  - rect.left,
1523                       rect.bottom - rect.top,
1524                       SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
1525                       SWP_NOZORDER
1526                     );
1527 #endif
1528     }
1529 }
1530
1531 /*
1532  * Toggle the window's full screen state.
1533  */
1534 void FGAPIENTRY glutFullScreenToggle( void )
1535 {
1536     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" );
1537     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" );
1538
1539     {
1540 #if TARGET_HOST_POSIX_X11
1541
1542       if (fgDisplay.StateFullScreen != None)
1543       {
1544         XEvent xevent;
1545         long event_mask;
1546         int status;
1547
1548         xevent.type = ClientMessage;
1549         xevent.xclient.type = ClientMessage;
1550         xevent.xclient.serial = 0;
1551         xevent.xclient.send_event = True;
1552         xevent.xclient.display = fgDisplay.Display;
1553         xevent.xclient.window = fgStructure.CurrentWindow->Window.Handle;
1554         xevent.xclient.message_type = fgDisplay.State;
1555         xevent.xclient.format = 32;
1556         xevent.xclient.data.l[0] = 2;  /* _NET_WM_STATE_TOGGLE */
1557         xevent.xclient.data.l[1] = fgDisplay.StateFullScreen;
1558         xevent.xclient.data.l[2] = 0;
1559         xevent.xclient.data.l[3] = 0;
1560         xevent.xclient.data.l[4] = 0;
1561
1562         /*** Don't really understand how event masks work... ***/
1563         event_mask = SubstructureRedirectMask | SubstructureNotifyMask;
1564
1565         status = XSendEvent(fgDisplay.Display,
1566           fgDisplay.RootWindow,
1567           False,
1568           event_mask,
1569           &xevent);
1570         FREEGLUT_INTERNAL_ERROR_EXIT(status != 0,
1571           "XSendEvent failed",
1572           "glutFullScreenToggle");
1573       }
1574       else
1575 #endif
1576       {
1577         /*
1578          * If the window manager is not Net WM compliant, fall back to legacy
1579          * behaviour.
1580          */
1581         glutFullScreen();
1582       }
1583     }
1584 }
1585
1586 /*
1587  * A.Donev: Set and retrieve the window's user data
1588  */
1589 void* FGAPIENTRY glutGetWindowData( void )
1590 {
1591     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" );
1592     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" );
1593     return fgStructure.CurrentWindow->UserData;
1594 }
1595
1596 void FGAPIENTRY glutSetWindowData(void* data)
1597 {
1598     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" );
1599     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" );
1600     fgStructure.CurrentWindow->UserData = data;
1601 }
1602
1603 /*** END OF FILE ***/