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