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