[User32]
[reactos.git] / reactos / dll / win32 / user32 / controls / button.c
index fee9536..8b4003b 100644 (file)
 #include <user32.h>
 
 #include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(button);
 
 /* GetWindowLong offsets for window extra information */
 #define STATE_GWL_OFFSET  0
 #define HFONT_GWL_OFFSET  (sizeof(LONG))
 #define HIMAGE_GWL_OFFSET (HFONT_GWL_OFFSET+sizeof(HFONT))
-#define NB_EXTRA_BYTES    (HIMAGE_GWL_OFFSET+sizeof(HANDLE))
+#define UISTATE_GWL_OFFSET (HIMAGE_GWL_OFFSET+sizeof(HFONT))
+#define NB_EXTRA_BYTES    (UISTATE_GWL_OFFSET+sizeof(LONG))
 
   /* Button state values */
 #define BUTTON_UNCHECKED       0x00
@@ -100,8 +102,6 @@ static void GB_Paint( HWND hwnd, HDC hDC, UINT action );
 static void UB_Paint( HWND hwnd, HDC hDC, UINT action );
 static void OB_Paint( HWND hwnd, HDC hDC, UINT action );
 static void BUTTON_CheckAutoRadioButton( HWND hwnd );
-static LRESULT WINAPI ButtonWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
-static LRESULT WINAPI ButtonWndProcW( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
 
 #define MAX_BTN_TYPE  12
 
@@ -146,36 +146,37 @@ static WORD checkBoxWidth = 0, checkBoxHeight = 0;
 /*********************************************************************
  * button class descriptor
  */
+static const WCHAR buttonW[] = {'B','u','t','t','o','n',0};
 const struct builtin_class_descr BUTTON_builtin_class =
 {
-#ifdef __REACTOS__
-    L"Button",           /* name */
-    CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC, /* style  */
-    ButtonWndProcW,      /* procW */
-    ButtonWndProcA,      /* procA */
-    NB_EXTRA_BYTES,      /* extra */
-    (LPWSTR)IDC_ARROW,   /* cursor */
-    0                    /* brush */
-#else
-    "Button",            /* name */
+    buttonW,             /* name */
     CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC, /* style  */
     ButtonWndProcA,      /* procA */
     ButtonWndProcW,      /* procW */
     NB_EXTRA_BYTES,      /* extra */
     IDC_ARROW,           /* cursor */
     0                    /* brush */
-#endif
 };
 
 
-__inline static LONG get_button_state( HWND hwnd )
+static inline LONG get_button_state( HWND hwnd )
 {
-    return GetWindowLongW( hwnd, STATE_GWL_OFFSET );
+    return GetWindowLongPtrW( hwnd, STATE_GWL_OFFSET );
 }
 
-__inline static void set_button_state( HWND hwnd, LONG state )
+static inline void set_button_state( HWND hwnd, LONG state )
 {
-    SetWindowLongW( hwnd, STATE_GWL_OFFSET, state );
+    SetWindowLongPtrW( hwnd, STATE_GWL_OFFSET, state );
+}
+
+static __inline void set_ui_state( HWND hwnd, LONG flags )
+{
+    SetWindowLongPtrW( hwnd, UISTATE_GWL_OFFSET, flags );
+}
+
+static __inline LONG get_ui_state( HWND hwnd )
+{
+    return GetWindowLongPtrW( hwnd, UISTATE_GWL_OFFSET );
 }
 
 __inline static HFONT get_button_font( HWND hwnd )
@@ -183,18 +184,18 @@ __inline static HFONT get_button_font( HWND hwnd )
     return (HFONT)GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET );
 }
 
-__inline static void set_button_font( HWND hwnd, HFONT font )
+static inline void set_button_font( HWND hwnd, HFONT font )
 {
     SetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET, (LONG_PTR)font );
 }
 
-__inline static UINT get_button_type( LONG window_style )
+static inline UINT get_button_type( LONG window_style )
 {
     return (window_style & 0x0f);
 }
 
 /* paint a button of any type */
