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