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