6aaeb7d73b6d1f7f9f6ed920239707cb4da68a84
[freeglut] / src / mswin / freeglut_window_mswin.c
1 /*\r
2  * freeglut_window_mswin.c\r
3  *\r
4  * The Windows-specific mouse cursor related stuff.\r
5  *\r
6  * Copyright (c) 2012 Stephen J. Baker. All Rights Reserved.\r
7  * Written by John F. Fay, <fayjf@sourceforge.net>\r
8  * Creation date: Sun Jan 22, 2012\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 #include <GL/freeglut.h>\r
29 #include "freeglut_internal_mswin.h"\r
30 \r
31 \r
32 /* The following include file is available from SGI but is not standard:\r
33  *   #include <GL/wglext.h>\r
34  * So we copy the necessary parts out of it.\r
35  * XXX: should local definitions for extensions be put in a separate include file?\r
36  */\r
37 typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc);\r
38 \r
39 typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);\r
40 \r
41 #define WGL_DRAW_TO_WINDOW_ARB         0x2001\r
42 #define WGL_ACCELERATION_ARB           0x2003\r
43 #define WGL_SUPPORT_OPENGL_ARB         0x2010\r
44 #define WGL_DOUBLE_BUFFER_ARB          0x2011\r
45 #define WGL_COLOR_BITS_ARB             0x2014\r
46 #define WGL_ALPHA_BITS_ARB             0x201B\r
47 #define WGL_DEPTH_BITS_ARB             0x2022\r
48 #define WGL_STENCIL_BITS_ARB           0x2023\r
49 #define WGL_FULL_ACCELERATION_ARB      0x2027\r
50 \r
51 #define WGL_SAMPLE_BUFFERS_ARB         0x2041\r
52 #define WGL_SAMPLES_ARB                0x2042\r
53 \r
54 #define WGL_TYPE_RGBA_FLOAT_ARB        0x21A0\r
55 \r
56 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9\r
57 \r
58 #ifndef WGL_ARB_create_context\r
59 #define WGL_ARB_create_context 1\r
60 #ifdef WGL_WGLEXT_PROTOTYPES\r
61 extern HGLRC WINAPI wglCreateContextAttribsARB (HDC, HGLRC, const int *);\r
62 #endif /* WGL_WGLEXT_PROTOTYPES */\r
63 typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList);\r
64 \r
65 #define WGL_CONTEXT_MAJOR_VERSION_ARB  0x2091\r
66 #define WGL_CONTEXT_MINOR_VERSION_ARB  0x2092\r
67 #define WGL_CONTEXT_LAYER_PLANE_ARB    0x2093\r
68 #define WGL_CONTEXT_FLAGS_ARB          0x2094\r
69 #define WGL_CONTEXT_PROFILE_MASK_ARB   0x9126\r
70 \r
71 #define WGL_CONTEXT_DEBUG_BIT_ARB      0x0001\r
72 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002\r
73 \r
74 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001\r
75 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002\r
76 \r
77 #define ERROR_INVALID_VERSION_ARB      0x2095\r
78 #define ERROR_INVALID_PROFILE_ARB      0x2096\r
79 #endif\r
80 /* End of copying the necessary parts out of it. */\r
81 \r
82 /* pushing attribute/value pairs into an array */\r
83 #define ATTRIB(a) attributes[where++]=(a)\r
84 #define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);}\r
85 \r
86 \r
87 extern int fghIsLegacyContextVersionRequested( void );\r
88 extern int fghMapBit( int mask, int from, int to );\r
89 extern int fghIsLegacyContextRequested( void );\r
90 extern void fghContextCreationError( void );\r
91 extern int fghNumberOfAuxBuffersRequested( void );\r
92 \r
93 \r
94 /*\r
95  * Setup the pixel format for a Win32 window\r
96  */\r
97 \r
98 #if defined(_WIN32_WCE)\r
99 static wchar_t* fghWstrFromStr(const char* str)\r
100 {\r
101     int i,len=strlen(str);\r
102     wchar_t* wstr = (wchar_t*)malloc(2*len+2);\r
103     for(i=0; i<len; i++)\r
104         wstr[i] = str[i];\r
105     wstr[len] = 0;\r
106     return wstr;\r
107 }\r
108 #endif /* defined(_WIN32_WCE) */\r
109 \r
110 \r
111 static void fghFillContextAttributes( int *attributes ) {\r
112   int where = 0, contextFlags, contextProfile;\r
113 \r
114   if ( !fghIsLegacyContextVersionRequested() ) {\r
115     ATTRIB_VAL( WGL_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion );\r
116     ATTRIB_VAL( WGL_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion );\r
117   }\r
118 \r
119   contextFlags =\r
120     fghMapBit( fgState.ContextFlags, GLUT_DEBUG, WGL_CONTEXT_DEBUG_BIT_ARB ) |\r
121     fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB );\r
122   if ( contextFlags != 0 ) {\r
123     ATTRIB_VAL( WGL_CONTEXT_FLAGS_ARB, contextFlags );\r
124   }\r
125 \r
126   contextProfile =\r
127     fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, WGL_CONTEXT_CORE_PROFILE_BIT_ARB ) |\r
128     fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB );\r
129   if ( contextProfile != 0 ) {\r
130     ATTRIB_VAL( WGL_CONTEXT_PROFILE_MASK_ARB, contextProfile );\r
131   }\r
132 \r
133   ATTRIB( 0 );\r
134 }\r
135 \r
136 static int fghIsExtensionSupported( HDC hdc, const char *extension ) {\r
137     const char *pWglExtString;\r
138     PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetEntensionsStringARB =\r
139       (PFNWGLGETEXTENSIONSSTRINGARBPROC) wglGetProcAddress("wglGetExtensionsStringARB");\r
140     if ( wglGetEntensionsStringARB == NULL )\r
141     {\r
142       return FALSE;\r
143     }\r
144     pWglExtString = wglGetEntensionsStringARB( hdc );\r
145     return ( pWglExtString != NULL ) && ( strstr(pWglExtString, extension) != NULL );\r
146 }\r
147 \r
148 void fgNewWGLCreateContext( SFG_Window* window )\r
149 {\r
150     HGLRC context;\r
151     int attributes[9];\r
152     PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;\r
153 \r
154     /* If nothing fancy has been required, leave the context as it is */\r
155     if ( fghIsLegacyContextRequested() )\r
156     {\r
157         return;\r
158     }\r
159 \r
160     wglMakeCurrent( window->Window.Device, window->Window.Context );\r
161 \r
162     if ( !fghIsExtensionSupported( window->Window.Device, "WGL_ARB_create_context" ) )\r
163     {\r
164         return;\r
165     }\r
166 \r
167     /* new context creation */\r
168     fghFillContextAttributes( attributes );\r
169 \r
170     wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress( "wglCreateContextAttribsARB" );\r
171     if ( wglCreateContextAttribsARB == NULL )\r
172     {\r
173         fgError( "wglCreateContextAttribsARB not found" );\r
174     }\r
175 \r
176     context = wglCreateContextAttribsARB( window->Window.Device, 0, attributes );\r
177     if ( context == NULL )\r
178     {\r
179         fghContextCreationError();\r
180     }\r
181 \r
182     wglMakeCurrent( NULL, NULL );\r
183     wglDeleteContext( window->Window.Context );\r
184     window->Window.Context = context;\r
185 }\r
186 \r
187 #if !defined(_WIN32_WCE)\r
188 \r
189 static void fghFillPFD( PIXELFORMATDESCRIPTOR *ppfd, HDC hdc, unsigned char layer_type )\r
190 {\r
191   int flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;\r
192   if ( fgState.DisplayMode & GLUT_DOUBLE ) {\r
193         flags |= PFD_DOUBLEBUFFER;\r
194   }\r
195   if ( fgState.DisplayMode & GLUT_STEREO ) {\r
196     flags |= PFD_STEREO;\r
197   }\r
198 \r
199 #if defined(_MSC_VER)\r
200 #pragma message( "fgSetupPixelFormat(): there is still some work to do here!" )\r
201 #endif\r
202 \r
203   /* Specify which pixel format do we opt for... */\r
204   ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);\r
205   ppfd->nVersion = 1;\r
206   ppfd->dwFlags = flags;\r
207 \r
208   if( fgState.DisplayMode & GLUT_INDEX ) {\r
209     ppfd->iPixelType = PFD_TYPE_COLORINDEX;\r
210     ppfd->cRedBits = 0;\r
211     ppfd->cGreenBits = 0;\r
212     ppfd->cBlueBits = 0;\r
213     ppfd->cAlphaBits = 0;\r
214   } else {\r
215     ppfd->iPixelType = PFD_TYPE_RGBA;\r
216     ppfd->cRedBits = 8;\r
217     ppfd->cGreenBits = 8;\r
218     ppfd->cBlueBits = 8;\r
219     ppfd->cAlphaBits = ( fgState.DisplayMode & GLUT_ALPHA ) ? 8 : 0;\r
220   }\r
221 \r
222   ppfd->cColorBits = 24;\r
223   ppfd->cRedShift = 0;\r
224   ppfd->cGreenShift = 0;\r
225   ppfd->cBlueShift = 0;\r
226   ppfd->cAlphaShift = 0;\r
227   ppfd->cAccumBits = ( fgState.DisplayMode & GLUT_ACCUM ) ? 1 : 0;\r
228   ppfd->cAccumRedBits = 0;\r
229   ppfd->cAccumGreenBits = 0;\r
230   ppfd->cAccumBlueBits = 0;\r
231   ppfd->cAccumAlphaBits = 0;\r
232 \r
233   /* Hmmm, or 32/0 instead of 24/8? */\r
234   ppfd->cDepthBits = 24;\r
235   ppfd->cStencilBits = 8;\r
236 \r
237   ppfd->cAuxBuffers = fghNumberOfAuxBuffersRequested();\r
238   ppfd->iLayerType = layer_type;\r
239   ppfd->bReserved = 0;\r
240   ppfd->dwLayerMask = 0;\r
241   ppfd->dwVisibleMask = 0;\r
242   ppfd->dwDamageMask = 0;\r
243   \r
244   ppfd->cColorBits = (BYTE) GetDeviceCaps( hdc, BITSPIXEL );\r
245 }\r
246 \r
247 static void fghFillPixelFormatAttributes( int *attributes, const PIXELFORMATDESCRIPTOR *ppfd )\r
248 {\r
249   int where = 0;\r
250 \r
251   ATTRIB_VAL( WGL_DRAW_TO_WINDOW_ARB, GL_TRUE );\r
252   ATTRIB_VAL( WGL_SUPPORT_OPENGL_ARB, GL_TRUE );\r
253   ATTRIB_VAL( WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB );\r
254 \r
255   ATTRIB_VAL( WGL_COLOR_BITS_ARB, ppfd->cColorBits );\r
256   ATTRIB_VAL( WGL_ALPHA_BITS_ARB, ppfd->cAlphaBits );\r
257   ATTRIB_VAL( WGL_DEPTH_BITS_ARB, ppfd->cDepthBits );\r
258   ATTRIB_VAL( WGL_STENCIL_BITS_ARB, ppfd->cStencilBits );\r
259 \r
260   ATTRIB_VAL( WGL_DOUBLE_BUFFER_ARB, ( fgState.DisplayMode & GLUT_DOUBLE ) != 0 );\r
261 \r
262   if ( fgState.DisplayMode & GLUT_SRGB ) {\r
263     ATTRIB_VAL( WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, TRUE );\r
264   }\r
265 \r
266   ATTRIB_VAL( WGL_SAMPLE_BUFFERS_ARB, GL_TRUE );\r
267   ATTRIB_VAL( WGL_SAMPLES_ARB, fgState.SampleNumber );\r
268   ATTRIB( 0 );\r
269 }\r
270 #endif\r
271 \r
272 GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,\r
273                               unsigned char layer_type )\r
274 {\r
275 #if defined(_WIN32_WCE)\r
276     return GL_TRUE;\r
277 #else\r
278     PIXELFORMATDESCRIPTOR pfd;\r
279     PIXELFORMATDESCRIPTOR* ppfd = &pfd;\r
280     int pixelformat;\r
281     HDC current_hDC;\r
282     GLboolean success;\r
283 \r
284     if (checkOnly)\r
285       current_hDC = CreateDC(TEXT("DISPLAY"), NULL ,NULL ,NULL);\r
286     else\r
287       current_hDC = window->Window.Device;\r
288 \r
289     fghFillPFD( ppfd, current_hDC, layer_type );\r
290     pixelformat = ChoosePixelFormat( current_hDC, ppfd );\r
291 \r
292     /* windows hack for multismapling/sRGB */\r
293     if ( ( fgState.DisplayMode & GLUT_MULTISAMPLE ) ||\r
294          ( fgState.DisplayMode & GLUT_SRGB ) )\r
295     {        \r
296         HGLRC rc, rc_before=wglGetCurrentContext();\r
297         HWND hWnd;\r
298         HDC hDC, hDC_before=wglGetCurrentDC();\r
299         WNDCLASS wndCls;\r
300 \r
301         /* create a dummy window */\r
302         ZeroMemory(&wndCls, sizeof(wndCls));\r
303         wndCls.lpfnWndProc = DefWindowProc;\r
304         wndCls.hInstance = fgDisplay.Instance;\r
305         wndCls.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;\r
306         wndCls.lpszClassName = _T("FREEGLUT_dummy");\r
307         RegisterClass( &wndCls );\r
308 \r
309         hWnd=CreateWindow(_T("FREEGLUT_dummy"), _T(""), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW , 0,0,0,0, 0, 0, fgDisplay.Instance, 0 );\r
310         hDC=GetDC(hWnd);\r
311         SetPixelFormat( hDC, pixelformat, ppfd );\r
312 \r
313         rc = wglCreateContext( hDC );\r
314         wglMakeCurrent(hDC, rc);\r
315 \r
316         if ( fghIsExtensionSupported( hDC, "WGL_ARB_multisample" ) )\r
317         {\r
318             PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARBProc =\r
319               (PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatARB");\r
320             if ( wglChoosePixelFormatARBProc )\r
321             {\r
322                 int attributes[100];\r
323                 int iPixelFormat;\r
324                 BOOL bValid;\r
325                 float fAttributes[] = { 0, 0 };\r
326                 UINT numFormats;\r
327                 fghFillPixelFormatAttributes( attributes, ppfd );\r
328                 bValid = wglChoosePixelFormatARBProc(hDC, attributes, fAttributes, 1, &iPixelFormat, &numFormats);\r
329 \r
330                 if ( bValid && numFormats > 0 )\r
331                 {\r
332                     pixelformat = iPixelFormat;\r
333                 }\r
334             }\r
335         }\r
336 \r
337         wglMakeCurrent( hDC_before, rc_before);\r
338         wglDeleteContext(rc);\r
339         ReleaseDC(hWnd, hDC);\r
340         DestroyWindow(hWnd);\r
341         UnregisterClass(_T("FREEGLUT_dummy"), fgDisplay.Instance);\r
342     }\r
343 \r
344     success = ( pixelformat != 0 ) && ( checkOnly || SetPixelFormat( current_hDC, pixelformat, ppfd ) );\r
345 \r
346     if (checkOnly)\r
347         DeleteDC(current_hDC);\r
348 \r
349     return success;\r
350 #endif /* defined(_WIN32_WCE) */\r
351 }\r
352 \r
353 \r
354 \r
355 void fgPlatformSetWindow ( SFG_Window *window )\r
356 {\r
357     if ( window != fgStructure.CurrentWindow )\r
358     {\r
359         if( fgStructure.CurrentWindow )\r
360             ReleaseDC( fgStructure.CurrentWindow->Window.Handle,\r
361                        fgStructure.CurrentWindow->Window.Device );\r
362 \r
363         if ( window )\r
364         {\r
365             window->Window.Device = GetDC( window->Window.Handle );\r
366             wglMakeCurrent(\r
367                 window->Window.Device,\r
368                 window->Window.Context\r
369             );\r
370         }\r
371     }\r
372 }\r
373 \r
374 \r
375 \r
376 /* Computes position of corners of window Rect (outer position including\r
377  * decorations) based on the provided client rect and based on the style\r
378  * of the window in question.\r
379  * If posIsOutside is set to true, the input client Rect is taken to follow\r
380  * freeGLUT's window specification convention in which the top-left corner\r
381  * is at the outside of the window, while the size\r
382  * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable\r
383  * area.\r
384  */\r
385 void fghComputeWindowRectFromClientArea_UseStyle( const DWORD windowStyle, RECT *clientRect, BOOL posIsOutside )\r
386 {\r
387     int xBorderWidth = 0, yBorderWidth = 0;\r
388 \r
389     /* If window has title bar, correct rect for it */\r
390     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
391         if (posIsOutside)\r
392             clientRect->bottom += GetSystemMetrics( SM_CYCAPTION );\r
393         else\r
394             clientRect->top -= GetSystemMetrics( SM_CYCAPTION );\r
395 \r
396     /* get width of window's borders (frame), correct rect for it.\r
397      * Note, borders can be of zero width if style does not specify borders\r
398      */\r
399     fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth);\r
400     if (posIsOutside)\r
401     {\r
402         clientRect->right  += xBorderWidth * 2;\r
403         clientRect->bottom += yBorderWidth * 2;\r
404     }\r
405     else\r
406     {\r
407         clientRect->left   -= xBorderWidth;\r
408         clientRect->right  += xBorderWidth;\r
409         clientRect->top    -= yBorderWidth;\r
410         clientRect->bottom += yBorderWidth;\r
411     }\r
412 }\r
413 \r
414 /* Computes position of corners of window Rect (outer position including\r
415  * decorations) based on the provided client rect and based on the style\r
416  * of the window in question. If the window pointer or the window handle\r
417  * is NULL, a fully decorated window (caption and border) is assumed.\r
418  * Furthermore, if posIsOutside is set to true, the input client Rect is\r
419  * taken to follow freeGLUT's window specification convention in which the\r
420  * top-left corner is at the outside of the window, while the size\r
421  * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable\r
422  * area.\r
423 */\r
424 void fghComputeWindowRectFromClientArea_QueryWindow( const SFG_Window *window, RECT *clientRect, BOOL posIsOutside )\r
425 {\r
426     DWORD windowStyle = 0;\r
427 \r
428     if (window && window->Window.Handle)\r
429         windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE);\r
430     else\r
431         windowStyle = WS_OVERLAPPEDWINDOW;\r
432 \r
433     fghComputeWindowRectFromClientArea_UseStyle(windowStyle, clientRect, posIsOutside);\r
434 }\r
435 \r
436 /* Computes position of corners of client area (drawable area) of a window\r
437  * based on the provided window Rect (outer position including decorations)\r
438  * and based on the style of the window in question. If the window pointer\r
439  * or the window handle is NULL, a fully decorated window (caption and\r
440  * border) is assumed.\r
441  * Furthermore, if wantPosOutside is set to true, the output client Rect\r
442  * will follow freeGLUT's window specification convention in which the\r
443  * top-left corner is at the outside of the window, the size\r
444  * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable\r
445  * area.\r
446  */\r
447 void fghComputeClientAreaFromWindowRect( const SFG_Window *window, RECT *windowRect, BOOL wantPosOutside )\r
448 {\r
449     DWORD windowStyle = 0;\r
450     int xBorderWidth = 0, yBorderWidth = 0;\r
451 \r
452     if (window && window->Window.Handle)\r
453         windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE);\r
454     else\r
455         windowStyle = WS_OVERLAPPEDWINDOW;\r
456 \r
457     /* If window has title bar, correct rect for it */\r
458     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
459         if (wantPosOutside)\r
460             windowRect->bottom -= GetSystemMetrics( SM_CYCAPTION );\r
461         else\r
462             windowRect->top    += GetSystemMetrics( SM_CYCAPTION );\r
463 \r
464     /* get width of window's borders (frame), correct rect for it.\r
465      * Note, borders can be of zero width if style does not specify borders\r
466      */\r
467     fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth);\r
468     if (wantPosOutside)\r
469     {\r
470         windowRect->right  -= xBorderWidth * 2;\r
471         windowRect->bottom -= yBorderWidth * 2;\r
472     }\r
473     else\r
474     {\r
475         windowRect->left   += xBorderWidth;\r
476         windowRect->right  -= xBorderWidth;\r
477         windowRect->top    += yBorderWidth;\r
478         windowRect->bottom -= yBorderWidth;\r
479     }\r
480 }\r
481 \r
482 /* Gets the rect describing the client area (drawable area) of the\r
483  * specified window.\r
484  * Returns an empty rect if window pointer or window handle is NULL.\r
485  * If wantPosOutside is set to true, the output client Rect\r
486  * will follow freeGLUT's window specification convention in which the\r
487  * top-left corner is at the outside of the window, while the size\r
488  * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable\r
489  * area.\r
490  */\r
491 RECT fghGetClientArea( const SFG_Window *window, BOOL wantPosOutside )\r
492 {\r
493     RECT windowRect = {0,0,0,0};\r
494 \r
495     freeglut_return_val_if_fail((window && window->Window.Handle),windowRect);\r
496     \r
497     /*\r
498      * call GetWindowRect()\r
499      * (this returns the pixel coordinates of the outside of the window)\r
500      */\r
501     GetWindowRect( window->Window.Handle, &windowRect );\r
502 \r
503     /* Then correct the results */\r
504     fghComputeClientAreaFromWindowRect(window, &windowRect, wantPosOutside);\r
505 \r
506     return windowRect;\r
507 }\r
508 \r
509 /* Returns the width of the window borders based on the window's style.\r
510  */\r
511 void fghGetBorderWidth(const DWORD windowStyle, int* xBorderWidth, int* yBorderWidth)\r
512 {\r
513     if (windowStyle & WS_THICKFRAME)\r
514     {\r
515         *xBorderWidth = GetSystemMetrics(SM_CXSIZEFRAME);\r
516         *yBorderWidth = GetSystemMetrics(SM_CYSIZEFRAME);\r
517     }\r
518     else if (windowStyle & WS_DLGFRAME)\r
519     {\r
520         *xBorderWidth = GetSystemMetrics(SM_CXFIXEDFRAME);\r
521         *yBorderWidth = GetSystemMetrics(SM_CYFIXEDFRAME);\r
522     }\r
523     else\r
524     {\r
525         *xBorderWidth = 0;\r
526         *yBorderWidth = 0;\r
527     }\r
528 }\r
529 \r
530 #if(WINVER >= 0x500)\r
531 typedef struct\r
532 {\r
533       int *x;\r
534       int *y;\r
535       const char *name;\r
536 } m_proc_t;\r
537 \r
538 static BOOL CALLBACK m_proc(HMONITOR mon,\r
539                             HDC hdc,\r
540                             LPRECT rect,\r
541                             LPARAM data)\r
542 {\r
543       m_proc_t *dp=(m_proc_t *)data;\r
544       MONITORINFOEX info;\r
545       BOOL res;\r
546       info.cbSize=sizeof(info);\r
547       res=GetMonitorInfo(mon,(LPMONITORINFO)&info);\r
548       if( res )\r
549       {\r
550           if( strcmp(dp->name,info.szDevice)==0 )\r
551           {\r
552               *(dp->x)=info.rcMonitor.left;\r
553               *(dp->y)=info.rcMonitor.top;\r
554               return FALSE;\r
555           }\r
556       }\r
557       return TRUE;\r
558 }\r
559 \r
560 /* \r
561  * this function returns the origin of the screen identified by\r
562  * fgDisplay.DisplayName, and 0 otherwise.\r
563  * This is used in fgOpenWindow to open the gamemode window on the screen\r
564  * identified by the -display command line argument. The function should\r
565  * not be called otherwise.\r
566  */\r
567 \r
568 static void get_display_origin(int *xp,int *yp)\r
569 {\r
570     *xp = 0;\r
571     *yp = 0;\r
572 \r
573     if( fgDisplay.DisplayName )\r
574     {\r
575         m_proc_t st;\r
576         st.x=xp;\r
577         st.y=yp;\r
578         st.name=fgDisplay.DisplayName;\r
579         EnumDisplayMonitors(0,0,m_proc,(LPARAM)&st);\r
580     }\r
581 }\r
582 #else\r
583 #pragma message( "-display parameter only works if compiled with WINVER >= 0x0500")\r
584 \r
585 static void get_display_origin(int *xp,int *yp)\r
586 {\r
587     *xp = 0;\r
588     *yp = 0;\r
589 \r
590     if( fgDisplay.DisplayName )\r
591     {\r
592         fgWarning( "for working -display support FreeGLUT must be compiled with WINVER >= 0x0500");\r
593     }\r
594 }\r
595 #endif\r
596 \r
597 \r
598 \r
599 /*\r
600  * Opens a window. Requires a SFG_Window object created and attached\r
601  * to the freeglut structure. OpenGL context is created here.\r
602  */\r
603 void fgPlatformOpenWindow( SFG_Window* window, const char* title,\r
604                            GLboolean positionUse, int x, int y,\r
605                            GLboolean sizeUse, int w, int h,\r
606                            GLboolean gameMode, GLboolean isSubWindow )\r
607 {\r
608 \r
609     WNDCLASS wc;\r
610     DWORD flags   = 0;\r
611     DWORD exFlags = 0;\r
612     ATOM atom;\r
613 \r
614     /* Grab the window class we have registered on glutInit(): */\r
615     atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc );\r
616     FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Info Not Found",\r
617                                    "fgOpenWindow" );\r
618 \r
619     /* Determine window style flags*/\r
620     if( gameMode )\r
621     {\r
622         FREEGLUT_INTERNAL_ERROR_EXIT ( window->Parent == NULL,\r
623                                        "Game mode being invoked on a subwindow",\r
624                                        "fgOpenWindow" );\r
625 \r
626         /*\r
627          * Set the window creation flags appropriately to make the window\r
628          * entirely visible:\r
629          */\r
630         flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;\r
631     }\r
632     else\r
633     {\r
634         flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;\r
635 \r
636         /*\r
637          * There's a small difference between creating the top, child and\r
638          * menu windows\r
639          */\r
640         if ( window->IsMenu )\r
641         {\r
642             flags |= WS_POPUP;\r
643             exFlags |= WS_EX_TOOLWINDOW;\r
644         }\r
645 #if defined(_WIN32_WCE)\r
646         /* no decorations for windows CE */\r
647 #else\r
648         /* if this is not a subwindow (child), set its style based on the requested display mode */\r
649         else if( window->Parent == NULL )\r
650             if ( fgState.DisplayMode & GLUT_BORDERLESS )\r
651             {\r
652                 /* no window decorations needed */\r
653             }\r
654             else if ( fgState.DisplayMode & GLUT_CAPTIONLESS )\r
655                 /* only window decoration is a border, no title bar or buttons */\r
656                 flags |= WS_DLGFRAME;\r
657             else\r
658                 /* window decoration are a border, title bar and buttons.\r
659                  * NB: we later query whether the window has a title bar or\r
660                  * not by testing for the maximize button, as the test for\r
661                  * WS_CAPTION can be true without the window having a title\r
662                  * bar. This style WS_OVERLAPPEDWINDOW gives you a maximize\r
663                  * button. */\r
664                 flags |= WS_OVERLAPPEDWINDOW;\r
665 #endif\r
666         else\r
667             /* subwindows always have no decoration, but are marked as a child window to the OS */\r
668             flags |= WS_CHILD;\r
669     }\r
670 \r
671     /* determine window size and position */\r
672     if( gameMode )\r
673     {\r
674         /* if in gamemode, query the origin of specified by the -display\r
675          * command line parameter (if any) and offset the upper-left corner\r
676          * of the window so we create the window on that screen.\r
677          * The -display argument doesn't do anything if not trying to enter\r
678          * gamemode.\r
679          */\r
680         int xoff=0, yoff=0;\r
681         get_display_origin(&xoff,&yoff);\r
682         x += xoff;\r
683         y += yoff;\r
684     }\r
685     if( !positionUse )\r
686     {\r
687         x = CW_USEDEFAULT;\r
688         y = CW_USEDEFAULT;\r
689     }\r
690     if( !sizeUse )\r
691     {\r
692         if( ! window->IsMenu )\r
693         {\r
694             w = CW_USEDEFAULT;\r
695             h = CW_USEDEFAULT;\r
696         }\r
697         else /* fail safe - Windows can make a window of size (0, 0) */\r
698             w = h = 300; /* default window size */\r
699     }\r
700     /* store requested client area width and height */\r
701     window->State.Width = w;\r
702     window->State.Height = h;\r
703 \r
704 #if !defined(_WIN32_WCE)    /* no decorations for windows CE */\r
705     if( sizeUse )\r
706     {\r
707         RECT windowRect;\r
708         /*\r
709          * Update the window dimensions, taking the window decorations\r
710          * into account.  FreeGLUT is to create the window with the\r
711          * topleft outside corner at (x,y) and with client area\r
712          * dimensions (w,h).\r
713          * note: don't need to do this when w=h=CW_USEDEFAULT, so in the\r
714          * if( sizeUse ) here is convenient.\r
715          */\r
716         windowRect.left     = x;\r
717         windowRect.top      = y;\r
718         windowRect.right    = x+w;\r
719         windowRect.bottom   = y+h;\r
720 \r
721         fghComputeWindowRectFromClientArea_UseStyle(flags,&windowRect,TRUE);\r
722 \r
723         w = windowRect.right - windowRect.left;\r
724         h = windowRect.bottom- windowRect.top;\r
725     }\r
726 #endif /* !defined(_WIN32_WCE) */\r
727 \r
728 #if defined(_WIN32_WCE)\r
729     {\r
730         wchar_t* wstr = fghWstrFromStr(title);\r
731 \r
732         window->Window.Handle = CreateWindow(\r
733             _T("FREEGLUT"),\r
734             wstr,\r
735             WS_VISIBLE | WS_POPUP,\r
736             0,0, 240,320,\r
737             NULL,\r
738             NULL,\r
739             fgDisplay.Instance,\r
740             (LPVOID) window\r
741         );\r
742 \r
743         free(wstr);\r
744 \r
745         SHFullScreen(window->Window.Handle, SHFS_HIDESTARTICON);\r
746         SHFullScreen(window->Window.Handle, SHFS_HIDESIPBUTTON);\r
747         SHFullScreen(window->Window.Handle, SHFS_HIDETASKBAR);\r
748         MoveWindow(window->Window.Handle, 0, 0, 240, 320, TRUE);\r
749         ShowWindow(window->Window.Handle, SW_SHOW);\r
750         UpdateWindow(window->Window.Handle);\r
751     }\r
752 #else\r
753     window->Window.Handle = CreateWindowEx(\r
754         exFlags,\r
755         _T("FREEGLUT"),\r
756         title,\r
757         flags,\r
758         x, y, w, h,\r
759         (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle,\r
760         (HMENU) NULL,\r
761         fgDisplay.Instance,\r
762         (LPVOID) window\r
763     );\r
764 #endif /* defined(_WIN32_WCE) */\r
765 \r
766     if( !( window->Window.Handle ) )\r
767         fgError( "Failed to create a window (%s)!", title );\r
768 \r
769 #if !defined(_WIN32_WCE)\r
770     /* Need to set requested style again, apparently Windows doesn't listen when requesting windows without title bar or borders */\r
771     SetWindowLong(window->Window.Handle, GWL_STYLE, flags);\r
772     SetWindowPos(window->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);\r
773 #endif /* defined(_WIN32_WCE) */\r
774 \r
775     /* Make a menu window always on top - fix Feature Request 947118 */\r
776     if( window->IsMenu || gameMode )\r
777         SetWindowPos(\r
778                         window->Window.Handle,\r
779                         HWND_TOPMOST,\r
780                         0, 0, 0, 0,\r
781                         SWP_NOMOVE | SWP_NOSIZE\r
782                     );\r
783 \r
784     /* Enable multitouch: additional flag TWF_FINETOUCH, TWF_WANTPALM */\r
785     #ifdef WM_TOUCH\r
786         if (fghRegisterTouchWindow == (pRegisterTouchWindow)0xDEADBEEF) \r
787                         fghRegisterTouchWindow = (pRegisterTouchWindow)GetProcAddress(GetModuleHandle("user32"),"RegisterTouchWindow");\r
788                 if (fghRegisterTouchWindow)\r
789              fghRegisterTouchWindow( window->Window.Handle, TWF_FINETOUCH | TWF_WANTPALM );\r
790     #endif\r
791 \r
792 #if defined(_WIN32_WCE)\r
793     ShowWindow( window->Window.Handle, SW_SHOW );\r
794 #else\r
795     ShowWindow( window->Window.Handle,\r
796                 fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW );\r
797 #endif /* defined(_WIN32_WCE) */\r
798 \r
799     UpdateWindow( window->Window.Handle );\r
800     ShowCursor( TRUE );  /* XXX Old comments say "hide cursor"! */\r
801 \r
802 }\r
803 \r
804 \r
805 /*\r
806  * Closes a window, destroying the frame and OpenGL context\r
807  */\r
808 void fgPlatformCloseWindow( SFG_Window* window )\r
809 {\r
810     /* Make sure we don't close a window with current context active */\r
811     if( fgStructure.CurrentWindow == window )\r
812         wglMakeCurrent( NULL, NULL );\r
813 \r
814     /*\r
815      * Step through the list of windows.  If the rendering context\r
816      * is not being used by another window, then we delete it.\r
817      */\r
818     {\r
819         int used = FALSE ;\r
820         SFG_Window *iter ;\r
821 \r
822         for( iter = (SFG_Window *)fgStructure.Windows.First;\r
823              iter;\r
824              iter = (SFG_Window *)iter->Node.Next )\r
825         {\r
826             if( ( iter->Window.Context == window->Window.Context ) &&\r
827                 ( iter != window ) )\r
828                 used = TRUE;\r
829         }\r
830 \r
831         if( ! used )\r
832             wglDeleteContext( window->Window.Context );\r
833     }\r
834 \r
835     DestroyWindow( window->Window.Handle );\r
836 }\r
837 \r
838 \r
839 \r