user32: Always clip the button painting to the client rectangle

Dmitry Timoshkov dmitry at codeweavers.com
Thu Dec 13 09:58:45 CST 2007


Hello,

this patch should fix the problem reported in the bug 7569.

I did many attempts to figure out how Windows draws the button control,
and whether it actually clips the painting. Testing for a clipping region
in WM_ERASEBKGND or WM_CTLCOLORSTATIC/WM_CTLCOLORBTN handlers of a hook proc
didn't reveal anything, and as a last resort I ran a test app under strace.exe
which shows that Windows calls NtGdiIntersectClipRect *after* those messages
are sent, and right before actual painting. An strace log also shows that
Windows doesn't do any attempts to restore an original clipping region
before the call to NtUserEndPaint, probably EndPaint does that.

An owner drawn button:

2806 536 248 NtUserBeginPaint ... ) == 0xa9010c85
2811 536 248 NtUserGetControlBrush (0x1b0492, -1459549051, 309, ... ) == 0x110005d
2812 536 248 NtGdiIntersectClipRect (-1459549051, 0, 0, 50, 14, ... ) == 0x3
2813 536 248 NtUserValidateHandleSecure (65556, ... ) == 0x1
2814 536 248 NtUserMessageCall (0x10014, WM_DRAWITEM, 0x0, 0x12fd08, 0, 688, 0, ... ) == 0x0
2815 536 248 NtUserEndPaint (0x1b0492, 1244592, ... ) == 0x1

Other button styles:

2797 532 1176 NtUserBeginPaint (0xb049a, 1244592, ... ) == 0x3e010f5f
2798 532 1176 NtUserGetControlBrush (0xb049a, 1040256863, 309, ... ) == 0x110005d
2799 532 1176 NtGdiIntersectClipRect (1040256863, 0, 0, 50, 14, ... ) == 0x3
2800 532 1176 NtGdiIntersectClipRect (1040256863, 2, 2, 48, 12, ... ) == 0x3
2801 532 1176 NtUserEndPaint (0xb049a, 1244592, ... ) == 0x1

Changelog:
    user32: Always clip the button painting to the client rectangle.
---
 dlls/user32/button.c |   32 ++++++++++++++++++--------------
 1 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/dlls/user32/button.c b/dlls/user32/button.c
index 6e21bbc..d6ee30c 100644
--- a/dlls/user32/button.c
+++ b/dlls/user32/button.c
@@ -217,6 +217,15 @@ static inline WCHAR *get_button_text( HWND hwnd )
     return buffer;
 }
 
+static void setup_clipping( HWND hwnd, HDC hdc )
+{
+    RECT rc;
+
+    GetClientRect( hwnd, &rc );
+    DPtoLP( hdc, (POINT *)&rc, 2 );
+    IntersectClipRect( hdc, rc.left, rc.top, rc.right, rc.bottom );
+}
+
 /***********************************************************************
  *           ButtonWndProc_common
  */
@@ -798,6 +807,9 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
     parent = GetParent(hwnd);
     if (!parent) parent = hwnd;
     SendMessageW( parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)hwnd );
+
+    setup_clipping( hwnd, hDC );
+
     hOldPen = (HPEN)SelectObject(hDC, SYSCOLOR_GetPen(COLOR_WINDOWFRAME));
     hOldBrush =(HBRUSH)SelectObject(hDC,GetSysColorBrush(COLOR_BTNFACE));
     oldBkMode = SetBkMode(hDC, TRANSPARENT);
@@ -970,7 +982,7 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action )
     if (dtFlags == (UINT)-1L) /* Noting to draw */
 	return;
 
-    IntersectClipRect(hDC, client.left, client.top, client.right, client.bottom);
+    setup_clipping( hwnd, hDC );
 
     if (action == ODA_DRAWENTIRE)
 	BUTTON_DrawLabel(hwnd, hDC, dtFlags, &rtext);
@@ -1046,6 +1058,8 @@ static void GB_Paint( HWND hwnd, HDC hDC, UINT action )
     if (dtFlags == (UINT)-1L)
        return;
 
+    setup_clipping( hwnd, hDC );
+
     /* Because buttons have CS_PARENTDC class style, there is a chance
      * that label will be drawn out of client rect.
      * But Windows doesn't clip label's rect, so do I.
@@ -1100,8 +1114,6 @@ static void OB_Paint( HWND hwnd, HDC hDC, UINT action )
 {
     LONG state = get_button_state( hwnd );
     DRAWITEMSTRUCT dis;
-    HRGN clipRegion;
-    RECT clipRect;
     LONG_PTR id = GetWindowLongPtrW( hwnd, GWLP_ID );
     HWND parent;
     HFONT hFont, hPrevFont = 0;
@@ -1118,21 +1130,13 @@ static void OB_Paint( HWND hwnd, HDC hDC, UINT action )
     dis.itemData   = 0;
     GetClientRect( hwnd, &dis.rcItem );
 
-    clipRegion = CreateRectRgnIndirect(&dis.rcItem);
-    if (GetClipRgn(hDC, clipRegion) != 1)
-    {
-	DeleteObject(clipRegion);
-	clipRegion=NULL;
-    }
-    clipRect = dis.rcItem;
-    DPtoLP(hDC, (LPPOINT) &clipRect, 2);
-    IntersectClipRect(hDC, clipRect.left,  clipRect.top, clipRect.right, clipRect.bottom);
-
     if ((hFont = get_button_font( hwnd ))) hPrevFont = SelectObject( hDC, hFont );
     parent = GetParent(hwnd);
     if (!parent) parent = hwnd;
     SendMessageW( parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)hwnd );
+
+    setup_clipping( hwnd, hDC );
+
     SendMessageW( GetParent(hwnd), WM_DRAWITEM, id, (LPARAM)&dis );
     if (hPrevFont) SelectObject(hDC, hPrevFont);
-    SelectClipRgn(hDC, clipRegion);
 }
-- 
1.5.3.7






More information about the wine-patches mailing list