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