- fallback to non-sRGB visuals if the context creation failed (GLX-only)
[freeglut] / src / mswin / fg_state_mswin.c
1 /*
2  * fg_state_mswin.c
3  *
4  * The Windows-specific state query methods.
5  *
6  * Copyright (c) 2012 Stephen J. Baker. All Rights Reserved.
7  * Written by John F. Fay, <fayjf@sourceforge.net>
8  * Creation date: Sun Jan 22, 2012
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  */
27
28 #include <GL/freeglut.h>
29 #include "../fg_internal.h"
30
31
32 extern GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
33                                      unsigned char layer_type );
34
35 /*
36  * Helper functions for getting client area from the window rect
37  * and the window rect from the client area given the style of the window
38  * (or a valid window pointer from which the style can be queried).
39  */
40 extern void fghGetClientArea( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside );
41 extern void fghGetStyleFromWindow( const SFG_Window *window, DWORD *windowStyle, DWORD *windowExStyle );
42 extern void fghComputeWindowRectFromClientArea_UseStyle( RECT *clientRect, const DWORD windowStyle, const DWORD windowExStyle, BOOL posIsOutside );
43
44
45 /* The following include file is available from SGI but is not standard:
46  *   #include <GL/wglext.h>
47  * So we copy the necessary parts out of it to support the multisampling query
48  */
49 #ifndef WGL_SAMPLES_ARB
50 #define WGL_SAMPLES_ARB                0x2042
51 #endif
52 #ifndef WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB
53 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9
54 #endif
55
56 typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
57
58 #if defined(_WIN32_WCE)
59 #   include <Aygshell.h>
60 #   ifdef FREEGLUT_LIB_PRAGMAS
61 #       pragma comment( lib, "Aygshell.lib" )
62 #   endif
63 #endif /* defined(_WIN32_WCE) */
64
65
66
67 int fgPlatformGlutGet ( GLenum eWhat )
68 {
69     int returnValue ;
70     GLboolean boolValue ;
71
72     int nsamples = 0;
73
74     switch( eWhat )
75     {
76     case GLUT_WINDOW_NUM_SAMPLES:
77       glGetIntegerv(WGL_SAMPLES_ARB, &nsamples);
78       return nsamples;
79
80     /* Handle the OpenGL inquiries */
81     case GLUT_WINDOW_RGBA:
82 #if defined(_WIN32_WCE)
83       boolValue = (GLboolean)0;  /* WinCE doesn't support this feature */
84 #else
85       glGetBooleanv ( GL_RGBA_MODE, &boolValue );
86       returnValue = boolValue ? 1 : 0;
87 #endif
88       return returnValue;
89     case GLUT_WINDOW_DOUBLEBUFFER:
90 #if defined(_WIN32_WCE)
91       boolValue = (GLboolean)0;  /* WinCE doesn't support this feature */
92 #else
93       glGetBooleanv ( GL_DOUBLEBUFFER, &boolValue );
94       returnValue = boolValue ? 1 : 0;
95 #endif
96       return returnValue;
97     case GLUT_WINDOW_STEREO:
98 #if defined(_WIN32_WCE)
99       boolValue = (GLboolean)0;  /* WinCE doesn't support this feature */
100 #else
101       glGetBooleanv ( GL_STEREO, &boolValue );
102       returnValue = boolValue ? 1 : 0;
103 #endif
104       return returnValue;
105
106     case GLUT_WINDOW_RED_SIZE:
107       glGetIntegerv ( GL_RED_BITS, &returnValue );
108       return returnValue;
109     case GLUT_WINDOW_GREEN_SIZE:
110       glGetIntegerv ( GL_GREEN_BITS, &returnValue );
111       return returnValue;
112     case GLUT_WINDOW_BLUE_SIZE:
113       glGetIntegerv ( GL_BLUE_BITS, &returnValue );
114       return returnValue;
115     case GLUT_WINDOW_ALPHA_SIZE:
116       glGetIntegerv ( GL_ALPHA_BITS, &returnValue );
117       return returnValue;
118     case GLUT_WINDOW_ACCUM_RED_SIZE:
119 #if defined(_WIN32_WCE)
120       returnValue = 0;  /* WinCE doesn't support this feature */
121 #else
122       glGetIntegerv ( GL_ACCUM_RED_BITS, &returnValue );
123 #endif
124       return returnValue;
125     case GLUT_WINDOW_ACCUM_GREEN_SIZE:
126 #if defined(_WIN32_WCE)
127       returnValue = 0;  /* WinCE doesn't support this feature */
128 #else
129       glGetIntegerv ( GL_ACCUM_GREEN_BITS, &returnValue );
130 #endif
131       return returnValue;
132     case GLUT_WINDOW_ACCUM_BLUE_SIZE:
133 #if defined(_WIN32_WCE)
134       returnValue = 0;  /* WinCE doesn't support this feature */
135 #else
136       glGetIntegerv ( GL_ACCUM_BLUE_BITS, &returnValue );
137 #endif
138       return returnValue;
139     case GLUT_WINDOW_ACCUM_ALPHA_SIZE:
140 #if defined(_WIN32_WCE)
141       returnValue = 0;  /* WinCE doesn't support this feature */
142 #else
143       glGetIntegerv ( GL_ACCUM_ALPHA_BITS, &returnValue );
144 #endif
145       return returnValue;
146     case GLUT_WINDOW_DEPTH_SIZE:
147       glGetIntegerv ( GL_DEPTH_BITS, &returnValue );
148       return returnValue;
149
150     case GLUT_WINDOW_BUFFER_SIZE:
151     {
152         PIXELFORMATDESCRIPTOR  pfd;
153         HDC hdc = fgStructure.CurrentWindow->Window.pContext.Device;
154         int iPixelFormat = GetPixelFormat( hdc );
155         DescribePixelFormat(hdc, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
156
157         returnValue = pfd.cColorBits;
158         if (pfd.iPixelType==PFD_TYPE_RGBA)
159             returnValue += pfd.cAlphaBits;
160
161         return returnValue;
162     }
163     case GLUT_WINDOW_STENCIL_SIZE:
164       glGetIntegerv ( GL_STENCIL_BITS, &returnValue );
165       return returnValue;
166
167     case GLUT_WINDOW_X:
168     case GLUT_WINDOW_Y:
169     {
170         /*
171          *  NB:
172          *  - When you create a window with position (x,y) and size
173          *    (w,h), the upper left hand corner of the outside of the
174          *    window is at (x,y) and the size of the drawable area is
175          *    (w,h).
176          *  - When you query the size and position of the window--as
177          *    is happening here for Windows--"freeglut" will return
178          *    the size of the drawable area--the (w,h) that you
179          *    specified when you created the window--and the coordinates
180          *    of the upper left hand corner of the drawable area, i.e.
181          *    of the client rect--which is NOT the (x,y) you specified.
182          */
183
184         RECT winRect;
185         POINT topLeft = {0,0};
186
187         freeglut_return_val_if_fail( fgStructure.CurrentWindow != NULL, 0 );
188
189 #if defined(_WIN32_WCE)
190         GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect);
191 #else
192         ClientToScreen(fgStructure.CurrentWindow->Window.Handle, &topLeft);
193
194         if (fgStructure.CurrentWindow->Parent)
195             /* For child window, we should return relative to upper-left
196              * of parent's client area.
197              */
198             ScreenToClient(fgStructure.CurrentWindow->Parent->Window.Handle,&topLeft);
199
200         winRect.left = topLeft.x;
201         winRect.top  = topLeft.y;
202 #endif /* defined(_WIN32_WCE) */
203
204         switch( eWhat )
205         {
206         case GLUT_WINDOW_X:      return winRect.left;
207         case GLUT_WINDOW_Y:      return winRect.top ;
208         }
209     }
210     break;
211
212     case GLUT_WINDOW_WIDTH:
213     case GLUT_WINDOW_HEIGHT:
214     {
215         RECT winRect;
216         freeglut_return_val_if_fail( fgStructure.CurrentWindow != NULL, 0 );
217
218         GetClientRect( fgStructure.CurrentWindow->Window.Handle, &winRect);
219
220         switch( eWhat )
221         {
222         case GLUT_WINDOW_WIDTH:      return winRect.right-winRect.left;
223         case GLUT_WINDOW_HEIGHT:     return winRect.bottom-winRect.top;
224         }
225     }
226     break;
227
228     case GLUT_WINDOW_BORDER_WIDTH :
229     case GLUT_WINDOW_BORDER_HEIGHT :
230 #if defined(_WIN32_WCE)
231         return 0;
232 #else
233         {
234             /* We can't get the border width or header height in the simple way
235              * with some calls to GetSystemMetrics. We'd then have to assume which
236              * elements are present for a given decoration, and such calculations
237              * wouldn't be valid for every version of Windows. The below should be
238              * robust. */
239             int borderWidth, captionHeight;
240             DWORD windowStyle, windowExStyle;
241             RECT clientRect, winRect;
242
243             /* Get style of window, or default style */
244             fghGetStyleFromWindow( fgStructure.CurrentWindow, &windowStyle, &windowExStyle );
245             /* Get client area if we have a current window, else use dummy rect */
246             /* Also get window rect (including non-client area) */
247             if (fgStructure.CurrentWindow && fgStructure.CurrentWindow->Window.Handle)
248             {
249                 fghGetClientArea(&clientRect,fgStructure.CurrentWindow, FALSE);
250                 GetWindowRect(fgStructure.CurrentWindow->Window.Handle,&winRect);
251             }
252             else
253             {
254                 SetRect(&clientRect,0,0,200,200);
255                 CopyRect(&winRect,&clientRect);
256                 fghComputeWindowRectFromClientArea_UseStyle(&winRect,windowStyle,windowExStyle,FALSE);
257             }
258
259             /* Calculate border width by taking width of whole window minus width of client area and divide by two
260              * NB: we assume horizontal and vertical borders have the same size, which should always be the case
261              * unless the user bypassed FreeGLUT and messed with the windowstyle himself.
262              * Once borderwidth is known, account for it when comparing height of window to height of client area.
263              * all other extra pixels are assumed to be atop the window, forming the caption.
264              */
265             borderWidth   = ((winRect.right-winRect.left)-(clientRect.right-clientRect.left))/2;
266             captionHeight = (winRect.bottom-winRect.top)-(clientRect.bottom-clientRect.top)-borderWidth; /* include top border in caption height */
267
268             switch( eWhat )
269             {
270             case GLUT_WINDOW_BORDER_WIDTH:
271                 return borderWidth;
272             case GLUT_WINDOW_BORDER_HEIGHT:
273                 return captionHeight;
274             }
275         }
276 #endif /* defined(_WIN32_WCE) */
277
278     case GLUT_DISPLAY_MODE_POSSIBLE:
279 #if defined(_WIN32_WCE)
280         return 0;
281 #else
282         return fgSetupPixelFormat( fgStructure.CurrentWindow, GL_TRUE,
283                                     PFD_MAIN_PLANE );
284 #endif /* defined(_WIN32_WCE) */
285
286
287     case GLUT_WINDOW_FORMAT_ID:
288 #if !defined(_WIN32_WCE)
289         if( fgStructure.CurrentWindow != NULL )
290             return GetPixelFormat( fgStructure.CurrentWindow->Window.pContext.Device );
291 #endif /* defined(_WIN32_WCE) */
292         return 0;
293
294     case GLUT_WINDOW_SRGB:
295         if( fgStructure.CurrentWindow != NULL ) {
296             static int attr = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
297             static PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB;
298             HDC hdc = fgStructure.CurrentWindow->Window.pContext.Device;
299             int ipixfmt = GetPixelFormat(hdc);
300             int val;
301
302             if(!wglGetPixelFormatAttribivARB) {
303                 if(!(wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribivARB"))) {
304                     return 0;
305                 }
306             }
307             if(wglGetPixelFormatAttribivARB(hdc, ipixfmt, 0, 1, &attr, &val)) {
308                 return val;
309             }
310         }
311         return 0;
312
313     default:
314         fgWarning( "glutGet(): missing enum handle %d", eWhat );
315         break;
316     }
317
318     return -1;
319 }
320
321
322 int fgPlatformGlutDeviceGet ( GLenum eWhat )
323 {
324     switch( eWhat )
325     {
326     case GLUT_HAS_KEYBOARD:
327         /*
328          * Win32 is assumed a keyboard, and this cannot be queried,
329          * except for WindowsCE.
330          */
331 #if defined(_WIN32_CE)
332         return ( GetKeyboardStatus() & KBDI_KEYBOARD_PRESENT ) ? 1 : 0;
333 #   if FREEGLUT_LIB_PRAGMAS
334 #       pragma comment (lib,"Kbdui.lib")
335 #   endif
336
337 #else
338         return 1;
339 #endif
340
341     case GLUT_HAS_MOUSE:
342         /*
343          * MS Windows can be booted without a mouse.
344          */
345         return GetSystemMetrics( SM_MOUSEPRESENT );
346
347     case GLUT_NUM_MOUSE_BUTTONS:
348 #  if defined(_WIN32_WCE)
349         return 1;
350 #  else
351         return GetSystemMetrics( SM_CMOUSEBUTTONS );
352 #  endif
353
354     default:
355         fgWarning( "glutDeviceGet(): missing enum handle %d", eWhat );
356         return -1;
357         break;
358     }
359 }
360
361 /*
362  * This is for querying the number of supported auxiliary or multisample
363  * buffers for a (the current?) display mode.
364  * see http://old.nabble.com/-GLX--glutGetModeValues-to13514723.html#a13514723
365  * Not currently implemented, but we should be able to query the relevant
366  * info using
367  * http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt
368  * (if supported on the executing machine!)
369  */
370 int *fgPlatformGlutGetModeValues(GLenum eWhat, int *size)
371 {
372   *size = 0;
373   return NULL;
374 }