reimplemented the client-area/window-area conversion code. It should now
authorDiederick Niehorster <dcnieho@gmail.com>
Fri, 16 Nov 2012 11:02:06 +0000 (11:02 +0000)
committerDiederick Niehorster <dcnieho@gmail.com>
Fri, 16 Nov 2012 11:02:06 +0000 (11:02 +0000)
be robust across Windows and Visual Studio versions. Bugs in window
size with VS2012 fixed!

git-svn-id: svn+ssh://svn.code.sf.net/p/freeglut/code/trunk/freeglut/freeglut@1394 7f0cb862-5218-0410-a997-914c9d46530a

progs/demos/Resizer/Resizer.cpp
src/mswin/fg_main_mswin.c
src/mswin/fg_menu_mswin.c
src/mswin/fg_state_mswin.c
src/mswin/fg_window_mswin.c

index 76d55f7..bd19ffe 100644 (file)
@@ -220,13 +220,19 @@ void Redisplay(void)
 \r
 int main(int argc, char* argv[])\r
 {\r
+    int border, caption;\r
     glutInit( &argc, argv );\r
     glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE /*| GLUT_BORDERLESS*/); // do try as well with GLUT_BORDERLESS and GLUT_CAPTIONLESS\r
     glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE,GLUT_ACTION_GLUTMAINLOOP_RETURNS);\r
-\r
-    /* The window position you request is the outer top-left of the window,\r
-     * the client area is at a different position if the window has borders\r
-     * and/or a title bar.\r
+    \r
+    /* Get border and caption size of default window style */\r
+    border  = glutGet(GLUT_WINDOW_BORDER_WIDTH);\r
+    caption = glutGet(GLUT_WINDOW_HEADER_HEIGHT);\r
+    printf("default window style border: %dpx, caption: %dpx\n",border,caption);\r
+\r
+    /* NB: The window position you request is the outer top-left of the\r
+     * window, the client area is at a different position if the window has\r
+     * borders and/or a title bar.\r
      */\r
     glutInitWindowPosition(150,250);\r
     glutInitWindowSize(200,200);\r
index d778d67..a9f8552 100644 (file)
@@ -63,8 +63,8 @@ struct GXKeyList gxKeyList;
  * and the window rect from the client area given the style of the window
  * (or a valid window pointer from which the style can be queried).
  */
-extern void fghComputeWindowRectFromClientArea_QueryWindow( const SFG_Window *window, RECT *clientRect, BOOL posIsOutside );
-extern RECT fghGetClientArea                              ( const SFG_Window *window,                   BOOL wantPosOutside );
+extern void fghComputeWindowRectFromClientArea_QueryWindow( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside );
+extern void fghGetClientArea                              ( RECT *clientRect, const SFG_Window *window, BOOL wantPosOutside );
 
 
 void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height )
@@ -86,7 +86,7 @@ void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height )
 
     if (window->Parent == NULL)
         /* get the window rect from this to feed to SetWindowPos, correct for window decorations */
-        fghComputeWindowRectFromClientArea_QueryWindow(window,&windowRect,TRUE);
+        fghComputeWindowRectFromClientArea_QueryWindow(&windowRect,window,TRUE);
     else
     {
         /* correct rect for position client area of parent window
@@ -96,11 +96,8 @@ void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height )
          * for them.
          */
         RECT parentRect;
-        parentRect = fghGetClientArea( window->Parent, FALSE );
-        windowRect.left   -= parentRect.left;
-        windowRect.right  -= parentRect.left;
-        windowRect.top    -= parentRect.top;
-        windowRect.bottom -= parentRect.top;
+        fghGetClientArea( &parentRect, window->Parent, FALSE );
+        OffsetRect(&windowRect,-parentRect.left,-parentRect.top);
     }
     
     /* Do the actual resizing */
index 0d6a599..3d83693 100644 (file)
@@ -29,7 +29,7 @@
 #include <GL/freeglut.h>
 #include "../fg_internal.h"
 
-extern RECT fghGetClientArea( const SFG_Window *window, BOOL wantPosOutside );
+extern void fghGetClientArea( RECT *clientRect, const SFG_Window *window, BOOL wantPosOutside );
 
 
 GLvoid fgPlatformGetGameModeVMaxExtent( SFG_Window* window, int* x, int* y )
