From: Gabriel Ivăncescu gabrielopcode@gmail.com
Windows only sends the activation messages and hooks once, until the SetActiveWindow completes for that window.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46274 Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
AFAICS these two patches help with the recent user32 tests failures on the testbot.
Although I believe the patches are correct, I'm not sure the failure root cause is that windows are now activated recursively.
Instead, I think that some change caused window procs to now be always called recursively when they weren't before.
dlls/user32/tests/msg.c | 91 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index a2adf56565d..adb167bdad3 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -10203,6 +10203,40 @@ static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LP return ret; }
+static LRESULT WINAPI SetActiveWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + static LONG defwndproc_counter = 0; + struct recvd_message msg; + LRESULT ret; + + switch (message) + { + /* log only specific messages we are interested in */ + case WM_NCACTIVATE: + case WM_ACTIVATE: + case WM_SETFOCUS: + case WM_KILLFOCUS: + break; + default: + return DefWindowProcA(hwnd, message, wParam, lParam); + } + + msg.hwnd = hwnd; + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + msg.descr = "activation"; + add_message(&msg); + + defwndproc_counter++; + ret = DefWindowProcA(hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) @@ -10300,6 +10334,10 @@ static BOOL RegisterWindowClasses(void) cls.lpszClassName = "ShowWindowClass"; if(!RegisterClassA(&cls)) return FALSE;
+ cls.lpfnWndProc = SetActiveWindowProcA; + cls.lpszClassName = "SetActiveWindowClass"; + if(!RegisterClassA(&cls)) return FALSE; + cls.lpfnWndProc = PopupMsgCheckProcA; cls.lpszClassName = "TestPopupClass"; if(!RegisterClassA(&cls)) return FALSE; @@ -10355,6 +10393,7 @@ static BOOL is_our_logged_class(HWND hwnd) { if (!lstrcmpiA(buf, "TestWindowClass") || !lstrcmpiA(buf, "ShowWindowClass") || + !lstrcmpiA(buf, "SetActiveWindowClass") || !lstrcmpiA(buf, "TestParentClass") || !lstrcmpiA(buf, "TestPopupClass") || !lstrcmpiA(buf, "SimpleWindowClass") || @@ -14758,10 +14797,46 @@ static const struct message SetActiveWindowSeq4[] = { 0 } };
+static LRESULT WINAPI test_recursive_set_active_window_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + if (message == WM_ACTIVATE && LOWORD(wparam) != WA_INACTIVE) + { + SetActiveWindow((HWND)lparam); + SetActiveWindow(hwnd); + return 0; + } + + return DefWindowProcA(hwnd, message, wparam, lparam); +} + +static void test_set_active_window_recursive(HWND hwnd, HWND hwnd2) +{ + const struct message RecursiveActivationSeq[] = + { + { HCBT_ACTIVATE, hook|wparam, (WPARAM)hwnd }, + { WM_NCACTIVATE, sent|wparam|lparam, FALSE, (LPARAM)hwnd }, + { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)hwnd }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, + { HCBT_ACTIVATE, hook|wparam, (WPARAM)hwnd2 }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, + { WM_NCACTIVATE, sent|wparam|lparam, FALSE, (LPARAM)hwnd }, + { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)hwnd }, + { 0 } + }; + SetActiveWindow(hwnd2); + + flush_sequence(); + SetActiveWindow(hwnd); + ok_sequence(RecursiveActivationSeq, "recursive activation", TRUE); + + DestroyWindow(hwnd2); + DestroyWindow(hwnd); + flush_sequence(); +}
static void test_SetActiveWindow(void) { - HWND hwnd, popup, ret; + HWND hwnd, hwnd2, popup, ret;
hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow", WS_OVERLAPPEDWINDOW | WS_VISIBLE, @@ -14812,6 +14887,20 @@ static void test_SetActiveWindow(void) trace("done\n");
DestroyWindow(hwnd); + + hwnd = CreateWindowExA(0, "SimpleWindowClass", NULL, WS_OVERLAPPED|WS_VISIBLE, + 100, 100, 200, 200, 0, 0, 0, NULL); + ok(hwnd != 0, "Failed to create simple window\n"); + SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)test_recursive_set_active_window_proc); + + hwnd2 = CreateWindowExA(0, "SetActiveWindowClass", NULL, WS_OVERLAPPED|WS_VISIBLE, + 10, 10, 50, 50, hwnd, 0, 0, NULL); + ok(hwnd2 != 0, "Failed to create recursive activation window\n"); + + test_set_active_window_recursive(hwnd, hwnd2); + + DestroyWindow(hwnd2); + DestroyWindow(hwnd); }
static const struct message SetForegroundWindowSeq[] =