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