@@ -69,11 +69,12 @@ void fgPlatformCheckMenuDeactivate()
             else
             {
                 /* Check if focus lost because non-client area of
-                * window was pressed (pressing on client area is
-                * handled in fgCheckActiveMenu)
-                */
+                 * window was pressed (pressing on client area is
+                 * handled in fgCheckActiveMenu)
+                 */
                 POINT mouse_pos;
-                RECT clientArea = fghGetClientArea(menu->ParentWindow, GL_FALSE);
+                RECT clientArea;
+                fghGetClientArea(&clientArea,menu->ParentWindow, GL_FALSE);
                 GetCursorPos(&mouse_pos);
                 if ( !PtInRect( &clientArea, mouse_pos ) )
                     fgDeactivateMenu(menu->ParentWindow);
index 91256a3..659ceca 100644 (file)
@@ -37,8 +37,9 @@ extern GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
  * and the window rect from the client area given the style of the window
  * (or a valid window pointer from which the style can be queried).
  */
-extern RECT fghGetClientArea( const SFG_Window *window, BOOL wantPosOutside );
-extern void fghGetBorderWidth(const DWORD windowStyle, int* xBorderWidth, int* yBorderWidth);
+extern void fghGetClientArea( RECT *clientRect, const SFG_Window *window, BOOL wantPosOutside );
+extern void fghGetStyleFromWindow( const SFG_Window *window, DWORD *windowStyle, DWORD *windowExStyle );
+extern void fghComputeWindowRectFromClientArea_UseStyle( RECT *clientRect, const DWORD windowStyle, const DWORD windowExStyle, BOOL posIsOutside );
 
 
 /* The following include file is available from SGI but is not standard:
@@ -165,7 +166,7 @@ int fgPlatformGlutGet ( GLenum eWhat )
          *  behaviour, both under Windows and under UNIX/X11:
          *  - When you create a window with position (x,y) and size
          *    (w,h), the upper left hand corner of the outside of the
-         *    window is at (x,y) and the size of the drawable area  is
+         *    window is at (x,y) and the size of the drawable area is
          *    (w,h).
          *  - When you query the size and position of the window--as
          *    is happening here for Windows--"freeglut" will return
@@ -182,7 +183,7 @@ int fgPlatformGlutGet ( GLenum eWhat )
 #if defined(_WIN32_WCE)
         GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect );
 #else
-        winRect = fghGetClientArea(fgStructure.CurrentWindow, FALSE);
+        fghGetClientArea(&winRect,fgStructure.CurrentWindow, FALSE);
         if (fgStructure.CurrentWindow->Parent && (eWhat==GLUT_WINDOW_X || eWhat==GLUT_WINDOW_Y))
         {
             /* For child window, we should return relative to upper-left
@@ -214,25 +215,45 @@ int fgPlatformGlutGet ( GLenum eWhat )
         return 0;
 #else
         {
-            DWORD windowStyle;
-
+            /* We can't get the border width or header height in the simple way
+             * with some calls to GetSystemMetrics. We'd then have to assume which
+             * elements are present for a given decoration, and such calculations
+             * wouldn't be valid for every version of Windows. The below should be
+             * robust. */
+            int borderWidth, captionHeight;
+            DWORD windowStyle, windowExStyle;
+            RECT clientRect, winRect;
+
+            /* Get style of window, or default style */
+            fghGetStyleFromWindow( fgStructure.CurrentWindow, &windowStyle, &windowExStyle );
+            /* Get client area if any window */
             if (fgStructure.CurrentWindow && fgStructure.CurrentWindow->Window.Handle)
-                windowStyle = GetWindowLong(fgStructure.CurrentWindow->Window.Handle, GWL_STYLE);
+                fghGetClientArea(&clientRect,fgStructure.CurrentWindow,FALSE);
             else
-                /* If no window, return sizes for a default window with title bar and border */
-                windowStyle = WS_OVERLAPPEDWINDOW;
+                SetRect(&clientRect,0,0,200,200);
+
+            /* Compute window rect (including non-client area) */
+            CopyRect(&winRect,&clientRect);
+            fghComputeWindowRectFromClientArea_UseStyle(&winRect,windowStyle,windowExStyle,FALSE);
+
+            /* Calculate border width by taking width of whole window minus width of client area and divide by two
+             * NB: we assume horizontal and vertical borders have the same size, which should always be the case
+             * unless the user bypassed FreeGLUT and messed with the windowstyle himself.
+             * Once borderwidth is known, account for it when comparing height of window to height of client area.
+             * all other extra pixels are assumed to be atop the window, forming the caption.
+             */
+            borderWidth   = ((winRect.right-winRect.left)-(clientRect.right-clientRect.left))/2;
+            captionHeight = (winRect.bottom-winRect.top)-(clientRect.bottom-clientRect.top)-borderWidth*2;
             
             switch( eWhat )
             {
             case GLUT_WINDOW_BORDER_WIDTH:
                 {
-                    int xBorderWidth, yBorderWidth;
-                    fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth);
-                    return xBorderWidth;
+                    return borderWidth;
                 }
             case GLUT_WINDOW_HEADER_HEIGHT:
                 /* 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... */
-                return (windowStyle & WS_MAXIMIZEBOX)? GetSystemMetrics( SM_CYCAPTION ) : 0;
+                return captionHeight;
             }
         }
 #endif /* defined(_WIN32_WCE) */
