Fix button behaviour on WM_SETFOCUS/WM_KILLFOCUS with a test case
Dmitry Timoshkov
dmitry at baikal.ru
Thu Aug 5 03:53:02 CDT 2004
Hello,
trying to merge an old fix for the button code I decided to write
a test case for it.
Changelog:
Dmitry Timoshkov <dmitry at codeweavers.com>
Fix button behaviour on WM_SETFOCUS/WM_KILLFOCUS with a test case.
diff -u cvs/hq/wine/controls/button.c wine/controls/button.c
--- cvs/hq/wine/controls/button.c 2004-04-01 19:05:33.000000000 +0900
+++ wine/controls/button.c 2004-08-05 16:58:58.000000000 +0900
@@ -152,9 +152,9 @@ inline static void paint_button( HWND hw
/* retrieve the button text; returned buffer must be freed by caller */
inline static WCHAR *get_button_text( HWND hwnd )
{
- INT len = GetWindowTextLengthW( hwnd );
+ INT len = 512;
WCHAR *buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
- if (buffer) GetWindowTextW( hwnd, buffer, len + 1 );
+ if (buffer) InternalGetWindowText( hwnd, buffer, len + 1 );
return buffer;
}
@@ -209,9 +209,12 @@ static LRESULT WINAPI ButtonWndProc_comm
{
HDC hdc = (HDC)wParam;
RECT rc;
- HBRUSH hBrush = (HBRUSH)SendMessageW(GetParent(hWnd), WM_CTLCOLORBTN, (WPARAM)hdc, (LPARAM)hWnd);
+ HBRUSH hBrush;
+ HWND parent = GetParent(hWnd);
+ if (!parent) parent = hWnd;
+ hBrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORBTN, (WPARAM)hdc, (LPARAM)hWnd);
if (!hBrush) /* did the app forget to call defwindowproc ? */
- hBrush = (HBRUSH)DefWindowProcW(GetParent(hWnd), WM_CTLCOLORBTN,
+ hBrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORBTN,
(WPARAM)hdc, (LPARAM)hWnd);
GetClientRect(hWnd, &rc);
FillRect(hdc, &rc, hBrush);
@@ -319,11 +322,13 @@ static LRESULT WINAPI ButtonWndProc_comm
HDC hdc = GetDC(hWnd);
HBRUSH hbrush;
RECT client, rc;
+ HWND parent = GetParent(hWnd);
- hbrush = (HBRUSH)SendMessageW(GetParent(hWnd), WM_CTLCOLORSTATIC,
+ if (!parent) parent = hWnd;
+ hbrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC,
(WPARAM)hdc, (LPARAM)hWnd);
if (!hbrush) /* did the app forget to call DefWindowProc ? */
- hbrush = (HBRUSH)DefWindowProcW(GetParent(hWnd), WM_CTLCOLORSTATIC,
+ hbrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC,
(WPARAM)hdc, (LPARAM)hWnd);
GetClientRect(hWnd, &client);
@@ -353,16 +358,6 @@ static LRESULT WINAPI ButtonWndProc_comm
return (LRESULT)get_button_font( hWnd );
case WM_SETFOCUS:
- if ((btn_type == BS_RADIOBUTTON || btn_type == BS_AUTORADIOBUTTON) && (GetCapture() != hWnd) &&
- !(SendMessageW(hWnd, BM_GETCHECK, 0, 0) & BST_CHECKED))
- {
- /* The notification is sent when the button (BS_AUTORADIOBUTTON)
- is unchecked and the focus was not given by a mouse click. */
- if (btn_type == BS_AUTORADIOBUTTON)
- SendMessageW( hWnd, BM_SETCHECK, BUTTON_CHECKED, 0 );
- SendMessageW( GetParent(hWnd), WM_COMMAND,
- MAKEWPARAM( GetWindowLongA(hWnd,GWL_ID), BN_CLICKED ), (LPARAM)hWnd);
- }
set_button_state( hWnd, get_button_state(hWnd) | BUTTON_HASFOCUS );
paint_button( hWnd, btn_type, ODA_FOCUS );
break;
@@ -370,7 +365,6 @@ static LRESULT WINAPI ButtonWndProc_comm
case WM_KILLFOCUS:
set_button_state( hWnd, get_button_state(hWnd) & ~BUTTON_HASFOCUS );
paint_button( hWnd, btn_type, ODA_FOCUS );
- InvalidateRect( hWnd, NULL, TRUE );
break;
case WM_SYSCOLORCHANGE:
@@ -725,12 +719,15 @@ static void PB_Paint( HWND hwnd, HDC hDC
LONG state = get_button_state( hwnd );
LONG style = GetWindowLongA( hwnd, GWL_STYLE );
BOOL pushedState = (state & BUTTON_HIGHLIGHTED);
+ HWND parent;
GetClientRect( hwnd, &rc );
/* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont );
- SendMessageW( GetParent(hwnd), WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)hwnd );
+ parent = GetParent(hwnd);
+ if (!parent) parent = hwnd;
+ SendMessageW( parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)hwnd );
hOldPen = (HPEN)SelectObject(hDC, SYSCOLOR_GetPen(COLOR_WINDOWFRAME));
hOldBrush =(HBRUSH)SelectObject(hDC,GetSysColorBrush(COLOR_BTNFACE));
oldBkMode = SetBkMode(hDC, TRANSPARENT);
@@ -808,6 +805,7 @@ static void CB_Paint( HWND hwnd, HDC hDC
HFONT hFont;
LONG state = get_button_state( hwnd );
LONG style = GetWindowLongA( hwnd, GWL_STYLE );
+ HWND parent;
if (style & BS_PUSHLIKE)
{
@@ -820,10 +818,12 @@ static void CB_Paint( HWND hwnd, HDC hDC
if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont );
- hBrush = (HBRUSH)SendMessageW(GetParent(hwnd), WM_CTLCOLORSTATIC,
+ parent = GetParent(hwnd);
+ if (!parent) parent = hwnd;
+ hBrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC,
(WPARAM)hDC, (LPARAM)hwnd);
if (!hBrush) /* did the app forget to call defwindowproc ? */
- hBrush = (HBRUSH)DefWindowProcW(GetParent(hwnd), WM_CTLCOLORSTATIC,
+ hBrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC,
(WPARAM)hDC, (LPARAM)hwnd );
if (style & BS_LEFTTEXT)
@@ -953,14 +953,15 @@ static void GB_Paint( HWND hwnd, HDC hDC
UINT dtFlags;
TEXTMETRICW tm;
LONG style = GetWindowLongA( hwnd, GWL_STYLE );
-
- if (action != ODA_DRAWENTIRE) return;
+ HWND parent;
if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont );
/* GroupBox acts like static control, so it sends CTLCOLORSTATIC */
- hbr = (HBRUSH)SendMessageW(GetParent(hwnd), WM_CTLCOLORSTATIC, (WPARAM)hDC, (LPARAM)hwnd);
+ parent = GetParent(hwnd);
+ if (!parent) parent = hwnd;
+ hbr = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC, (WPARAM)hDC, (LPARAM)hwnd);
if (!hbr) /* did the app forget to call defwindowproc ? */
- hbr = (HBRUSH)DefWindowProcW(GetParent(hwnd), WM_CTLCOLORSTATIC,
+ hbr = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC,
(WPARAM)hDC, (LPARAM)hwnd);
GetClientRect( hwnd, &rc);
@@ -1000,6 +1001,7 @@ static void UB_Paint( HWND hwnd, HDC hDC
HBRUSH hBrush;
HFONT hFont;
LONG state = get_button_state( hwnd );
+ HWND parent;
if (action == ODA_SELECT) return;
@@ -1007,9 +1009,11 @@ static void UB_Paint( HWND hwnd, HDC hDC
if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont );
- hBrush = (HBRUSH)SendMessageW(GetParent(hwnd), WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)hwnd);
+ parent = GetParent(hwnd);
+ if (!parent) parent = hwnd;
+ hBrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)hwnd);
if (!hBrush) /* did the app forget to call defwindowproc ? */
- hBrush = (HBRUSH)DefWindowProcW(GetParent(hwnd), WM_CTLCOLORBTN,
+ hBrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORBTN,
(WPARAM)hDC, (LPARAM)hwnd);
FillRect( hDC, &rc, hBrush );
@@ -1030,6 +1034,7 @@ static void OB_Paint( HWND hwnd, HDC hDC
HRGN clipRegion;
RECT clipRect;
UINT id = GetWindowLongA( hwnd, GWL_ID );
+ HWND parent;
dis.CtlType = ODT_BUTTON;
dis.CtlID = id;
@@ -1053,7 +1058,9 @@ static void OB_Paint( HWND hwnd, HDC hDC
DPtoLP(hDC, (LPPOINT) &clipRect, 2);
IntersectClipRect(hDC, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
- SetBkColor( hDC, GetSysColor( COLOR_BTNFACE ) );
+ parent = GetParent(hwnd);
+ if (!parent) parent = hwnd;
+ SendMessageW( parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)hwnd );
SendMessageW( GetParent(hwnd), WM_DRAWITEM, id, (LPARAM)&dis );
SelectClipRgn(hDC, clipRegion);
}
diff -u cvs/hq/wine/dlls/user/tests/msg.c wine/dlls/user/tests/msg.c
--- cvs/hq/wine/dlls/user/tests/msg.c 2004-07-10 14:03:08.000000000 +0900
+++ wine/dlls/user/tests/msg.c 2004-08-05 16:58:17.000000000 +0900
@@ -473,6 +473,7 @@ static const struct message WmEndCustomD
/* Creation and destruction of a modal dialog (32) */
static const struct message WmModalDialogSeq[] = {
{ WM_CANCELMODE, sent|parent },
+ { HCBT_SETFOCUS, hook },
{ WM_KILLFOCUS, sent|parent },
{ WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
{ WM_ENABLE, sent|parent|wparam, 0 },
@@ -1607,6 +1608,126 @@ static void test_messages(void)
flush_sequence();
}
+/****************** button message test *************************/
+static const struct message WmSetFocusButtonSeq[] =
+{
+ { HCBT_SETFOCUS, hook },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
+ { WM_SETFOCUS, sent|wparam, 0 },
+ { WM_CTLCOLORBTN, sent|defwinproc },
+ { 0 }
+};
+static const struct message WmKillFocusButtonSeq[] =
+{
+ { HCBT_SETFOCUS, hook },
+ { WM_KILLFOCUS, sent|wparam, 0 },
+ { WM_CTLCOLORBTN, sent|defwinproc },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
+ { 0 }
+};
+static const struct message WmSetFocusStaticSeq[] =
+{
+ { HCBT_SETFOCUS, hook },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
+ { WM_SETFOCUS, sent|wparam, 0 },
+ { WM_CTLCOLORSTATIC, sent|defwinproc },
+ { 0 }
+};
+static const struct message WmKillFocusStaticSeq[] =
+{
+ { HCBT_SETFOCUS, hook },
+ { WM_KILLFOCUS, sent|wparam, 0 },
+ { WM_CTLCOLORSTATIC, sent|defwinproc },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
+ { 0 }
+};
+
+static WNDPROC old_button_proc;
+
+static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static long defwndproc_counter = 0;
+ LRESULT ret;
+ struct message msg;
+
+ trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
+
+ msg.message = message;
+ msg.flags = sent|wparam|lparam;
+ if (defwndproc_counter) msg.flags |= defwinproc;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ add_message(&msg);
+
+ defwndproc_counter++;
+ ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
+ defwndproc_counter--;
+
+ return ret;
+}
+
+static void subclass_button(void)
+{
+ WNDCLASSA cls;
+
+ if (!GetClassInfoA(0, "button", &cls)) assert(0);
+
+ old_button_proc = cls.lpfnWndProc;
+
+ cls.hInstance = GetModuleHandle(0);
+ cls.lpfnWndProc = button_hook_proc;
+ cls.lpszClassName = "my_button_class";
+ if (!RegisterClassA(&cls)) assert(0);
+}
+
+static void test_button_messages(void)
+{
+ static const struct
+ {
+ DWORD style;
+ const struct message *setfocus;
+ const struct message *killfocus;
+ } button[] = {
+ { BS_PUSHBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
+ { BS_DEFPUSHBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
+ { BS_CHECKBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
+ { BS_AUTOCHECKBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
+ { BS_RADIOBUTTON, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
+ { BS_3STATE, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
+ { BS_AUTO3STATE, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
+ { BS_GROUPBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
+ { BS_USERBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
+ { BS_AUTORADIOBUTTON, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
+ { BS_OWNERDRAW, WmSetFocusButtonSeq, WmKillFocusButtonSeq }
+ };
+ int i;
+ HWND hwnd;
+
+ subclass_button();
+
+ for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
+ {
+ hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
+ 0, 0, 50, 14, 0, 0, 0, NULL);
+ ok(hwnd != 0, "Failed to create button window\n");
+
+ ShowWindow(hwnd, SW_SHOW);
+ UpdateWindow(hwnd);
+ SetFocus(0);
+ flush_sequence();
+
+ trace("button style %08lx\n", button[i].style);
+ SetFocus(hwnd);
+ ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button");
+
+ SetFocus(0);
+ ok_sequence(button[i].killfocus, "SetFocus(0) on a button");
+
+ DestroyWindow(hwnd);
+ }
+}
+/************* end of button message test ********************/
+
static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static long defwndproc_counter = 0;
@@ -1784,6 +1905,9 @@ static LRESULT CALLBACK cbt_hook_proc(in
trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
+ /* Log also SetFocus(0) calls */
+ if (!wParam) wParam = lParam;
+
if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
{
if (!strcmp(buf, "TestWindowClass") ||
@@ -1794,6 +1918,7 @@ static LRESULT CALLBACK cbt_hook_proc(in
!strcmp(buf, "MDI_frame_class") ||
!strcmp(buf, "MDI_client_class") ||
!strcmp(buf, "MDI_child_class") ||
+ !strcmp(buf, "my_button_class") ||
!strcmp(buf, "#32770"))
{
struct message msg;
@@ -1817,6 +1942,7 @@ START_TEST(msg)
test_messages();
test_mdi_messages();
+ test_button_messages();
UnhookWindowsHookEx(hCBT_hook);
}
More information about the wine-patches
mailing list