-__inline static void paint_button( HWND hwnd, LONG style, UINT action )
+static inline void paint_button( HWND hwnd, LONG style, UINT action )
 {
     if (btnPaintFunc[style] && IsWindowVisible(hwnd))
     {
@@ -205,7 +206,7 @@ __inline static void paint_button( HWND hwnd, LONG style, UINT action )
 }
 
 /* retrieve the button text; returned buffer must be freed by caller */
-__inline static WCHAR *get_button_text( HWND hwnd )
+static inline WCHAR *get_button_text( HWND hwnd )
 {
     INT len = 512;
     WCHAR *buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
@@ -213,21 +214,51 @@ __inline static 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 );
+}
+
+/* Retrieve the UI state for the control */
+static BOOL button_update_uistate(HWND hwnd, BOOL unicode)
+{
+    LONG flags, prevflags;
+
+    if (unicode)
+        flags = DefWindowProcW(hwnd, WM_QUERYUISTATE, 0, 0);
+    else
+        flags = DefWindowProcA(hwnd, WM_QUERYUISTATE, 0, 0);
+
+    prevflags = get_ui_state(hwnd);
+
+    if (prevflags != flags)
+    {
+        set_ui_state(hwnd, flags);
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
 /***********************************************************************
  *           ButtonWndProc_common
  */
-static LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
-                                           WPARAM wParam, LPARAM lParam, BOOL unicode )
+LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
+                                  WPARAM wParam, LPARAM lParam, BOOL unicode )
 {
     RECT rect;
     POINT pt;
-    LONG style = GetWindowLongW( hWnd, GWL_STYLE );
+    LONG style = GetWindowLongPtrW( hWnd, GWL_STYLE );
     UINT btn_type = get_button_type( style );
     LONG state;
     HANDLE oldHbitmap;
 
-    pt.x = LOWORD(lParam);
-    pt.y = HIWORD(lParam);
+    pt.x = (short)LOWORD(lParam);
+    pt.y = (short)HIWORD(lParam);
 
     switch (uMsg)
     {
@@ -258,7 +289,15 @@ static LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
         }
         if (btn_type >= MAX_BTN_TYPE)
             return -1; /* abort */
+
+        /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
+        if (btn_type == BS_USERBUTTON )
+        {
+            style = (style & ~0x0f) | BS_PUSHBUTTON;
+            SetWindowLongPtrW( hWnd, GWL_STYLE, style );
+        }
         set_button_state( hWnd, BUTTON_UNCHECKED );
+        button_update_uistate( hWnd, unicode );
         return 0;
 
     case WM_ERASEBKGND:
@@ -296,6 +335,7 @@ static LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
        {
            SendMessageW( hWnd, BM_SETSTATE, TRUE, 0 );
             set_button_state( hWnd, get_button_state( hWnd ) | BUTTON_BTNPRESSED );
+            SetCapture( hWnd );
        }
        break;
 
@@ -407,7 +447,7 @@ static LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
 
     case WM_SETFONT:
         set_button_font( hWnd, (HFONT)wParam );
-        if (lParam) paint_button( hWnd, btn_type, ODA_DRAWENTIRE );
+        if (lParam) InvalidateRect(hWnd, NULL, TRUE);
         break;
 
     case WM_GETFONT:
@@ -432,24 +472,22 @@ static LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
         if (style & BS_NOTIFY)
             BUTTON_NOTIFY_PARENT(hWnd, BN_KILLFOCUS);
 
+        InvalidateRect( hWnd, NULL, FALSE );
         break;
 
     case WM_SYSCOLORCHANGE:
         InvalidateRect( hWnd, NULL, FALSE );
         break;
 
-#ifndef __REACTOS__
-    case BM_SETSTYLE16:
-#endif
     case BM_SETSTYLE:
         if ((wParam & 0x0f) >= MAX_BTN_TYPE) break;
         btn_type = wParam & 0x0f;
         style = (style & ~0x0f) | btn_type;
-        SetWindowLongW( hWnd, GWL_STYLE, style );
+        SetWindowLongPtrW( hWnd, GWL_STYLE, style );
 
         /* Only redraw if lParam flag is set.*/
         if (lParam)
-           paint_button( hWnd, btn_type, ODA_DRAWENTIRE );
+            InvalidateRect( hWnd, NULL, TRUE );
 
         break;
 
@@ -478,15 +516,9 @@ static LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
     case BM_GETIMAGE:
         return GetWindowLongPtrW( hWnd, HIMAGE_GWL_OFFSET );
 
-#ifndef __REACTOS__
-    case BM_GETCHECK16:
-#endif
     case BM_GETCHECK:
         return get_button_state( hWnd ) & 3;
 
-#ifndef __REACTOS__
-    case BM_SETCHECK16:
-#endif
     case BM_SETCHECK:
         if (wParam > maxCheckState[btn_type]) wParam = maxCheckState[btn_type];
         state = get_button_state( hWnd );
@@ -494,7 +526,7 @@ static LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
         {
             if (wParam) style |= WS_TABSTOP;
             else style &= ~WS_TABSTOP;
-            SetWindowLongW( hWnd, GWL_STYLE, style );
+            SetWindowLongPtrW( hWnd, GWL_STYLE, style );
         }
         if ((state & 3) != wParam)
         {
@@ -505,15 +537,9 @@ static LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
             BUTTON_CheckAutoRadioButton( hWnd );
         break;
 
-#ifndef __REACTOS__
-    case BM_GETSTATE16:
-#endif
     case BM_GETSTATE:
         return get_button_state( hWnd );
 
-#ifndef __REACTOS__
-    case BM_SETSTATE16:
-#endif
     case BM_SETSTATE:
         state = get_button_state( hWnd );
         if (wParam)
@@ -529,6 +555,16 @@ static LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
         paint_button( hWnd, btn_type, ODA_SELECT );
         break;
 
+    case WM_UPDATEUISTATE:
+        if (unicode)
+            DefWindowProcW(hWnd, uMsg, wParam, lParam);
+        else
+            DefWindowProcA(hWnd, uMsg, wParam, lParam);
+
+        if (button_update_uistate(hWnd, unicode))
+            paint_button( hWnd, btn_type, ODA_DRAWENTIRE );
+        break;
+
     case WM_NCHITTEST:
         if(btn_type == BS_GROUPBOX) return HTTRANSPARENT;
         /* fall through */
@@ -545,7 +581,7 @@ static LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
  * the passed HWND and calls the real window procedure (with a WND*
  * pointer pointing to the locked windowstructure).
  */
-static LRESULT WINAPI ButtonWndProcW( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+LRESULT WINAPI ButtonWndProcW( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
 {
     if (!IsWindow( hWnd )) return 0;
     return ButtonWndProc_common( hWnd, uMsg, wParam, lParam, TRUE );
@@ -555,7 +591,7 @@ static LRESULT WINAPI ButtonWndProcW( HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
 /***********************************************************************
  *           ButtonWndProcA
  */
-static LRESULT WINAPI ButtonWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+LRESULT WINAPI ButtonWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
 {
     if (!IsWindow( hWnd )) return 0;
     return ButtonWndProc_common( hWnd, uMsg, wParam, lParam, FALSE );
@@ -564,9 +600,8 @@ static LRESULT WINAPI ButtonWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
 
 /**********************************************************************
  * Convert button styles to flags used by DrawText.
- * TODO: handle WS_EX_RIGHT extended style.
  */
-static UINT BUTTON_BStoDT(DWORD style)
+static UINT BUTTON_BStoDT( DWORD style, DWORD ex_style )
 {
    UINT dtStyle = DT_NOCLIP;  /* We use SelectClipRgn to limit output */
 
@@ -590,8 +625,10 @@ static UINT BUTTON_BStoDT(DWORD style)
          /* all other flavours have left aligned text */
    }
 
+   if (ex_style & WS_EX_RIGHT) dtStyle = DT_RIGHT | (dtStyle & ~(DT_LEFT | DT_CENTER));
+
    /* DrawText ignores vertical alignment for multiline text,
-    * but we use these flags to align label manualy.
+    * but we use these flags to align label manually.
     */
    if (get_button_type(style) != BS_GROUPBOX)
    {
@@ -622,11 +659,12 @@ static UINT BUTTON_BStoDT(DWORD style)
  */
 static UINT BUTTON_CalcLabelRect(HWND hwnd, HDC hdc, RECT *rc)
 {
-   LONG style = GetWindowLongW( hwnd, GWL_STYLE );
+   LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE );
+   LONG ex_style = GetWindowLongPtrW( hwnd, GWL_EXSTYLE );
    WCHAR *text;
    ICONINFO    iconInfo;
    BITMAP      bm;
-   UINT        dtStyle = BUTTON_BStoDT(style);
+   UINT        dtStyle = BUTTON_BStoDT( style, ex_style );
    RECT        r = *rc;
    INT         n;
 
@@ -642,6 +680,9 @@ static UINT BUTTON_CalcLabelRect(HWND hwnd, HDC hdc, RECT *rc)
           }
           DrawTextW(hdc, text, -1, &r, dtStyle | DT_CALCRECT);
           HeapFree( GetProcessHeap(), 0, text );
+
+          if (get_ui_state( hwnd ) & UISF_HIDEACCEL)
+              dtStyle |= DT_HIDEPREFIX;
           break;
 
       case BS_ICON:
@@ -669,7 +710,7 @@ static UINT BUTTON_CalcLabelRect(HWND hwnd, HDC hdc, RECT *rc)
       empty_rect:
          rc->right = r.left;
          rc->bottom = r.top;
-         return (UINT)(LONG)-1;
+         return (UINT)-1;
    }
 
    /* Position label inside bounding rectangle according to
@@ -729,7 +770,7 @@ static BOOL CALLBACK BUTTON_DrawTextCallback(HDC hdc, LPARAM lp, WPARAM wp, int
  *
  *   Common function for drawing button label.
  */
-static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, RECT *rc)
+static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, const RECT *rc)
 {
    DRAWSTATEPROC lpOutputProc = NULL;
    LPARAM lp;
@@ -737,7 +778,7 @@ static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, RECT *rc)
    HBRUSH hbr = 0;
    UINT flags = IsWindowEnabled(hwnd) ? DSS_NORMAL : DSS_DISABLED;
    LONG state = get_button_state( hwnd );
-   LONG style = GetWindowLongW( hwnd, GWL_STYLE );
+   LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE );
    WCHAR *text = NULL;
 
    /* FIXME: To draw disabled label in Win31 look-and-feel, we probably
@@ -759,6 +800,9 @@ static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, RECT *rc)
          if (!(text = get_button_text( hwnd ))) return;
          lp = (LPARAM)text;
          wp = (WPARAM)dtFlags;
+
+         if (dtFlags & DT_HIDEPREFIX)
+             flags |= DSS_HIDEPREFIX;
          break;
 
       case BS_ICON:
@@ -785,7 +829,7 @@ static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, RECT *rc)
  */
 static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
 {
-    RECT     rc, focus_rect, r;
+    RECT     rc, r;
     UINT     dtFlags, uState;
     HPEN     hOldPen;
     HBRUSH   hOldBrush;
@@ -793,7 +837,7 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
     COLORREF oldTxtColor;
     HFONT hFont;
     LONG state = get_button_state( hwnd );
-    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
+    LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE );
     BOOL pushedState = (state & BUTTON_HIGHLIGHTED);
     HWND parent;
 
@@ -804,21 +848,28 @@ 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 );
 #ifdef __REACTOS__
-    hOldPen = (HPEN)SelectObject(hDC, GetSysColorPen(COLOR_WINDOWFRAME));
+    hOldPen = SelectObject(hDC, GetStockObject(DC_PEN));
+    SetDCPenColor(hDC, GetSysColor(COLOR_WINDOWFRAME));
 #else
-    hOldPen = (HPEN)SelectObject(hDC, SYSCOLOR_GetPen(COLOR_WINDOWFRAME));
+    hOldPen = SelectObject(hDC, SYSCOLOR_GetPen(COLOR_WINDOWFRAME));
 #endif
-    hOldBrush =(HBRUSH)SelectObject(hDC,GetSysColorBrush(COLOR_BTNFACE));
+    hOldBrush = SelectObject(hDC,GetSysColorBrush(COLOR_BTNFACE));
     oldBkMode = SetBkMode(hDC, TRANSPARENT);
 
     if (get_button_type(style) == BS_DEFPUSHBUTTON)
     {
-        Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
+        if (action != ODA_FOCUS)
+            Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
        InflateRect( &rc, -1, -1 );
     }
 
-    uState = DFCS_BUTTONPUSH | DFCS_ADJUSTRECT;
+    /* completely skip the drawing if only focus has changed */
+    if (action == ODA_FOCUS) goto draw_focus;
+
+    uState = DFCS_BUTTONPUSH;
 
     if (style & BS_FLAT)
         uState |= DFCS_MONO;
@@ -835,8 +886,6 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
 
     DrawFrameControl( hDC, &rc, DFC_BUTTON, uState );
 
-    focus_rect = rc;
-
     /* draw button label */
     r = rc;
     dtFlags = BUTTON_CalcLabelRect(hwnd, hDC, &r);
@@ -847,19 +896,21 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
     if (pushedState)
        OffsetRect(&r, 1, 1);
 
-    IntersectClipRect(hDC, rc.left, rc.top, rc.right, rc.bottom);
-
     oldTxtColor = SetTextColor( hDC, GetSysColor(COLOR_BTNTEXT) );
 
     BUTTON_DrawLabel(hwnd, hDC, dtFlags, &r);
 
     SetTextColor( hDC, oldTxtColor );
 
-    if (state & BUTTON_HASFOCUS)
+draw_focus:
+    if ((action == ODA_FOCUS) ||
+        ((action == ODA_DRAWENTIRE) && (state & BUTTON_HASFOCUS)))
     {
-        InflateRect( &focus_rect, -1, -1 );
-        IntersectRect(&focus_rect, &focus_rect, &rc);
-        DrawFocusRect( hDC, &focus_rect );
+        if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS))
+        {
+            InflateRect( &rc, -2, -2 );
+            DrawFocusRect( hDC, &rc );
+        }
     }
 
  cleanup:
@@ -880,7 +931,7 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action )
     UINT dtFlags;
     HFONT hFont;
     LONG state = get_button_state( hwnd );
-    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
+    LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE );
     HWND parent;
 
     if (style & BS_PUSHLIKE)
@@ -901,6 +952,7 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action )
     if (!hBrush) /* did the app forget to call defwindowproc ? */
         hBrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC,
                                        (WPARAM)hDC, (LPARAM)hwnd );
+    setup_clipping( hwnd, hDC );
 
     if (style & BS_LEFTTEXT)
     {
@@ -914,7 +966,7 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action )
         rtext.left += checkBoxWidth + 4;
         rbox.right = checkBoxWidth;
     }
+
     /* Since WM_ERASEBKGND does nothing, first prepare background */
     if (action == ODA_SELECT) FillRect( hDC, &rbox, hBrush );
     if (action == ODA_DRAWENTIRE) FillRect( hDC, &client, hBrush );
@@ -980,8 +1032,6 @@ 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);
-
     if (action == ODA_DRAWENTIRE)
        BUTTON_DrawLabel(hwnd, hDC, dtFlags, &rtext);
 
@@ -989,10 +1039,13 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action )
     if ((action == ODA_FOCUS) ||
         ((action == ODA_DRAWENTIRE) && (state & BUTTON_HASFOCUS)))
     {
-       rtext.left--;
-       rtext.right++;
-       IntersectRect(&rtext, &rtext, &client);
-       DrawFocusRect( hDC, &rtext );
+        if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS))
+        {
+            rtext.left--;
+            rtext.right++;
+            IntersectRect(&rtext, &rtext, &client);
+            DrawFocusRect( hDC, &rtext );
+        }
     }
 }
 
