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