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