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