index 7aef7a7..7720929 100644 (file)
@@ -371,29 +371,26 @@ void fgPlatformSetWindow ( SFG_Window *window )
 }
 
 
-/* Returns the width of the window borders based on the window's style.
-*/
-void fghGetBorderWidth(const DWORD windowStyle, int* xBorderWidth, int* yBorderWidth)
+/* Get window style and extended window style of a FreeGLUT window
+ * If the window pointer or the window handle is NULL, a fully
+ * decorated window (caption and border) is assumed.
+ */
+void fghGetStyleFromWindow( const SFG_Window *window, DWORD *windowStyle, DWORD *windowExStyle )
 {
-    if (windowStyle & WS_THICKFRAME)
-    {
-        *xBorderWidth = GetSystemMetrics(SM_CXSIZEFRAME);
-        *yBorderWidth = GetSystemMetrics(SM_CYSIZEFRAME);
-    }
-    else if (windowStyle & WS_DLGFRAME)
+    if (window && window->Window.Handle)
     {
-        *xBorderWidth = GetSystemMetrics(SM_CXFIXEDFRAME);
-        *yBorderWidth = GetSystemMetrics(SM_CYFIXEDFRAME);
+        *windowStyle   = GetWindowLong(window->Window.Handle, GWL_STYLE);
+        *windowExStyle = GetWindowLong(window->Window.Handle, GWL_EXSTYLE);
     }
     else
     {
-        *xBorderWidth = 0;
-        *yBorderWidth = 0;
+        /* WindowExStyle==0 is fine/default, exStyle is currently only used for menu windows */
+        *windowStyle   = WS_OVERLAPPEDWINDOW;
+        *windowExStyle = 0;
     }
 }
 
 
-
 /* Computes position of corners of window Rect (outer position including
  * decorations) based on the provided client rect and based on the style
  * of the window in question.
@@ -403,35 +400,25 @@ void fghGetBorderWidth(const DWORD windowStyle, int* xBorderWidth, int* yBorderW
  * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
  * area.
  */
-void fghComputeWindowRectFromClientArea_UseStyle( const DWORD windowStyle, RECT *clientRect, BOOL posIsOutside )
+void fghComputeWindowRectFromClientArea_UseStyle( RECT *clientRect, const DWORD windowStyle, const DWORD windowExStyle, BOOL posIsOutside )
 {
-    int xBorderWidth = 0, yBorderWidth = 0;
+    RECT windowRect   = {0,0,0,0};
+    CopyRect(&windowRect,clientRect);
 
-    /* If window has title bar, correct rect for it */
-    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... */
-    {
-        if (posIsOutside)
-            clientRect->bottom += GetSystemMetrics( SM_CYCAPTION );
-        else
-            clientRect->top -= GetSystemMetrics( SM_CYCAPTION );
-    }
+    /* Get rect including non-client area */
+    AdjustWindowRectEx(&windowRect,windowStyle,FALSE,windowExStyle);
 
-    /* get width of window's borders (frame), correct rect for it.
-     * Note, borders can be of zero width if style does not specify borders
-     */
-    fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth);
+    /* Move window right and down by non-client area extent on left and top, if wanted */
     if (posIsOutside)
     {
-        clientRect->right  += xBorderWidth * 2;
-        clientRect->bottom += yBorderWidth * 2;
-    }
-    else
-    {
-        clientRect->left   -= xBorderWidth;
-        clientRect->right  += xBorderWidth;
-        clientRect->top    -= yBorderWidth;
-        clientRect->bottom += yBorderWidth;
+        windowRect.right   += clientRect->left-windowRect.left;
+        windowRect.bottom  += clientRect->top -windowRect.top;
+        windowRect.left     = clientRect->left;
+        windowRect.top      = clientRect->top;
     }
+    
+    /* done, copy windowRect to output */
+    CopyRect(clientRect,&windowRect);
 }
 
 /* Computes position of corners of window Rect (outer position including
@@ -444,68 +431,17 @@ void fghComputeWindowRectFromClientArea_UseStyle( const DWORD windowStyle, RECT
  * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
  * area.
 */
-void fghComputeWindowRectFromClientArea_QueryWindow( const SFG_Window *window, RECT *clientRect, BOOL posIsOutside )
+void fghComputeWindowRectFromClientArea_QueryWindow( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside )
 {
-    DWORD windowStyle = 0;
-
-    if (window && window->Window.Handle)
-        windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE);
-    else
-        windowStyle = WS_OVERLAPPEDWINDOW;
+    DWORD windowStyle = 0, windowExStyle = 0;
+    fghGetStyleFromWindow(window,&windowStyle,&windowExStyle);
 
