Adding multitouch capability per e-mail from Florian Echtler dated 3/17/11 12:07 PM
[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     /* register extension events _before_ window is mapped */
1124     #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
1125        fgRegisterDevices( fgDisplay.Display, &(window->Window.Handle) );
1126     #endif
1127
1128     XMapWindow( fgDisplay.Display, window->Window.Handle );
1129
1130     XFree(visualInfo);
1131
1132     if( !isSubWindow)
1133         XPeekIfEvent( fgDisplay.Display, &eventReturnBuffer, &fghWindowIsVisible, window->Window.Handle );
1134
1135 #elif TARGET_HOST_MS_WINDOWS
1136
1137     WNDCLASS wc;
1138     DWORD flags;
1139     DWORD exFlags = 0;
1140     ATOM atom;
1141     int WindowStyle = 0;
1142
1143     /* Grab the window class we have registered on glutInit(): */
1144     atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc );
1145     FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Info Not Found",
1146                                    "fgOpenWindow" );
1147
1148     if( gameMode )
1149     {
1150         FREEGLUT_INTERNAL_ERROR_EXIT ( window->Parent == NULL,
1151                                        "Game mode being invoked on a subwindow",
1152                                        "fgOpenWindow" );
1153
1154         /*
1155          * Set the window creation flags appropriately to make the window
1156          * entirely visible:
1157          */
1158         flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
1159     }
1160     else
1161     {
1162         int worig = w, horig = h;
1163
1164 #if !defined(_WIN32_WCE)
1165         if ( ( ! isSubWindow ) && ( ! window->IsMenu ) )
1166         {
1167             /*
1168              * Update the window dimensions, taking account of window
1169              * decorations.  "freeglut" is to create the window with the
1170              * outside of its border at (x,y) and with dimensions (w,h).
1171              */
1172             w += (GetSystemMetrics( SM_CXSIZEFRAME ) )*2;
1173             h += (GetSystemMetrics( SM_CYSIZEFRAME ) )*2 +
1174                 GetSystemMetrics( SM_CYCAPTION );
1175         }
1176 #endif /* defined(_WIN32_WCE) */
1177
1178         if( ! positionUse )
1179         {
1180             x = CW_USEDEFAULT;
1181             y = CW_USEDEFAULT;
1182         }
1183         /* setting State.Width/Height to call resize callback later */
1184         if( ! sizeUse )
1185         {
1186             if( ! window->IsMenu )
1187             {
1188                 w = CW_USEDEFAULT;
1189                 h = CW_USEDEFAULT;
1190             }
1191             else /* fail safe - Windows can make a window of size (0, 0) */
1192                 w = h = 300; /* default window size */
1193             window->State.Width = window->State.Height = -1;
1194         }
1195         else
1196         {
1197             window->State.Width = worig;
1198             window->State.Height = horig;
1199         }
1200
1201         /*
1202          * There's a small difference between creating the top, child and
1203          * game mode windows
1204          */
1205         flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
1206
1207         if ( window->IsMenu )
1208         {
1209             flags |= WS_POPUP;
1210             exFlags |= WS_EX_TOOLWINDOW;
1211         }
1212 #if !defined(_WIN32_WCE)
1213         else if( window->Parent == NULL )
1214             flags |= WS_OVERLAPPEDWINDOW;
1215 #endif
1216         else
1217             flags |= WS_CHILD;
1218     }
1219
1220 #if defined(_WIN32_WCE)
1221     {
1222         wchar_t* wstr = fghWstrFromStr(title);
1223
1224         window->Window.Handle = CreateWindow(
1225             _T("FREEGLUT"),
1226             wstr,
1227             WS_VISIBLE | WS_POPUP,
1228             0,0, 240,320,
1229             NULL,
1230             NULL,
1231             fgDisplay.Instance,
1232             (LPVOID) window
1233         );
1234
1235         free(wstr);
1236
1237         SHFullScreen(window->Window.Handle, SHFS_HIDESTARTICON);
1238         SHFullScreen(window->Window.Handle, SHFS_HIDESIPBUTTON);
1239         SHFullScreen(window->Window.Handle, SHFS_HIDETASKBAR);
1240         MoveWindow(window->Window.Handle, 0, 0, 240, 320, TRUE);
1241         ShowWindow(window->Window.Handle, SW_SHOW);
1242         UpdateWindow(window->Window.Handle);
1243     }
1244 #else
1245     {
1246       /* xoff and yoff are used to place window relative to current display */
1247       /* The operation of gamemode also depends on this */
1248         int xoff=0,yoff=0;
1249         get_display_origin(&xoff,&yoff);
1250
1251         window->Window.Handle = CreateWindowEx(
1252             exFlags,
1253             _T("FREEGLUT"),
1254             title,
1255             flags,
1256             x+xoff, y+yoff, w, h,
1257             (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle,
1258             (HMENU) NULL,
1259             fgDisplay.Instance,
1260             (LPVOID) window
1261         );
1262     }
1263 #endif /* defined(_WIN32_WCE) */
1264
1265     if( !( window->Window.Handle ) )
1266         fgError( "Failed to create a window (%s)!", title );
1267
1268     /* Make a menu window always on top - fix Feature Request 947118 */
1269     if( window->IsMenu || gameMode )
1270         SetWindowPos(
1271                         window->Window.Handle,
1272                         HWND_TOPMOST,
1273                         0, 0, 0, 0,
1274                         SWP_NOMOVE | SWP_NOSIZE
1275                     );
1276
1277     /* Hack to remove the caption (title bar) and/or border
1278      * and all the system menu controls.
1279      */
1280     WindowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE);
1281     if ( fgState.DisplayMode & GLUT_CAPTIONLESS )
1282     {
1283         SetWindowLong ( window->Window.Handle, GWL_STYLE,
1284                         WindowStyle & ~(WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX));
1285     }
1286     else if ( fgState.DisplayMode & GLUT_BORDERLESS )
1287     {
1288         SetWindowLong ( window->Window.Handle, GWL_STYLE,
1289                         WindowStyle & ~(WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX));
1290     }
1291 /*  SetWindowPos(window->Window.Handle, NULL, 0, 0, 0, 0,
1292      SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); */
1293
1294     /* Enable multitouch: additional flag TWF_FINETOUCH, TWF_WANTPALM */
1295     #ifdef WM_TOUCH
1296        RegisterTouchWindow( window->Window.Handle, TWF_FINETOUCH | TWF_WANTPALM );
1297     #endif
1298
1299 #if defined(_WIN32_WCE)
1300     ShowWindow( window->Window.Handle, SW_SHOW );
1301 #else
1302     ShowWindow( window->Window.Handle,
1303                 fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW );
1304 #endif /* defined(_WIN32_WCE) */
1305
1306     UpdateWindow( window->Window.Handle );
1307     ShowCursor( TRUE );  /* XXX Old comments say "hide cursor"! */
1308
1309 #endif
1310
1311     fgSetWindow( window );
1312
1313     window->Window.DoubleBuffered =
1314         ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0;
1315
1316     if ( ! window->Window.DoubleBuffered )
1317     {
1318         glDrawBuffer ( GL_FRONT );
1319         glReadBuffer ( GL_FRONT );
1320     }
1321 }
1322
1323 /*
1324  * Closes a window, destroying the frame and OpenGL context
1325  */
1326 void fgCloseWindow( SFG_Window* window )
1327 {
1328     /* if we're in gamemode, call glutLeaveGameMode first to make sure the
1329      * gamemode is properly closed before closing the window
1330      */
1331     if (fgStructure.GameModeWindow != NULL)
1332         glutLeaveGameMode();
1333
1334 #if TARGET_HOST_POSIX_X11
1335
1336     if( window->Window.Context )
1337         glXDestroyContext( fgDisplay.Display, window->Window.Context );
1338     XFree( window->Window.FBConfig );
1339
1340     if( window->Window.Handle ) {
1341         XDestroyWindow( fgDisplay.Display, window->Window.Handle );
1342     }
1343     /* XFlush( fgDisplay.Display ); */ /* XXX Shouldn't need this */
1344
1345 #elif TARGET_HOST_MS_WINDOWS
1346
1347     /* Make sure we don't close a window with current context active */
1348     if( fgStructure.CurrentWindow == window )
1349         wglMakeCurrent( NULL, NULL );
1350
1351     /*
1352      * Step through the list of windows.  If the rendering context
1353      * is not being used by another window, then we delete it.
1354      */
1355     {
1356         int used = FALSE ;
1357         SFG_Window *iter ;
1358
1359         for( iter = (SFG_Window *)fgStructure.Windows.First;
1360              iter;
1361              iter = (SFG_Window *)iter->Node.Next )
1362         {
1363             if( ( iter->Window.Context == window->Window.Context ) &&
1364                 ( iter != window ) )
1365                 used = TRUE;
1366         }
1367
1368         if( ! used )
1369             wglDeleteContext( window->Window.Context );
1370     }
1371
1372     DestroyWindow( window->Window.Handle );
1373 #endif
1374 }
1375
1376
1377 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
1378
1379 /*
1380  * Creates a new top-level freeglut window
1381  */
1382 int FGAPIENTRY glutCreateWindow( const char* title )
1383 {
1384     /* XXX GLUT does not exit; it simply calls "glutInit" quietly if the
1385      * XXX application has not already done so.  The "freeglut" community
1386      * XXX decided not to go this route (freeglut-developer e-mail from
1387      * XXX Steve Baker, 12/16/04, 4:22 PM CST, "Re: [Freeglut-developer]
1388      * XXX Desired 'freeglut' behaviour when there is no current window"
1389      */
1390     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateWindow" );
1391
1392     return fgCreateWindow( NULL, title, fgState.Position.Use,
1393                            fgState.Position.X, fgState.Position.Y,
1394                            fgState.Size.Use, fgState.Size.X, fgState.Size.Y,
1395                            GL_FALSE, GL_FALSE )->ID;
1396 }
1397
1398 #if TARGET_HOST_MS_WINDOWS
1399 int FGAPIENTRY __glutCreateWindowWithExit( const char *title, void (__cdecl *exit_function)(int) )
1400 {
1401   __glutExitFunc = exit_function;
1402   return glutCreateWindow( title );
1403 }
1404 #endif
1405
1406 /*
1407  * This function creates a sub window.
1408  */
1409 int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h )
1410 {
1411     int ret = 0;
1412     SFG_Window* window = NULL;
1413     SFG_Window* parent = NULL;
1414
1415     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateSubWindow" );
1416     parent = fgWindowByID( parentID );
1417     freeglut_return_val_if_fail( parent != NULL, 0 );
1418     if ( x < 0 )
1419     {
1420         x = parent->State.Width + x ;
1421         if ( w >= 0 ) x -= w ;
1422     }
1423
1424     if ( w < 0 ) w = parent->State.Width - x + w ;
1425     if ( w < 0 )
1426     {
1427         x += w ;
1428         w = -w ;
1429     }
1430
1431     if ( y < 0 )
1432     {
1433         y = parent->State.Height + y ;
1434         if ( h >= 0 ) y -= h ;
1435     }
1436
1437     if ( h < 0 ) h = parent->State.Height - y + h ;
1438     if ( h < 0 )
1439     {
1440         y += h ;
1441         h = -h ;
1442     }
1443
1444     window = fgCreateWindow( parent, "", GL_TRUE, x, y, GL_TRUE, w, h, GL_FALSE, GL_FALSE );
1445     ret = window->ID;
1446
1447     return ret;
1448 }
1449
1450 /*
1451  * Destroys a window and all of its subwindows
1452  */
1453 void FGAPIENTRY glutDestroyWindow( int windowID )
1454 {
1455     SFG_Window* window;
1456     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyWindow" );
1457     window = fgWindowByID( windowID );
1458     freeglut_return_if_fail( window != NULL );
1459     {
1460         fgExecutionState ExecState = fgState.ExecState;
1461         fgAddToWindowDestroyList( window );
1462         fgState.ExecState = ExecState;
1463     }
1464 }
1465
1466 /*
1467  * This function selects the current window
1468  */
1469 void FGAPIENTRY glutSetWindow( int ID )
1470 {
1471     SFG_Window* window = NULL;
1472
1473     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindow" );
1474     if( fgStructure.CurrentWindow != NULL )
1475         if( fgStructure.CurrentWindow->ID == ID )
1476             return;
1477
1478     window = fgWindowByID( ID );
1479     if( window == NULL )
1480     {
1481         fgWarning( "glutSetWindow(): window ID %d not found!", ID );
1482         return;
1483     }
1484
1485     fgSetWindow( window );
1486 }
1487
1488 /*
1489  * This function returns the ID number of the current window, 0 if none exists
1490  */
1491 int FGAPIENTRY glutGetWindow( void )
1492 {
1493     SFG_Window *win = fgStructure.CurrentWindow;
1494     /*
1495      * Since GLUT did not throw an error if this function was called without a prior call to
1496      * "glutInit", this function shouldn't do so here.  Instead let us return a zero.
1497      * See Feature Request "[ 1307049 ] glutInit check".
1498      */
1499     if ( ! fgState.Initialised )
1500         return 0;
1501
1502     while ( win && win->IsMenu )
1503         win = win->Parent;
1504     return win ? win->ID : 0;
1505 }
1506
1507 /*
1508  * This function makes the current window visible
1509  */
1510 void FGAPIENTRY glutShowWindow( void )
1511 {
1512     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutShowWindow" );
1513     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutShowWindow" );
1514
1515 #if TARGET_HOST_POSIX_X11
1516
1517     XMapWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle );
1518     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1519
1520 #elif TARGET_HOST_MS_WINDOWS
1521
1522     ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_SHOW );
1523
1524 #endif
1525
1526     fgStructure.CurrentWindow->State.Redisplay = GL_TRUE;
1527 }
1528
1529 /*
1530  * This function hides the current window
1531  */
1532 void FGAPIENTRY glutHideWindow( void )
1533 {
1534     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutHideWindow" );
1535     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutHideWindow" );
1536
1537 #if TARGET_HOST_POSIX_X11
1538
1539     if( fgStructure.CurrentWindow->Parent == NULL )
1540         XWithdrawWindow( fgDisplay.Display,
1541                          fgStructure.CurrentWindow->Window.Handle,
1542                          fgDisplay.Screen );
1543     else
1544         XUnmapWindow( fgDisplay.Display,
1545                       fgStructure.CurrentWindow->Window.Handle );
1546     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1547
1548 #elif TARGET_HOST_MS_WINDOWS
1549
1550     ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_HIDE );
1551
1552 #endif
1553
1554     fgStructure.CurrentWindow->State.Redisplay = GL_FALSE;
1555 }
1556
1557 /*
1558  * Iconify the current window (top-level windows only)
1559  */
1560 void FGAPIENTRY glutIconifyWindow( void )
1561 {
1562     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIconifyWindow" );
1563     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIconifyWindow" );
1564
1565     fgStructure.CurrentWindow->State.Visible   = GL_FALSE;
1566 #if TARGET_HOST_POSIX_X11
1567
1568     XIconifyWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
1569                     fgDisplay.Screen );
1570     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1571
1572 #elif TARGET_HOST_MS_WINDOWS
1573
1574     ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_MINIMIZE );
1575
1576 #endif
1577
1578     fgStructure.CurrentWindow->State.Redisplay = GL_FALSE;
1579 }
1580
1581 /*
1582  * Set the current window's title
1583  */
1584 void FGAPIENTRY glutSetWindowTitle( const char* title )
1585 {
1586     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowTitle" );
1587     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowTitle" );
1588     if( ! fgStructure.CurrentWindow->Parent )
1589     {
1590 #if TARGET_HOST_POSIX_X11
1591
1592         XTextProperty text;
1593
1594         text.value = (unsigned char *) title;
1595         text.encoding = XA_STRING;
1596         text.format = 8;
1597         text.nitems = strlen( title );
1598
1599         XSetWMName(
1600             fgDisplay.Display,
1601             fgStructure.CurrentWindow->Window.Handle,
1602             &text
1603         );
1604
1605         XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1606
1607 #elif TARGET_HOST_MS_WINDOWS
1608 #    ifdef _WIN32_WCE
1609         {
1610             wchar_t* wstr = fghWstrFromStr(title);
1611             SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr );
1612             free(wstr);
1613         }
1614 #    else
1615         SetWindowText( fgStructure.CurrentWindow->Window.Handle, title );
1616 #    endif
1617
1618 #endif
1619     }
1620 }
1621
1622 /*
1623  * Set the current window's iconified title
1624  */
1625 void FGAPIENTRY glutSetIconTitle( const char* title )
1626 {
1627     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetIconTitle" );
1628     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetIconTitle" );
1629
1630     if( ! fgStructure.CurrentWindow->Parent )
1631     {
1632 #if TARGET_HOST_POSIX_X11
1633
1634         XTextProperty text;
1635
1636         text.value = (unsigned char *) title;
1637         text.encoding = XA_STRING;
1638         text.format = 8;
1639         text.nitems = strlen( title );
1640
1641         XSetWMIconName(
1642             fgDisplay.Display,
1643             fgStructure.CurrentWindow->Window.Handle,
1644             &text
1645         );
1646
1647         XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1648
1649 #elif TARGET_HOST_MS_WINDOWS
1650 #    ifdef _WIN32_WCE
1651         {
1652             wchar_t* wstr = fghWstrFromStr(title);
1653             SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr );
1654             free(wstr);
1655         }
1656 #    else
1657         SetWindowText( fgStructure.CurrentWindow->Window.Handle, title );
1658 #    endif
1659
1660 #endif
1661     }
1662 }
1663
1664 /*
1665  * Change the current window's size
1666  */
1667 void FGAPIENTRY glutReshapeWindow( int width, int height )
1668 {
1669     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" );
1670     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" );
1671
1672     if (glutGet(GLUT_FULL_SCREEN))
1673     {
1674       /*  Leave full screen state before resizing. */
1675       glutFullScreenToggle();
1676     }
1677
1678     fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE;
1679     fgStructure.CurrentWindow->State.Width  = width ;
1680     fgStructure.CurrentWindow->State.Height = height;
1681 }
1682
1683 /*
1684  * Change the current window's position
1685  */
1686 void FGAPIENTRY glutPositionWindow( int x, int y )
1687 {
1688     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" );
1689     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" );
1690
1691     if (glutGet(GLUT_FULL_SCREEN))
1692     {
1693       /*  Leave full screen state before moving. */
1694       glutFullScreenToggle();
1695     }
1696
1697 #if TARGET_HOST_POSIX_X11
1698
1699     XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
1700                  x, y );
1701     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1702
1703 #elif TARGET_HOST_MS_WINDOWS
1704
1705     {
1706         RECT winRect;
1707
1708         /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
1709         GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect );
1710         MoveWindow(
1711             fgStructure.CurrentWindow->Window.Handle,
1712             x,
1713             y,
1714             winRect.right - winRect.left,
1715             winRect.bottom - winRect.top,
1716             TRUE
1717         );
1718     }
1719
1720 #endif
1721 }
1722
1723 /*
1724  * Lowers the current window (by Z order change)
1725  */
1726 void FGAPIENTRY glutPushWindow( void )
1727 {
1728     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" );
1729     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" );
1730
1731 #if TARGET_HOST_POSIX_X11
1732
1733     XLowerWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle );
1734
1735 #elif TARGET_HOST_MS_WINDOWS
1736
1737     SetWindowPos(
1738         fgStructure.CurrentWindow->Window.Handle,
1739         HWND_BOTTOM,
1740         0, 0, 0, 0,
1741         SWP_NOSIZE | SWP_NOMOVE
1742     );
1743
1744 #endif
1745 }
1746
1747 /*
1748  * Raises the current window (by Z order change)
1749  */
1750 void FGAPIENTRY glutPopWindow( void )
1751 {
1752     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" );
1753     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" );
1754
1755 #if TARGET_HOST_POSIX_X11
1756
1757     XRaiseWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle );
1758
1759 #elif TARGET_HOST_MS_WINDOWS
1760
1761     SetWindowPos(
1762         fgStructure.CurrentWindow->Window.Handle,
1763         HWND_TOP,
1764         0, 0, 0, 0,
1765         SWP_NOSIZE | SWP_NOMOVE
1766     );
1767
1768 #endif
1769 }
1770
1771 /*
1772  * Resize the current window so that it fits the whole screen
1773  */
1774 void FGAPIENTRY glutFullScreen( void )
1775 {
1776     SFG_Window *win;
1777
1778     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );
1779     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );
1780
1781     win = fgStructure.CurrentWindow;
1782
1783 #if TARGET_HOST_POSIX_X11
1784     if(!glutGet(GLUT_FULL_SCREEN)) {
1785         if(fghToggleFullscreen() != -1) {
1786             win->State.IsFullscreen = GL_TRUE;
1787         }
1788     }
1789
1790 #elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */
1791
1792     if (glutGet(GLUT_FULL_SCREEN))
1793     {
1794         /*  Leave full screen state before resizing. */
1795         glutFullScreenToggle();
1796     }
1797
1798     {
1799         RECT rect;
1800
1801         /* For fullscreen mode, force the top-left corner to 0,0
1802          * and adjust the window rectangle so that the client area
1803          * covers the whole screen.
1804          */
1805
1806         rect.left   = 0;
1807         rect.top    = 0;
1808         get_display_origin(&rect.left,&rect.top);
1809         rect.right  = fgDisplay.ScreenWidth+rect.left;
1810         rect.bottom = fgDisplay.ScreenHeight+rect.top;
1811
1812         AdjustWindowRect ( &rect, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS |
1813                                   WS_CLIPCHILDREN, FALSE );
1814
1815         /*
1816          * SWP_NOACTIVATE     Do not activate the window
1817          * SWP_NOOWNERZORDER  Do not change position in z-order
1818          * SWP_NOSENDCHANGING Supress WM_WINDOWPOSCHANGING message
1819          * SWP_NOZORDER       Retains the current Z order (ignore 2nd param)
1820          */
1821
1822         SetWindowPos( fgStructure.CurrentWindow->Window.Handle,
1823                       HWND_TOP,
1824                       rect.left,
1825                       rect.top,
1826                       rect.right  - rect.left,
1827                       rect.bottom - rect.top,
1828                       SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
1829                       SWP_NOZORDER
1830                     );
1831         
1832         win->State.IsFullscreen = GL_TRUE;
1833     }
1834 #endif
1835 }
1836
1837 /*
1838  * Toggle the window's full screen state.
1839  */
1840 void FGAPIENTRY glutFullScreenToggle( void )
1841 {
1842     SFG_Window *win;
1843
1844     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" );
1845     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" );
1846
1847     win = fgStructure.CurrentWindow;
1848
1849 #if TARGET_HOST_POSIX_X11
1850     if(fghToggleFullscreen() != -1) {
1851         win->State.IsFullscreen = !win->State.IsFullscreen;
1852     }
1853 #elif TARGET_HOST_MS_WINDOWS
1854     glutFullScreen();
1855     win->State.IsFullscreen = !win->State.IsFullscreen;
1856 #endif
1857 }
1858
1859 /*
1860  * A.Donev: Set and retrieve the window's user data
1861  */
1862 void* FGAPIENTRY glutGetWindowData( void )
1863 {
1864     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" );
1865     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" );
1866     return fgStructure.CurrentWindow->UserData;
1867 }
1868
1869 void FGAPIENTRY glutSetWindowData(void* data)
1870 {
1871     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" );
1872     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" );
1873     fgStructure.CurrentWindow->UserData = data;
1874 }
1875
1876 /*** END OF FILE ***/