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