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