Button should do ReleaseCapture() on WM_KILLFOCUS if it's in a pressed state
Dmitry Timoshkov
dmitry at baikal.ru
Thu Aug 26 08:45:05 CDT 2004
Hello,
this is another result of my bug hunting for a not existing capture bug.
Changelog:
Dmitry Timoshkov <dmitry at codeweavers.com>
Button should do ReleaseCapture() on WM_KILLFOCUS if it's
in a pressed state.
Add a comprehensive test case for capture behaviour.
diff -u cvs/hq/wine/controls/button.c wine/controls/button.c
--- cvs/hq/wine/controls/button.c 2004-08-23 13:33:05.000000000 +0900
+++ wine/controls/button.c 2004-08-26 22:02:00.000000000 +0900
@@ -363,6 +363,10 @@ static LRESULT WINAPI ButtonWndProc_comm
break;
case WM_KILLFOCUS:
+ state = get_button_state( hWnd );
+ if ((state & BUTTON_BTNPRESSED) && GetCapture() == hWnd)
+ ReleaseCapture();
+
set_button_state( hWnd, get_button_state(hWnd) & ~BUTTON_HASFOCUS );
paint_button( hWnd, btn_type, ODA_FOCUS );
break;
diff -u cvs/hq/wine/dlls/user/tests/win.c wine/dlls/user/tests/win.c
--- cvs/hq/wine/dlls/user/tests/win.c 2004-08-17 13:52:51.000000000 +0900
+++ wine/dlls/user/tests/win.c 2004-08-26 18:27:47.000000000 +0900
@@ -1814,6 +1814,166 @@ static void test_SetActiveWindow(HWND hw
ok( GetActiveWindow() != hwnd2, "Window %p is still active\n", hwnd2 );
}
+static void check_wnd_state(HWND active, HWND foreground, HWND focus, HWND capture)
+{
+ ok(active == GetActiveWindow(), "GetActiveWindow() = %p\n", GetActiveWindow());
+ if (foreground)
+ ok(foreground == GetForegroundWindow(), "GetForegroundWindow() = %p\n", GetForegroundWindow());
+ ok(focus == GetFocus(), "GetFocus() = %p\n", GetFocus());
+ ok(capture == GetCapture(), "GetCapture() = %p\n", GetCapture());
+}
+
+static WNDPROC old_button_proc;
+
+static LRESULT WINAPI button_hook_proc(HWND button, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ LRESULT ret;
+ USHORT key_state;
+
+ key_state = GetKeyState(VK_LBUTTON);
+ ok(!(key_state & 0x8000), "VK_LBUTTON should not be pressed, state %04x\n", key_state);
+
+ ret = CallWindowProcA(old_button_proc, button, msg, wparam, lparam);
+
+ if (msg == WM_LBUTTONDOWN)
+ {
+ HWND hwnd, capture;
+
+ check_wnd_state(button, button, button, button);
+
+ hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
+ assert(hwnd);
+ trace("hwnd %p\n", hwnd);
+
+ check_wnd_state(button, button, button, button);
+
+ ShowWindow(hwnd, SW_SHOWNOACTIVATE);
+
+ check_wnd_state(button, button, button, button);
+
+ DestroyWindow(hwnd);
+
+ hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
+ assert(hwnd);
+ trace("hwnd %p\n", hwnd);
+
+ check_wnd_state(button, button, button, button);
+
+ /* button wnd proc should release capture on WM_KILLFOCUS if it does
+ * match internal button state.
+ */
+ SendMessage(button, WM_KILLFOCUS, 0, 0);
+ check_wnd_state(button, button, button, 0);
+
+ ShowWindow(hwnd, SW_SHOW);
+ check_wnd_state(hwnd, hwnd, hwnd, 0);
+
+ capture = SetCapture(hwnd);
+ ok(capture == 0, "SetCapture() = %p\n", capture);
+
+ check_wnd_state(hwnd, hwnd, hwnd, hwnd);
+
+ DestroyWindow(hwnd);
+
+ check_wnd_state(button, 0, button, 0);
+ }
+
+ return ret;
+}
+
+static void test_capture_1(void)
+{
+ HWND button, capture;
+
+ capture = GetCapture();
+ ok(capture == 0, "GetCapture() = %p\n", capture);
+
+ button = CreateWindowExA(0, "button", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
+ assert(button);
+ trace("button %p\n", button);
+
+ old_button_proc = (WNDPROC)SetWindowLongPtrA(button, GWLP_WNDPROC, (LONG_PTR)button_hook_proc);
+
+ SendMessageA(button, WM_LBUTTONDOWN, 0, 0);
+
+ DestroyWindow(button);
+}
+
+static void test_capture_2(void)
+{
+ HWND button, hwnd, capture;
+
+ check_wnd_state(0, 0, 0, 0);
+
+ button = CreateWindowExA(0, "button", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
+ assert(button);
+ trace("button %p\n", button);
+
+ check_wnd_state(button, button, button, 0);
+
+ capture = SetCapture(button);
+ ok(capture == 0, "SetCapture() = %p\n", capture);
+
+ check_wnd_state(button, button, button, button);
+
+ /* button wnd proc should ignore WM_KILLFOCUS if it doesn't match
+ * internal button state.
+ */
+ SendMessage(button, WM_KILLFOCUS, 0, 0);
+ check_wnd_state(button, button, button, button);
+
+ hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
+ assert(hwnd);
+ trace("hwnd %p\n", hwnd);
+
+ check_wnd_state(button, button, button, button);
+
+ ShowWindow(hwnd, SW_SHOWNOACTIVATE);
+
+ check_wnd_state(button, button, button, button);
+
+ DestroyWindow(hwnd);
+
+ hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
+ assert(hwnd);
+ trace("hwnd %p\n", hwnd);
+
+ check_wnd_state(button, button, button, button);
+
+ ShowWindow(hwnd, SW_SHOW);
+
+ check_wnd_state(hwnd, hwnd, hwnd, button);
+
+ capture = SetCapture(hwnd);
+ ok(capture == button, "SetCapture() = %p\n", capture);
+
+ check_wnd_state(hwnd, hwnd, hwnd, hwnd);
+
+ DestroyWindow(hwnd);
+ check_wnd_state(button, button, button, 0);
+
+ DestroyWindow(button);
+ check_wnd_state(0, 0, 0, 0);
+}
+
+static void test_capture_3(HWND hwnd1, HWND hwnd2)
+{
+ ShowWindow(hwnd1, SW_HIDE);
+ ShowWindow(hwnd2, SW_HIDE);
+
+ ok(!IsWindowVisible(hwnd1), "%p should be invisible\n", hwnd1);
+ ok(!IsWindowVisible(hwnd2), "%p should be invisible\n", hwnd2);
+
+ SetCapture(hwnd1);
+ check_wnd_state(0, 0, 0, hwnd1);
+
+ SetCapture(hwnd2);
+ check_wnd_state(0, 0, 0, hwnd2);
+
+ ShowWindow(hwnd1, SW_SHOW);
+ check_wnd_state(hwnd1, hwnd1, hwnd1, hwnd2);
+}
+
START_TEST(win)
{
pGetAncestor = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetAncestor" );
@@ -1852,6 +2012,10 @@ START_TEST(win)
assert( hwndMain );
assert( hwndMain2 );
+ test_capture_1();
+ test_capture_2();
+ test_capture_3(hwndMain, hwndMain2);
+
test_parent_owner();
test_shell_window();
More information about the wine-patches
mailing list