-    fghComputeWindowRectFromClientArea_UseStyle(windowStyle, clientRect, posIsOutside);
+    fghComputeWindowRectFromClientArea_UseStyle(clientRect, windowStyle, windowExStyle, posIsOutside);
 }
 
-/* Computes position of corners of client area (drawable area) of a window
- * based on the provided window Rect (outer position including decorations)
- * and based on the style of the window in question. If the window pointer
- * or the window handle is NULL, a fully decorated window (caption and
- * border) is assumed.
- * Furthermore, if wantPosOutside is set to true, the output client Rect
- * will follow freeGLUT's window specification convention in which the
- * top-left corner is at the outside of the window, the size
- * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
- * area.
- */
-void fghComputeClientAreaFromWindowRect( const SFG_Window *window, RECT *windowRect, BOOL wantPosOutside )
-{
-    DWORD windowStyle = 0;
-    int xBorderWidth = 0, yBorderWidth = 0;
-
-    if (window && window->Window.Handle)
-        windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE);
-    else
-        windowStyle = WS_OVERLAPPEDWINDOW;
-
-    /* If window has title bar, correct rect for it */
-    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... */
-    {
-        if (wantPosOutside)
-            windowRect->bottom -= GetSystemMetrics( SM_CYCAPTION );
-        else
-            windowRect->top    += GetSystemMetrics( SM_CYCAPTION );
-    }
-
-    /* get width of window's borders (frame), correct rect for it.
-     * Note, borders can be of zero width if style does not specify borders
-     */
-    fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth);
-    if (wantPosOutside)
-    {
-        windowRect->right  -= xBorderWidth * 2;
-        windowRect->bottom -= yBorderWidth * 2;
-    }
-    else
-    {
-        windowRect->left   += xBorderWidth;
-        windowRect->right  -= xBorderWidth;
-        windowRect->top    += yBorderWidth;
-        windowRect->bottom -= yBorderWidth;
-    }
-}
 
 /* Gets the rect describing the client area (drawable area) of the
- * specified window.
+ * specified window. Output is position of corners of client area (drawable area) on the screen.
  * Returns an empty rect if window pointer or window handle is NULL.
  * If wantPosOutside is set to true, the output client Rect
  * will follow freeGLUT's window specification convention in which the
@@ -513,24 +449,38 @@ void fghComputeClientAreaFromWindowRect( const SFG_Window *window, RECT *windowR
  * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable
  * area.
  */
-RECT fghGetClientArea( const SFG_Window *window, BOOL wantPosOutside )
+void fghGetClientArea( RECT *clientRect, const SFG_Window *window, BOOL wantPosOutside )
 {
-    RECT windowRect = {0,0,0,0};
+    POINT topLeftClient = {0,0};
+    POINT topLeftWindow = {0,0};
 
-    freeglut_return_val_if_fail((window && window->Window.Handle),windowRect);
+    freeglut_return_if_fail((window && window->Window.Handle));
     
     /*
      * call GetWindowRect()
      * (this returns the pixel coordinates of the outside of the window)
-     * cannot use GetClientRect as it seems to return a rect relative to
+     * cannot use GetClientRect as it returns a rect relative to
      * the top-left point of the client area (.top and .left are thus always 0)
+     * and is thus only useful for querying the size of the client area, not
+     * its position.
      */
-    GetWindowRect( window->Window.Handle, &windowRect );
-
-    /* Then correct the results */
-    fghComputeClientAreaFromWindowRect(window, &windowRect, wantPosOutside);
-
-    return windowRect;
+    GetWindowRect( window->Window.Handle, clientRect );
+    topLeftWindow.x = clientRect->top;
+    topLeftWindow.y = clientRect->left;
+    
+    /* Get size of client rect */
+    GetClientRect(window->Window.Handle, clientRect);
+    /* Get position of top-left of client area on the screen */
+    ClientToScreen(window->Window.Handle,&topLeftClient);
+    /* Add top-left offset */
+    OffsetRect(clientRect,topLeftClient.x,topLeftClient.y);
+
+    /* replace top and left with top and left of window, if wanted */
+    if (wantPosOutside)
+    {
+        clientRect->left = topLeftWindow.x;
+        clientRect->top  = topLeftWindow.y;
+    }
 }
 
 #if(WINVER >= 0x500)
@@ -724,8 +674,9 @@ void fgPlatformOpenWindow( SFG_Window* window, const char* title,
         windowRect.right    = x+w;
         windowRect.bottom   = y+h;
 
-        fghComputeWindowRectFromClientArea_UseStyle(flags,&windowRect,TRUE);
+        fghComputeWindowRectFromClientArea_UseStyle(&windowRect,flags,exFlags,TRUE);
 
+        /* NB: w and h are now width and height of window including non-client area! */
         w = windowRect.right - windowRect.left;
         h = windowRect.bottom- windowRect.top;
     }