@@ -1013,7 +1066,7 @@ static void BUTTON_CheckAutoRadioButton( HWND hwnd )
     {
         if (!sibling) break;
         if ((hwnd != sibling) &&
-            ((GetWindowLongW( sibling, GWL_STYLE) & 0x0f) == BS_AUTORADIOBUTTON))
+            ((GetWindowLongPtrW( sibling, GWL_STYLE) & 0x0f) == BS_AUTORADIOBUTTON))
             SendMessageW( sibling, BM_SETCHECK, BUTTON_UNCHECKED, 0 );
         sibling = GetNextDlgGroupItem( parent, sibling, FALSE );
     } while (sibling != start);
@@ -1031,7 +1084,7 @@ static void GB_Paint( HWND hwnd, HDC hDC, UINT action )
     HFONT hFont;
     UINT dtFlags;
     TEXTMETRICW tm;
-    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
+    LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE );
     HWND parent;
 
     if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont );
@@ -1042,6 +1095,7 @@ static void GB_Paint( HWND hwnd, HDC hDC, UINT action )
     if (!hbr) /* did the app forget to call defwindowproc ? */
         hbr = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC,
                                     (WPARAM)hDC, (LPARAM)hwnd);
+    setup_clipping( hwnd, hDC );
 
     GetClientRect( hwnd, &rc);
     rcFrame = rc;
@@ -1061,7 +1115,7 @@ static void GB_Paint( HWND hwnd, HDC hDC, UINT action )
      * But Windows doesn't clip label's rect, so do I.
      */
 
-    /* There is 1-pixel marging at the left, right, and bottom */
+    /* There is 1-pixel margin at the left, right, and bottom */
     rc.left--; rc.right++; rc.bottom++;
     FillRect(hDC, &rc, hbr);
     rc.left++; rc.right--; rc.bottom--;
@@ -1098,7 +1152,12 @@ static void UB_Paint( HWND hwnd, HDC hDC, UINT action )
     FillRect( hDC, &rc, hBrush );
     if ((action == ODA_FOCUS) ||
         ((action == ODA_DRAWENTIRE) && (state & BUTTON_HASFOCUS)))
-        DrawFocusRect( hDC, &rc );
+    {
+        if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS))
+            DrawFocusRect( hDC, &rc );
+    }
+
+    BUTTON_NOTIFY_PARENT( hwnd, BN_PAINT );
 }
 
 
@@ -1110,8 +1169,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;
@@ -1128,21 +1185,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);
 }