-- v11: win32u/window: Ignore changing WS_EX_TOPMOST for message-only windows. user32/tests: Check that message-only windows ignore WS_EX_TOPMOST.
From: Giovanni Mascellani gmascellani@codeweavers.com
libOVR brings a message window topmost claiming that this way it receives WM_DEVICECHANGE faster. Currently, in Wine, this causes a WM_KILLFOCUS to be sent to the actual topmost window, which in turn causes "Shantae: Risky's Revenge" to minimize. The effect is that the game automatically minimizes as soon as it is launched, which is incorrect. --- dlls/user32/tests/win.c | 128 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index c2da0b04dad..79b493c3289 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -8919,6 +8919,133 @@ static void test_hwnd_message(void) DestroyWindow(hwnd); }
+static HWND message_window_topmost_hwnd_msg = NULL; +static BOOL message_window_topmost_received_killfocus; + +static LRESULT WINAPI message_window_topmost_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + todo_wine_if(hwnd == message_window_topmost_hwnd_msg) + ok(hwnd != message_window_topmost_hwnd_msg, "Received message %u for message-only window %p\n", msg, hwnd); + if (msg == WM_KILLFOCUS) message_window_topmost_received_killfocus = TRUE; + return DefWindowProcW(hwnd, msg, wparam, lparam); +} + + +static void test_message_window_topmost(void) +{ + /* All SWP_* flags except SWP_NOZORDER, which has a different effect. */ + const UINT swp_flags = SWP_ASYNCWINDOWPOS | SWP_DEFERERASE | SWP_DRAWFRAME | SWP_FRAMECHANGED + | SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOOWNERZORDER + | SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_SHOWWINDOW; + /* Same as above, except the flags that cause + * ERROR_INVALID_PARAMETER to be returned by DeferWindowPos(). */ + const UINT dwp_flags = SWP_DRAWFRAME | SWP_FRAMECHANGED + | SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOOWNERZORDER + | SWP_NOREDRAW | SWP_NOSIZE | SWP_SHOWWINDOW; + HWND hwnd, hwnd_msg; + HDWP hdwp; + RECT rect; + BOOL ret; + MSG msg; + + hwnd = CreateWindowW(L"static", L"main window", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 210, 211, 212, 213, NULL, NULL, GetModuleHandleW(NULL), NULL); + ok(!!hwnd, "Cannot create main window\n"); + flush_events(TRUE); + SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)message_window_topmost_proc); + + hwnd_msg = CreateWindowW(L"static", L"message window", 0, + 220, 221, 222, 223, HWND_MESSAGE, NULL, GetModuleHandleW(NULL), NULL); + ok(!!hwnd_msg, "Cannot create message window\n"); + flush_events(TRUE); + SetWindowLongPtrW(hwnd_msg, GWLP_WNDPROC, (LONG_PTR)message_window_topmost_proc); + + ret = GetWindowRect(hwnd_msg, &rect); + ok(ret, "Unexpected failure when calling GetWindowRect()\n"); + ok(rect.left == 220 && rect.top == 221 && rect.right == 220 + 222 && rect.bottom == 221 + 223, + "Unexpected rectangle %s\n", wine_dbgstr_rect(&rect)); + + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + message_window_topmost_hwnd_msg = hwnd_msg; + + SetLastError(0xdeadbeef); + + ret = SetWindowPos(hwnd_msg, HWND_TOPMOST, 230, 231, 232, 233, 0); + ok(ret, "Unexpected failure when calling SetWindowPos()\n"); + + ret = SetWindowPos(hwnd_msg, HWND_TOPMOST, 234, 235, 236, 237, swp_flags); + ok(ret, "Unexpected failure when calling SetWindowPos()\n"); + + ret = SetWindowPos(hwnd_msg, HWND_NOTOPMOST, 240, 241, 242, 243, 0); + ok(ret, "Unexpected failure when calling SetWindowPos()\n"); + + ret = SetWindowPos(hwnd_msg, HWND_NOTOPMOST, 244, 245, 246, 247, swp_flags); + ok(ret, "Unexpected failure when calling SetWindowPos()\n"); + + hdwp = BeginDeferWindowPos(4); + ok(!!hdwp, "Unexpected failure when calling BeginDeferWindowPos()\n"); + + hdwp = DeferWindowPos(hdwp, hwnd_msg, HWND_TOPMOST, 250, 251, 252, 253, 0); + ok(!!hdwp, "Unexpected failure when calling DeferWindowPos()\n"); + + hdwp = DeferWindowPos(hdwp, hwnd_msg, HWND_TOPMOST, 254, 255, 256, 257, dwp_flags); + ok(!!hdwp, "Unexpected failure when calling DeferWindowPos()\n"); + + hdwp = DeferWindowPos(hdwp, hwnd_msg, HWND_NOTOPMOST, 260, 261, 262, 263, 0); + ok(!!hdwp, "Unexpected failure when calling DeferWindowPos()\n"); + + hdwp = DeferWindowPos(hdwp, hwnd_msg, HWND_NOTOPMOST, 264, 265, 266, 267, dwp_flags); + ok(!!hdwp, "Unexpected failure when calling DeferWindowPos()\n"); + + ret = EndDeferWindowPos(hdwp); + ok(ret, "Unexpected failure when calling EndDeferWindowPos()\n"); + + todo_wine ok(GetLastError() == 0xdeadbeef, "Last error unexpectedly set to %#lx\n", GetLastError()); + + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + message_window_topmost_hwnd_msg = NULL; + + ret = GetWindowRect(hwnd_msg, &rect); + ok(ret, "Unexpected failure when calling GetWindowRect()\n"); + todo_wine ok(rect.left == 220 && rect.top == 221 && rect.right == 220 + 222 && rect.bottom == 221 + 223, + "Unexpected rectangle %s\n", wine_dbgstr_rect(&rect)); + + todo_wine + ok(!message_window_topmost_received_killfocus, "Received WM_KILLFOCUS\n"); + message_window_topmost_received_killfocus = FALSE; + + ret = SetWindowPos(hwnd_msg, HWND_TOPMOST, 230, 231, 232, 233, SWP_NOZORDER); + ok(ret, "Unexpected failure when calling SetWindowPos()\n"); + + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + todo_wine_if(!message_window_topmost_received_killfocus) + ok(message_window_topmost_received_killfocus, "Did not receive WM_KILLFOCUS\n"); + + ret = GetWindowRect(hwnd_msg, &rect); + ok(ret, "Unexpected failure when calling GetWindowRect()\n"); + ok(rect.left == 230 && rect.top == 231 && rect.right == 230 + 232 && rect.bottom == 231 + 233, + "Unexpected rectangle %s\n", wine_dbgstr_rect(&rect)); + + ok(DestroyWindow(hwnd_msg), "Cannot destroy main window\n"); + ok(DestroyWindow(hwnd), "Cannot destroy message window\n"); +} + + static void test_layered_window(void) { HWND hwnd, child; @@ -13326,6 +13453,7 @@ START_TEST(win) test_thick_child_size(hwndMain); test_fullscreen(); test_hwnd_message(); + test_message_window_topmost(); test_nonclient_area(hwndMain); test_params(); test_GetWindowModuleFileName();
From: Giovanni Mascellani gmascellani@codeweavers.com
--- dlls/user32/tests/win.c | 7 ++----- dlls/win32u/window.c | 10 ++++++---- 2 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 79b493c3289..160d85f2190 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -8924,7 +8924,6 @@ static BOOL message_window_topmost_received_killfocus;
static LRESULT WINAPI message_window_topmost_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - todo_wine_if(hwnd == message_window_topmost_hwnd_msg) ok(hwnd != message_window_topmost_hwnd_msg, "Received message %u for message-only window %p\n", msg, hwnd); if (msg == WM_KILLFOCUS) message_window_topmost_received_killfocus = TRUE; return DefWindowProcW(hwnd, msg, wparam, lparam); @@ -9005,7 +9004,7 @@ static void test_message_window_topmost(void) ret = EndDeferWindowPos(hdwp); ok(ret, "Unexpected failure when calling EndDeferWindowPos()\n");
- todo_wine ok(GetLastError() == 0xdeadbeef, "Last error unexpectedly set to %#lx\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "Last error unexpectedly set to %#lx\n", GetLastError());
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { @@ -9017,10 +9016,9 @@ static void test_message_window_topmost(void)
ret = GetWindowRect(hwnd_msg, &rect); ok(ret, "Unexpected failure when calling GetWindowRect()\n"); - todo_wine ok(rect.left == 220 && rect.top == 221 && rect.right == 220 + 222 && rect.bottom == 221 + 223, + ok(rect.left == 220 && rect.top == 221 && rect.right == 220 + 222 && rect.bottom == 221 + 223, "Unexpected rectangle %s\n", wine_dbgstr_rect(&rect));
- todo_wine ok(!message_window_topmost_received_killfocus, "Received WM_KILLFOCUS\n"); message_window_topmost_received_killfocus = FALSE;
@@ -9033,7 +9031,6 @@ static void test_message_window_topmost(void) DispatchMessageW(&msg); }
- todo_wine_if(!message_window_topmost_received_killfocus) ok(message_window_topmost_received_killfocus, "Did not receive WM_KILLFOCUS\n");
ret = GetWindowRect(hwnd_msg, &rect); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 3482679b97a..272d8926be2 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -3751,10 +3751,12 @@ BOOL set_window_pos( WINDOWPOS *winpos, int parent_x, int parent_y ) if (winpos->hwndInsertAfter == (HWND)0xffff) winpos->hwndInsertAfter = HWND_TOPMOST; else if (winpos->hwndInsertAfter == (HWND)0xfffe) winpos->hwndInsertAfter = HWND_NOTOPMOST;
- if (!(winpos->hwndInsertAfter == HWND_TOP || - winpos->hwndInsertAfter == HWND_BOTTOM || - winpos->hwndInsertAfter == HWND_TOPMOST || - winpos->hwndInsertAfter == HWND_NOTOPMOST)) + if (winpos->hwndInsertAfter == HWND_TOPMOST || winpos->hwndInsertAfter == HWND_NOTOPMOST) + { + HWND parent = NtUserGetAncestor( NtUserGetAncestor( winpos->hwnd, GA_ROOT ), GA_PARENT ); + if (parent == get_hwnd_message_parent()) return TRUE; + } + else if (winpos->hwndInsertAfter != HWND_TOP && winpos->hwndInsertAfter != HWND_BOTTOM) { HWND parent = NtUserGetAncestor( winpos->hwnd, GA_PARENT ); HWND insertafter_parent = NtUserGetAncestor( winpos->hwndInsertAfter, GA_PARENT );
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=149969
Your paranoid android.
=== w10pro64 (32 bit report) ===
user32: win.c:3851: Test failed: GetForegroundWindow returned 000202C8 win.c:3782: Test failed: SetForegroundWindow failed, error 0 win.c:3785: Test failed: GetForegroundWindow returned 000202C8 win.c:3822: Test failed: GetForegroundWindow returned 000202C8 win.c:3910: Test failed: GetActiveWindow() = 000201A8 win.c:3914: Test failed: GetFocus() = 00000000 win.c:3917: Test failed: GetFocus() = 00000000
=== w1064_2qxl (64 bit report) ===
user32: win.c:4615: Test failed: hwnd 000000000003003E/000000000003003E message 0200 win.c:4619: Test failed: hwnd 000000000003003E/000000000003003E message 0201 win.c:4628: Test failed: hwnd 0000000000140032/0000000000140032 message 0202 win.c:4631: Test failed: hwnd 0000000000140032/0000000000140032 message 0201
=== w10pro64_ja (64 bit report) ===
user32: win.c:214: Test failed: didn't get start_event
=== debian11 (32 bit hi:IN report) ===
user32: win.c:4070: Test failed: Expected active window 00B500F0, got 00000000. win.c:4071: Test failed: Expected focus window 00B500F0, got 00000000.
=== debian11 (32 bit ja:JP report) ===
user32: win.c:4070: Test failed: Expected active window 00B500F0, got 00000000. win.c:4071: Test failed: Expected focus window 00B500F0, got 00000000.
=== debian11b (64 bit WoW report) ===
user32: input.c:4305: Test succeeded inside todo block: button_down_hwnd_todo 1: got MSG_TEST_WIN hwnd 00000000015700FA, msg WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032
Sorry, I hadn't noticed the review. I have included all your suggestions, hopefully the MR is better now. Thanks!
This merge request was approved by Rémi Bernon.