simplified some window rect calculations
[freeglut] / src / mswin / fg_state_mswin.c
1 /*
2  * freeglut_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 );
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 #define WGL_SAMPLES_ARB                0x2042
50
51 #if defined(_WIN32_WCE)
52 #   include <Aygshell.h>
53 #   ifdef FREEGLUT_LIB_PRAGMAS
54 #       pragma comment( lib, "Aygshell.lib" )
55 #   endif
56 #endif /* defined(_WIN32_WCE) */
57
58
59
60 int fgPlatformGlutGet ( GLenum eWhat )
61 {
62     int returnValue ;
63     GLboolean boolValue ;
64
65     int nsamples = 0;
66
67     switch( eWhat )
68     {
69     case GLUT_WINDOW_NUM_SAMPLES:
70       glGetIntegerv(WGL_SAMPLES_ARB, &nsamples);
71       return nsamples;
72
73     /* Handle the OpenGL inquiries */
74     case GLUT_WINDOW_RGBA:
75 #if defined(_WIN32_WCE)
76       boolValue = (GLboolean)0;  /* WinCE doesn't support this feature */
77 #else
78       glGetBooleanv ( GL_RGBA_MODE, &boolValue );
79       returnValue = boolValue ? 1 : 0;
80 #endif
81       return returnValue;
82     case GLUT_WINDOW_DOUBLEBUFFER:
83 #if defined(_WIN32_WCE)
84       boolValue = (GLboolean)0;  /* WinCE doesn't support this feature */
85 #else
86       glGetBooleanv ( GL_DOUBLEBUFFER, &boolValue );
87       returnValue = boolValue ? 1 : 0;
88 #endif
89       return returnValue;
90     case GLUT_WINDOW_STEREO:
91 #if defined(_WIN32_WCE)
92       boolValue = (GLboolean)0;  /* WinCE doesn't support this feature */
93 #else
94       glGetBooleanv ( GL_STEREO, &boolValue );
95       returnValue = boolValue ? 1 : 0;
96 #endif
97       return returnValue;
98
99     case GLUT_WINDOW_RED_SIZE:
100       glGetIntegerv ( GL_RED_BITS, &returnValue );
101       return returnValue;
102     case GLUT_WINDOW_GREEN_SIZE:
103       glGetIntegerv ( GL_GREEN_BITS, &returnValue );
104       return returnValue;
105     case GLUT_WINDOW_BLUE_SIZE:
106       glGetIntegerv ( GL_BLUE_BITS, &returnValue );
107       return returnValue;
108     case GLUT_WINDOW_ALPHA_SIZE:
109       glGetIntegerv ( GL_ALPHA_BITS, &returnValue );
110       return returnValue;
111     case GLUT_WINDOW_ACCUM_RED_SIZE:
112 #if defined(_WIN32_WCE)
113       returnValue = 0;  /* WinCE doesn't support this feature */
114 #else
115       glGetIntegerv ( GL_ACCUM_RED_BITS, &returnValue );
116 #endif
117       return returnValue;
118     case GLUT_WINDOW_ACCUM_GREEN_SIZE:
119 #if defined(_WIN32_WCE)
120       returnValue = 0;  /* WinCE doesn't support this feature */
121 #else
122       glGetIntegerv ( GL_ACCUM_GREEN_BITS, &returnValue );
123 #endif
124       return returnValue;
125     case GLUT_WINDOW_ACCUM_BLUE_SIZE:
126 #if defined(_WIN32_WCE)
127       returnValue = 0;  /* WinCE doesn't support this feature */
128 #else
129       glGetIntegerv ( GL_ACCUM_BLUE_BITS, &returnValue );
130 #endif
131       return returnValue;
132     case GLUT_WINDOW_ACCUM_ALPHA_SIZE:
133 #if defined(_WIN32_WCE)
134       returnValue = 0;  /* WinCE doesn't support this feature */
135 #else
136       glGetIntegerv ( GL_ACCUM_ALPHA_BITS, &returnValue );
137 #endif
138       return returnValue;
139     case GLUT_WINDOW_DEPTH_SIZE:
140       glGetIntegerv ( GL_DEPTH_BITS, &returnValue );
141       return returnValue;
142
143     case GLUT_WINDOW_BUFFER_SIZE:
144     {
145         PIXELFORMATDESCRIPTOR  pfd;
146         HDC hdc = fgStructure.CurrentWindow->Window.pContext.Device;
147         int iPixelFormat = GetPixelFormat( hdc );
148         DescribePixelFormat(hdc, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
149         
150         returnValue = pfd.cColorBits;
151         if (pfd.iPixelType==PFD_TYPE_RGBA)
152             returnValue += pfd.cAlphaBits;
153
154         return returnValue;
155     }
156     case GLUT_WINDOW_STENCIL_SIZE:
157       glGetIntegerv ( GL_STENCIL_BITS, &returnValue );
158       return returnValue;
159
160     case GLUT_WINDOW_X:
161     case GLUT_WINDOW_Y:
162     {
163         /*
164          *  There is considerable confusion about the "right thing to
165          *  do" concerning window  size and position.  GLUT itself is
166          *  not consistent between Windows and UNIX/X11; since
167          *  platform independence is a virtue for "freeglut", we
168          *  decided to break with GLUT's behaviour.
169          *
170          *  Under UNIX/X11, it is apparently not possible to get the
171          *  window border sizes in order to subtract them off the
172          *  window's initial position until some time after the window
173          *  has been created.  Therefore we decided on the following
174          *  behaviour, both under Windows and under UNIX/X11:
175          *  - When you create a window with position (x,y) and size
176          *    (w,h), the upper left hand corner of the outside of the
177          *    window is at (x,y) and the size of the drawable area is
178          *    (w,h).
179          *  - When you query the size and position of the window--as
180          *    is happening here for Windows--"freeglut" will return
181          *    the size of the drawable area--the (w,h) that you
182          *    specified when you created the window--and the coordinates
183          *    of the upper left hand corner of the drawable area, i.e.
184          *    of the client rect--which is NOT the (x,y) you specified.
185          */
186
187         RECT winRect;
188         POINT topLeft = {0,0};
189
190         freeglut_return_val_if_fail( fgStructure.CurrentWindow != NULL, 0 );
191
192 #if defined(_WIN32_WCE)
193         GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect);
194 #else
195         ClientToScreen(fgStructure.CurrentWindow->Window.Handle, &topLeft);
196         
197         if (fgStructure.CurrentWindow->Parent)
198             /* For child window, we should return relative to upper-left
199              * of parent's client area.
200              */
201             ScreenToClient(fgStructure.CurrentWindow->Parent->Window.Handle,&topLeft);
202
203         winRect.left = topLeft.x;
204         winRect.top  = topLeft.y;
205 #endif /* defined(_WIN32_WCE) */
206
207         switch( eWhat )
208         {
209         case GLUT_WINDOW_X:      return winRect.left;
210         case GLUT_WINDOW_Y:      return winRect.top ;
211         }
212     }
213     break;
214
215     case GLUT_WINDOW_WIDTH:
216         freeglut_return_val_if_fail( fgStructure.CurrentWindow != NULL, 0 );
217         return fgStructure.CurrentWindow->State.Width;
218     case GLUT_WINDOW_HEIGHT:
219         freeglut_return_val_if_fail( fgStructure.CurrentWindow != NULL, 0 );
220         return fgStructure.CurrentWindow->State.Height;
221
222     case GLUT_WINDOW_BORDER_WIDTH :
223     case GLUT_WINDOW_BORDER_HEIGHT :
224 #if defined(_WIN32_WCE)
225         return 0;
226 #else
227         {
228             /* We can't get the border width or header height in the simple way
229              * with some calls to GetSystemMetrics. We'd then have to assume which
230              * elements are present for a given decoration, and such calculations
231              * wouldn't be valid for every version of Windows. The below should be
232              * robust. */
233             int borderWidth, captionHeight;
234             DWORD windowStyle, windowExStyle;
235             RECT clientRect, winRect;
236
237             /* Get style of window, or default style */
238             fghGetStyleFromWindow( fgStructure.CurrentWindow, &windowStyle, &windowExStyle );
239             /* Get client area if we have a current window, else use dummy rect */
240             /* Also get window rect (including non-client area) */
241             if (fgStructure.CurrentWindow && fgStructure.CurrentWindow->Window.Handle)
242             {
243                 fghGetClientArea(&clientRect,fgStructure.CurrentWindow);
244                 GetWindowRect(fgStructure.CurrentWindow->Window.Handle,&winRect);
245             }
246             else
247             {
248                 SetRect(&clientRect,0,0,200,200);
249                 CopyRect(&winRect,&clientRect);
250                 fghComputeWindowRectFromClientArea_UseStyle(&winRect,windowStyle,windowExStyle,FALSE);
251             }
252
253             /* Calculate border width by taking width of whole window minus width of client area and divide by two
254              * NB: we assume horizontal and vertical borders have the same size, which should always be the case
255              * unless the user bypassed FreeGLUT and messed with the windowstyle himself.
256              * Once borderwidth is known, account for it when comparing height of window to height of client area.
257              * all other extra pixels are assumed to be atop the window, forming the caption.
258              */
259             borderWidth   = ((winRect.right-winRect.left)-(clientRect.right-clientRect.left))/2;
260             captionHeight = (winRect.bottom-winRect.top)-(clientRect.bottom-clientRect.top)-borderWidth*2;
261             
262             switch( eWhat )
263             {
264             case GLUT_WINDOW_BORDER_WIDTH:
265                 return borderWidth;
266             case GLUT_WINDOW_BORDER_HEIGHT:
267                 return captionHeight;
268             }
269         }
270 #endif /* defined(_WIN32_WCE) */
271
272     case GLUT_DISPLAY_MODE_POSSIBLE:
273 #if defined(_WIN32_WCE)
274         return 0;
275 #else
276         return fgSetupPixelFormat( fgStructure.CurrentWindow, GL_TRUE,
277                                     PFD_MAIN_PLANE );
278 #endif /* defined(_WIN32_WCE) */
279
280
281     case GLUT_WINDOW_FORMAT_ID:
282 #if !defined(_WIN32_WCE)
283         if( fgStructure.CurrentWindow != NULL )
284             return GetPixelFormat( fgStructure.CurrentWindow->Window.pContext.Device );
285 #endif /* defined(_WIN32_WCE) */
286         return 0;
287
288     default:
289         fgWarning( "glutGet(): missing enum handle %d", eWhat );
290         break;
291     }
292
293         return -1;
294 }
295
296
297 int fgPlatformGlutDeviceGet ( GLenum eWhat )
298 {
299     switch( eWhat )
300     {
301     case GLUT_HAS_KEYBOARD:
302         /*
303          * Win32 is assumed a keyboard, and this cannot be queried,
304          * except for WindowsCE.
305          */
306 #if defined(_WIN32_CE)
307         return ( GetKeyboardStatus() & KBDI_KEYBOARD_PRESENT ) ? 1 : 0;
308 #   if FREEGLUT_LIB_PRAGMAS
309 #       pragma comment (lib,"Kbdui.lib")
310 #   endif
311
312 #else
313         return 1;
314 #endif
315
316     case GLUT_HAS_MOUSE:
317         /*
318          * MS Windows can be booted without a mouse.
319          */
320         return GetSystemMetrics( SM_MOUSEPRESENT );
321
322     case GLUT_NUM_MOUSE_BUTTONS:
323 #  if defined(_WIN32_WCE)
324         return 1;
325 #  else
326         return GetSystemMetrics( SM_CMOUSEBUTTONS );
327 #  endif
328
329     default:
330         fgWarning( "glutDeviceGet(): missing enum handle %d", eWhat );
331         break;
332     }
333
334     /* And now -- the failure. */
335     return -1;
336 }
337
338 /*
339  * This is for querying the number of supported auxiliary or multisample
340  * buffers for a (the current?) display mode.
341  * see http://old.nabble.com/-GLX--glutGetModeValues-to13514723.html#a13514723
342  * Not currently implemented, but we should be able to query the relevant
343  * info using
344  * http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt
345  * (if supported on the executing machine!)
346  */
347 int *fgPlatformGlutGetModeValues(GLenum eWhat, int *size)
348 {
349   *size = 0;
350   return NULL;
351 }