I'm resending these, with the tests also run in cross-process mode (in addition to the same-process/cross-thread calls). The results are the same in both cases, and it exposes an inversion in Wine which can then cause various focus inconsistencies.
PATCH 1/8 is not strictly necessary to make the test run well on testbot, and can possibly be dropped, but it helped me when running the test in a VM, especially when multiple processes are involved (the new process windows couldn't get foreground and were just flashing in the taskbar instead).
The remaining todo_wine after the series are caused by the same kind of behavior as is fixed by PATCH 8/8, where WM_KILLFOCUS/WM_SETFOCUS messages aren't sent because the window already has focus. As foreground was temporarily stolen by another thread they should still apparently be sent. The logic was a little bit more complicated so I left it aside.
The remaining focus issues with Wine are mostly caused by:
* asynchronous SetForegroundWindow consequences, with user actions interleaved, causing events coming late to steal foreground that was already lost,
* threads not checking their messages for a while, causing a delay between host focus changes, and wineserver focus state updates.
My plan, to fix those, would be to:
* use timestamps to order SetForegroundWindow requests and their corresponding host events, and then ignore out-of-order events,
* track the host focus state globally, for instance from explorer, so that threads that do not check their messages for a while will not make wine focus state inconsistent.
This inversion makes the whole thing useless, as threads can steal foreground from each other, as they process the internal WM_WINE_SETACTIVEWINDOW messages in the wrong order, so it has to be fixed first.
Cheers,
Rémi Bernon (8): user32/tests: Attach a debugger to help SetForegroundWindow suceed. user32/tests: Add concurrency tests for SetForegroundWindow. user32: Do not deactivate if thread is foreground. user32: Call set_active_window from internal handler. server: Allow filtering internal sent messages. user32: Add discard_internal parameter to peek_message. user32: Discard internal messages in set_active_window. user32: Send WM_NCACTIVATE on SetForegroundWindow call.
dlls/user32/focus.c | 17 +- dlls/user32/message.c | 34 +++- dlls/user32/tests/win.c | 388 +++++++++++++++++++++++++++++++------ dlls/user32/user_private.h | 2 + server/queue.c | 9 +- 5 files changed, 374 insertions(+), 76 deletions(-)
This is not strictly required and it does not even work all the time, although MSDN says it should, but it helps, especially when multiple processes are creating windows.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/tests/win.c | 50 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 843da8900f1..15205b9eb6c 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -11896,6 +11896,53 @@ static void test_other_process_window(const char *argv0) DestroyWindow(hwnd); }
+static void start_debugger(int argc, char **argv) +{ + HANDLE debug_ready; + BOOL ret; + char event_name[MAX_PATH]; + + if (argc == 4 && !strcmp(argv[2], "debugger")) + { + DWORD pid; + DEBUG_EVENT de; + + sprintf(event_name, "test_debug_%s", argv[3]); + debug_ready = OpenEventA(EVENT_ALL_ACCESS, FALSE, event_name); + ok(debug_ready != 0, "OpenEventA failed\n"); + + sscanf(argv[3], "%x", &pid); + ret = DebugActiveProcess(pid); + ok(ret, "DebugActiveProcess failed, last error: %#x.\n", GetLastError()); + + SetEvent(debug_ready); + ok(ret, "SetEvent failed, last error %#x.\n", GetLastError()); + CloseHandle(debug_ready); + + while (WaitForDebugEvent(&de, INFINITE)) + ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); + + exit(0); + } + else + { + PROCESS_INFORMATION pi; + STARTUPINFOA si = {sizeof(si)}; + char cmd[MAX_PATH]; + + sprintf(event_name, "test_debug_%x", GetCurrentProcessId()); + debug_ready = CreateEventA(NULL, FALSE, FALSE, event_name); + ok(debug_ready != 0, "CreateEventA failed\n"); + + sprintf(cmd, "%s win debugger %x", argv[0], GetCurrentProcessId()); + ret = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "CreateProcessA failed, last error: %#x.\n", GetLastError()); + + WaitForSingleObject(debug_ready, INFINITE); + CloseHandle(debug_ready); + } +} + START_TEST(win) { char **argv; @@ -11920,6 +11967,9 @@ START_TEST(win) pAdjustWindowRectExForDpi = (void *)GetProcAddress( user32, "AdjustWindowRectExForDpi" ); pSystemParametersInfoForDpi = (void *)GetProcAddress( user32, "SystemParametersInfoForDpi" );
+ /* attaching a debugger to the current process will make sure SetForegroundWindow always succeed */ + start_debugger(argc, argv); + if (argc == 4) { HWND hwnd;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77164
Your paranoid android.
=== w1064v1507 (32 bit report) ===
user32: win.c:9478: Test failed: Timed out waiting for the child process
=== w1064v1809 (32 bit report) ===
user32: win.c:781: Test failed: rects do not match (3,26)-(157,26) / (0,0)-(0,0) win.c:3849: Test failed: hwnd 000200E4 message 0738
=== w1064v1809_2scr (32 bit report) ===
user32: win.c:3849: Test failed: hwnd 00020252 message 0738
=== w1064v1809_ja (32 bit report) ===
user32: win.c:3724: Test failed: message 0738 available win.c:3849: Test failed: hwnd 000202F2 message 7fff win.c:3928: Test failed: hwnd 000202F2/00090354 message 7fff win.c:3931: Test failed: hwnd 000202F2/00090354 message 7fff
=== w1064v1809_zh_CN (32 bit report) ===
user32: win.c:3849: Test failed: hwnd 0003018A message 0282 win.c:3928: Test failed: hwnd 0003018A/000E03DE message 0282 win.c:3931: Test failed: hwnd 0003018A/000E03DE message 0282
=== w1064v1809 (64 bit report) ===
user32: win.c:781: Test failed: rects do not match (3,26)-(157,26) / (0,0)-(0,0)
=== debiant (32 bit Chinese:China report) ===
user32: win.c:10147: Test failed: GetActiveWindow() = 00000000 win.c:10147: Test failed: GetFocus() = 00000000 win.c:10149: Test failed: Expected foreground window 00020052, got 00E000A8 win.c:10152: Test failed: Received WM_ACTIVATEAPP(0), did not expect it. win.c:10159: Test failed: Expected foreground window 00020052, got 00000000 win.c:10161: Test failed: GetActiveWindow() = 00000000 win.c:10161: Test failed: GetFocus() = 00000000 win.c:10169: Test failed: Received WM_ACTIVATEAPP(1), did not expect it.
When calling SetForegroundWindow for a window in another thread, an internal message is posted to the thread's message queue.
If this thread then calls SetForegroundWindow before processing its messages it will execute the corresponding set_active_window first, but then overwrite the active window later, when processing its internal messages.
This is not always the correct behavior and these tests help determine what should actually be done in various situations.
This aims to check the following sequences, with A being a separate thread or a separate process that created three windows, and B being the main test thread with some windows initially in background:
* window A0, A1, or A2 is foreground, then: * B sets foreground to window A0 * A sets foreground to window A1
As well as these sequences where foreground is also temporarily switched to window B0:
* window A0, A1, or A2 is foreground, then: * B sets foreground to window B0 * B sets foreground to window A0 * B sets foreground to window B0 * A sets foreground to window A1
In addition, we also do tests with additional SetActiveWindow / SetFocus calls to check their influence.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/tests/win.c | 338 +++++++++++++++++++++++++++++++++------- 1 file changed, 278 insertions(+), 60 deletions(-)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 15205b9eb6c..0a16a0d31ce 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -3240,40 +3240,294 @@ static void test_SetActiveWindow(HWND hwnd) DestroyWindow(hwnd2); }
-struct create_window_thread_params +static int test_sfw_msg_count; + +static LRESULT WINAPI test_sfw_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - HWND window; - HANDLE window_created; - HANDLE test_finished; + switch (msg) + { + case WM_NCACTIVATE: + case WM_ACTIVATE: + case WM_SETFOCUS: + case WM_KILLFOCUS: + test_sfw_msg_count++; + break; + } + + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +struct test_sfw_test_desc +{ + int initial_window; + BOOL steal_foreground; + BOOL call_set_active_window; + BOOL call_set_focus; + + BOOL todo_msgcount_before_set_foreground; + int msgcount_before_set_foreground; + BOOL todo_msgcount_after_set_foreground; + int msgcount_after_set_foreground; + BOOL todo_msgcount_after_peek_message; + int msgcount_after_peek_message; + BOOL todo_expected_window; + int expected_window; +}; + +static struct test_sfw_test_desc test_sfw_tests[] = { + {1, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 0, FALSE, 6, FALSE, 0}, + {1, TRUE, FALSE, FALSE, FALSE, 0, TRUE, 1, TRUE, 6, TRUE, 0}, + {1, FALSE, TRUE, FALSE, FALSE, 0, FALSE, 0, FALSE, 6, FALSE, 0}, + {1, TRUE, TRUE, FALSE, FALSE, 0, TRUE, 1, TRUE, 6, TRUE, 0}, + {1, FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, FALSE, 6, FALSE, 0}, + {1, TRUE, FALSE, TRUE, FALSE, 0, TRUE, 1, TRUE, 6, TRUE, 0}, + + {2, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 6, TRUE, 0, TRUE, 1}, + {2, TRUE, FALSE, FALSE, FALSE, 0, FALSE, 6, TRUE, 0, TRUE, 1}, + {2, FALSE, TRUE, FALSE, FALSE, 6, FALSE, 0, TRUE, 0, TRUE, 1}, + {2, TRUE, TRUE, FALSE, FALSE, 6, TRUE, 1, TRUE, 6, TRUE, 0}, + {2, FALSE, FALSE, TRUE, TRUE, 8, FALSE, 0, TRUE, 0, TRUE, 1}, + {2, TRUE, FALSE, TRUE, TRUE, 8, TRUE, 1, TRUE, 6, TRUE, 0}, + + {0, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 6, FALSE, 0, FALSE, 1}, + {0, TRUE, FALSE, FALSE, FALSE, 0, FALSE, 6, TRUE, 0, TRUE, 1}, + {0, FALSE, TRUE, FALSE, FALSE, 6, FALSE, 0, FALSE, 0, FALSE, 1}, + {0, TRUE, TRUE, FALSE, FALSE, 6, TRUE, 1, FALSE, 6, FALSE, 0}, + {0, FALSE, FALSE, TRUE, TRUE, 8, FALSE, 0, FALSE, 0, FALSE, 1}, + {0, TRUE, FALSE, TRUE, TRUE, 8, TRUE, 1, FALSE, 6, FALSE, 0}, };
-static DWORD WINAPI create_window_thread(void *param) +static DWORD WINAPI test_sfw_thread(void *param) { - struct create_window_thread_params *p = param; + HANDLE test_sfw_ready, test_sfw_start, test_sfw_done; + WNDPROC wndprocs[3]; + HWND windows[3]; DWORD res; BOOL ret; + MSG msg; + int i;
- p->window = CreateWindowA("static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, 0, 0, 0, 0); + test_sfw_ready = OpenEventA(EVENT_ALL_ACCESS, FALSE, "test_sfw_ready"); + test_sfw_start = OpenEventA(EVENT_ALL_ACCESS, FALSE, "test_sfw_start"); + test_sfw_done = OpenEventA(EVENT_ALL_ACCESS, FALSE, "test_sfw_done");
- ret = SetEvent(p->window_created); + windows[1] = CreateWindowA("static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, 0, 0, 0, 0); + windows[2] = CreateWindowA("static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, 0, 0, 0, 0); + windows[0] = CreateWindowA("static", "test_sfw_window", WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, 0, 0, 0, 0); + trace("window[0]:%p windows[1]:%p windows[2]:%p\n", windows[0], windows[1], windows[2]); + + ret = SetEvent(test_sfw_ready); ok(ret, "SetEvent failed, last error %#x.\n", GetLastError());
- res = WaitForSingleObject(p->test_finished, INFINITE); + /* wait for the initial state to be clean */ + + res = WaitForSingleObject(test_sfw_start, INFINITE); ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError()); + ret = ResetEvent(test_sfw_start); + ok(ret, "ResetEvent failed, last error %#x.\n", GetLastError()); + + for (i = 0; i < ARRAY_SIZE(windows); ++i) + wndprocs[i] = (WNDPROC)SetWindowLongPtrA(windows[i], GWLP_WNDPROC, (LONG_PTR)test_sfw_wndproc); + + flush_events(TRUE); + + for (i = 0; i < ARRAY_SIZE(test_sfw_tests); ++i) + { + struct test_sfw_test_desc *test = test_sfw_tests + i; + HWND initial_window = windows[test->initial_window]; + HWND expected_window = windows[test->expected_window]; + trace("running test %d\n", i); + + SetForegroundWindow(initial_window); + flush_events(TRUE); + check_wnd_state(initial_window, initial_window, initial_window, 0); + + ret = SetEvent(test_sfw_ready); + ok(ret, "SetEvent failed, last error %#x.\n", GetLastError()); + + res = WaitForSingleObject(test_sfw_start, INFINITE); + ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError()); + ret = ResetEvent(test_sfw_start); + ok(ret, "ResetEvent failed, last error %#x.\n", GetLastError()); + + test_sfw_msg_count = 0; + if (test->call_set_active_window) + SetActiveWindow(windows[1]); + if (test->call_set_focus) + SetFocus(windows[1]); + todo_wine_if(test->todo_msgcount_before_set_foreground) + ok(test_sfw_msg_count == test->msgcount_before_set_foreground, + "%d: Unexpected number of messages received before SetForegroundWindow: %d\n", i, test_sfw_msg_count); + + test_sfw_msg_count = 0; + SetForegroundWindow(windows[1]); + todo_wine_if(test->todo_msgcount_after_set_foreground) + ok(test_sfw_msg_count == test->msgcount_after_set_foreground, + "%d: Unexpected number of messages received after SetForegroundWindow: %d\n", i, test_sfw_msg_count); + + test_sfw_msg_count = 0; + ok(GetForegroundWindow() == windows[1], "GetForegroundWindow() returned %p\n", GetForegroundWindow()); + ok(GetActiveWindow() == windows[1], "GetActiveWindow() returned %p\n", GetActiveWindow()); + ok(GetFocus() == windows[1], "GetFocus() returned %p\n", GetFocus()); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + todo_wine_if(test->todo_msgcount_after_peek_message) + ok(test_sfw_msg_count == test->msgcount_after_peek_message, + "%d: Unexpected number of messages received after PeekMessageA: %d\n", i, test_sfw_msg_count); + + todo_wine_if(test->todo_expected_window) + ok(GetForegroundWindow() == expected_window, "%d: GetForegroundWindow() returned %p\n", i, GetForegroundWindow()); + todo_wine_if(test->todo_expected_window) + ok(GetActiveWindow() == expected_window, "%d: GetActiveWindow() returned %p\n", i, GetActiveWindow()); + todo_wine_if(test->todo_expected_window) + ok(GetFocus() == expected_window, "%d: GetFocus() returned %p\n", i, GetFocus()); + + res = WaitForSingleObject(test_sfw_done, INFINITE); + ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError()); + ret = ResetEvent(test_sfw_done); + ok(ret, "ResetEvent failed, last error %#x.\n", GetLastError()); + } + + for (i = 0; i < ARRAY_SIZE(windows); ++i) + SetWindowLongPtrA(windows[i], GWLP_WNDPROC, (LONG_PTR)wndprocs[i]); + + for (i = 0; i < ARRAY_SIZE(windows); ++i) + DestroyWindow(windows[i]); + + CloseHandle(test_sfw_ready); + CloseHandle(test_sfw_start); + CloseHandle(test_sfw_done);
- DestroyWindow(p->window); return 0; }
-static void test_SetForegroundWindow(HWND hwnd) +static void test_sfw_multi_thread(const char *argv0, HWND hwnd, BOOL cross_process) { - struct create_window_thread_params thread_params; - HANDLE thread; + PROCESS_INFORMATION pi; + STARTUPINFOA si = {sizeof(si)}; + HANDLE thread = 0; + HANDLE test_sfw_ready, test_sfw_start, test_sfw_done; DWORD res, tid; - BOOL ret; + HWND test_sfw_window; + char cmd[MAX_PATH]; HWND hwnd2; - MSG msg; LONG style; + BOOL ret; + MSG msg; + int i; + + hwnd2 = CreateWindowA("static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, 0, 0, 0, 0); + check_wnd_state(hwnd2, hwnd2, hwnd2, 0); + + test_sfw_ready = CreateEventA(NULL, FALSE, FALSE, "test_sfw_ready"); + ok(!!test_sfw_ready, "CreateEvent failed, last error %#x.\n", GetLastError()); + test_sfw_start = CreateEventA(NULL, FALSE, FALSE, "test_sfw_start"); + ok(!!test_sfw_start, "CreateEvent failed, last error %#x.\n", GetLastError()); + test_sfw_done = CreateEventA(NULL, FALSE, FALSE, "test_sfw_done"); + ok(!!test_sfw_done, "CreateEvent failed, last error %#x.\n", GetLastError()); + + if (cross_process) + { + sprintf(cmd, "%s win test_sfw", argv0); + ret = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "CreateProcessA failed, last error: %#x.\n", GetLastError()); + } + else + { + thread = CreateThread(NULL, 0, test_sfw_thread, NULL, 0, &tid); + ok(!!thread, "Failed to create thread, last error %#x.\n", GetLastError()); + } + + res = WaitForSingleObject(test_sfw_ready, INFINITE); + ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError()); + ret = ResetEvent(test_sfw_ready); + ok(ret, "ResetEvent failed, last error %#x.\n", GetLastError()); + + test_sfw_window = FindWindowA("static", "test_sfw_window"); + ok(test_sfw_window != NULL, "FindWindowA failed to find test window, last error %#x\n", GetLastError()); + check_wnd_state(hwnd2, test_sfw_window, hwnd2, 0); + + /* ensure initial state is consistent, with hwnd as active / foreground / focus window */ + + SetForegroundWindow(hwnd2); + check_wnd_state(hwnd2, hwnd2, hwnd2, 0); + + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + if (0) check_wnd_state(hwnd2, hwnd2, hwnd2, 0); + + /* FIXME: these tests are failing because of a race condition + * between internal process focus state applied immediately and + * X11 focus message coming late */ + todo_wine_if(!cross_process) + ok(GetActiveWindow() == hwnd2, "Expected active window %p, got %p.\n", hwnd2, GetActiveWindow()); + todo_wine_if(!cross_process) + ok(GetFocus() == hwnd2, "Expected focus window %p, got %p.\n", hwnd2, GetFocus()); + + SetForegroundWindow(hwnd); + check_wnd_state(hwnd, hwnd, hwnd, 0); + style = GetWindowLongA(hwnd2, GWL_STYLE) | WS_CHILD; + ok(SetWindowLongA(hwnd2, GWL_STYLE, style), "SetWindowLong failed\n"); + ok(SetForegroundWindow(hwnd2), "SetForegroundWindow failed\n"); + check_wnd_state(hwnd2, hwnd2, hwnd2, 0); + + SetForegroundWindow(hwnd); + check_wnd_state(hwnd, hwnd, hwnd, 0); + ok(SetWindowLongA(hwnd2, GWL_STYLE, style & (~WS_POPUP)), "SetWindowLong failed\n"); + ok(!SetForegroundWindow(hwnd2), "SetForegroundWindow failed\n"); + check_wnd_state(hwnd, hwnd, hwnd, 0); + + res = SetEvent(test_sfw_start); + ok(res, "SetEvent failed, last error %#x.\n", GetLastError()); + + /* now run the tests */ + + for (i = 0; i < ARRAY_SIZE(test_sfw_tests); ++i) + { + struct test_sfw_test_desc *test = test_sfw_tests + i; + + while (MsgWaitForMultipleObjects(1, &test_sfw_ready, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0) + { + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE)) + DispatchMessageA(&msg); + } + + ret = ResetEvent(test_sfw_ready); + ok(ret, "ResetEvent failed, last error %#x.\n", GetLastError()); + + if (test->steal_foreground) SetForegroundWindow(hwnd); + SetForegroundWindow(test_sfw_window); + if (test->steal_foreground) SetForegroundWindow(hwnd); + + res = SetEvent(test_sfw_start); + ok(res, "SetEvent failed, last error %#x.\n", GetLastError()); + + ret = SetEvent(test_sfw_done); + ok(res, "SetEvent failed, last error %#x.\n", GetLastError()); + } + + if (cross_process) + { + wait_child_process(pi.hProcess); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + else + { + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + } + + CloseHandle(test_sfw_start); + CloseHandle(test_sfw_done); + CloseHandle(test_sfw_ready); + + DestroyWindow(hwnd2); + flush_events(TRUE); +} + +static void test_SetForegroundWindow(const char *argv0, HWND hwnd) +{ + BOOL ret; + HWND hwnd2;
flush_events( TRUE ); ShowWindow(hwnd, SW_HIDE); @@ -3347,50 +3601,8 @@ static void test_SetForegroundWindow(HWND hwnd) DestroyWindow(hwnd2); check_wnd_state(hwnd, hwnd, hwnd, 0);
- hwnd2 = CreateWindowA("static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, 0, 0, 0, 0); - check_wnd_state(hwnd2, hwnd2, hwnd2, 0); - - thread_params.window_created = CreateEventW(NULL, FALSE, FALSE, NULL); - ok(!!thread_params.window_created, "CreateEvent failed, last error %#x.\n", GetLastError()); - thread_params.test_finished = CreateEventW(NULL, FALSE, FALSE, NULL); - ok(!!thread_params.test_finished, "CreateEvent failed, last error %#x.\n", GetLastError()); - thread = CreateThread(NULL, 0, create_window_thread, &thread_params, 0, &tid); - ok(!!thread, "Failed to create thread, last error %#x.\n", GetLastError()); - res = WaitForSingleObject(thread_params.window_created, INFINITE); - ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError()); - check_wnd_state(hwnd2, thread_params.window, hwnd2, 0); - - SetForegroundWindow(hwnd2); - check_wnd_state(hwnd2, hwnd2, hwnd2, 0); - - while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); - if (0) check_wnd_state(hwnd2, hwnd2, hwnd2, 0); - - /* FIXME: these tests are failing because of a race condition - * between internal focus state applied immediately and X11 focus - * message coming late */ - todo_wine ok(GetActiveWindow() == hwnd2, "Expected active window %p, got %p.\n", hwnd2, GetActiveWindow()); - todo_wine ok(GetFocus() == hwnd2, "Expected focus window %p, got %p.\n", hwnd2, GetFocus()); - - SetForegroundWindow(hwnd); - check_wnd_state(hwnd, hwnd, hwnd, 0); - style = GetWindowLongA(hwnd2, GWL_STYLE) | WS_CHILD; - ok(SetWindowLongA(hwnd2, GWL_STYLE, style), "SetWindowLong failed\n"); - ok(SetForegroundWindow(hwnd2), "SetForegroundWindow failed\n"); - check_wnd_state(hwnd2, hwnd2, hwnd2, 0); - - SetForegroundWindow(hwnd); - check_wnd_state(hwnd, hwnd, hwnd, 0); - ok(SetWindowLongA(hwnd2, GWL_STYLE, style & (~WS_POPUP)), "SetWindowLong failed\n"); - ok(!SetForegroundWindow(hwnd2), "SetForegroundWindow failed\n"); - check_wnd_state(hwnd, hwnd, hwnd, 0); - - SetEvent(thread_params.test_finished); - WaitForSingleObject(thread, INFINITE); - CloseHandle(thread_params.test_finished); - CloseHandle(thread_params.window_created); - CloseHandle(thread); - DestroyWindow(hwnd2); + test_sfw_multi_thread(argv0, hwnd, FALSE); + test_sfw_multi_thread(argv0, hwnd, TRUE); }
static WNDPROC old_button_proc; @@ -11993,6 +12205,12 @@ START_TEST(win) return; }
+ if (argc == 3 && !strcmp(argv[2], "test_sfw")) + { + test_sfw_thread(NULL); + return; + } + if (!RegisterWindowClasses()) assert(0);
hwndMain = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window", @@ -12090,7 +12308,7 @@ START_TEST(win) test_Expose(); test_layered_window();
- test_SetForegroundWindow(hwndMain); + test_SetForegroundWindow(argv[0], hwndMain); test_handles( hwndMain ); test_winregion(); test_map_points();
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77165
Your paranoid android.
=== w1064v1507 (32 bit report) ===
user32: win.c:9690: Test failed: Timed out waiting for the child process
=== w1064v1809 (32 bit report) ===
user32: win.c:781: Test failed: rects do not match (3,26)-(157,26) / (0,0)-(0,0)
=== w1064v1809_2scr (32 bit report) ===
user32: win.c:781: Test failed: rects do not match (3,26)-(157,26) / (0,0)-(0,0) win.c:4061: Test failed: hwnd 000202AA message 0738
=== w1064v1809_ja (32 bit report) ===
user32: win.c:3936: Test failed: message 0738 available win.c:4061: Test failed: hwnd 00040062 message 7fff win.c:4140: Test failed: hwnd 00040062/000202DA message 7fff win.c:4143: Test failed: hwnd 00040062/000202DA message 7fff
=== w1064v1809_zh_CN (32 bit report) ===
user32: win.c:4061: Test failed: hwnd 0001038A message 0282 win.c:4140: Test failed: hwnd 0001038A/000A03DE message 0282 win.c:4143: Test failed: hwnd 0001038A/000A03DE message 0282
=== w1064v1809 (64 bit report) ===
user32: win.c:781: Test failed: rects do not match (3,26)-(157,26) / (0,0)-(0,0) win.c:4061: Test failed: hwnd 00000000000200E4 message 0738
=== debiant (32 bit Japanese:Japan report) ===
user32: win.c:10378: Test failed: Expected foreground window 00020052, got 00280042 win.c:10380: Test failed: GetActiveWindow() = 00000000 win.c:10380: Test failed: GetFocus() = 00000000 win.c:10381: Test failed: Received WM_ACTIVATEAPP(1), did not expect it. win.c:10382: Test failed: Received WM_ACTIVATEAPP(0), did not expect it. win.c:10390: Test failed: Expected foreground window 00020052, got 00000000 win.c:10392: Test failed: GetActiveWindow() = 00000000 win.c:10392: Test failed: GetFocus() = 00000000 win.c:10400: Test failed: Received WM_ACTIVATEAPP(1), did not expect it.
Instead of only checking that the window is foreground.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/message.c | 2 +- dlls/user32/tests/win.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/message.c b/dlls/user32/message.c index aadec28b559..b02142991cd 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -1873,7 +1873,7 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR if (is_desktop_window( hwnd )) return 0; return WIN_SetStyle(hwnd, wparam, lparam); case WM_WINE_SETACTIVEWINDOW: - if (!wparam && GetForegroundWindow() == hwnd) return 0; + if (!wparam && GetWindowThreadProcessId( GetForegroundWindow(), NULL ) == GetCurrentThreadId()) return 0; return (LRESULT)SetActiveWindow( (HWND)wparam ); case WM_WINE_KEYBOARD_LL_HOOK: case WM_WINE_MOUSE_LL_HOOK: diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 0a16a0d31ce..9f082d16330 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -3276,18 +3276,18 @@ struct test_sfw_test_desc
static struct test_sfw_test_desc test_sfw_tests[] = { {1, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 0, FALSE, 6, FALSE, 0}, - {1, TRUE, FALSE, FALSE, FALSE, 0, TRUE, 1, TRUE, 6, TRUE, 0}, + {1, TRUE, FALSE, FALSE, FALSE, 0, TRUE, 1, FALSE, 6, FALSE, 0}, {1, FALSE, TRUE, FALSE, FALSE, 0, FALSE, 0, FALSE, 6, FALSE, 0}, - {1, TRUE, TRUE, FALSE, FALSE, 0, TRUE, 1, TRUE, 6, TRUE, 0}, + {1, TRUE, TRUE, FALSE, FALSE, 0, TRUE, 1, FALSE, 6, FALSE, 0}, {1, FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, FALSE, 6, FALSE, 0}, - {1, TRUE, FALSE, TRUE, FALSE, 0, TRUE, 1, TRUE, 6, TRUE, 0}, + {1, TRUE, FALSE, TRUE, FALSE, 0, TRUE, 1, FALSE, 6, FALSE, 0},
{2, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 6, TRUE, 0, TRUE, 1}, {2, TRUE, FALSE, FALSE, FALSE, 0, FALSE, 6, TRUE, 0, TRUE, 1}, {2, FALSE, TRUE, FALSE, FALSE, 6, FALSE, 0, TRUE, 0, TRUE, 1}, - {2, TRUE, TRUE, FALSE, FALSE, 6, TRUE, 1, TRUE, 6, TRUE, 0}, + {2, TRUE, TRUE, FALSE, FALSE, 6, TRUE, 1, FALSE, 6, FALSE, 0}, {2, FALSE, FALSE, TRUE, TRUE, 8, FALSE, 0, TRUE, 0, TRUE, 1}, - {2, TRUE, FALSE, TRUE, TRUE, 8, TRUE, 1, TRUE, 6, TRUE, 0}, + {2, TRUE, FALSE, TRUE, TRUE, 8, TRUE, 1, FALSE, 6, FALSE, 0},
{0, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 6, FALSE, 0, FALSE, 1}, {0, TRUE, FALSE, FALSE, FALSE, 0, FALSE, 6, TRUE, 0, TRUE, 1},
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77166
Your paranoid android.
=== w1064v1809 (32 bit report) ===
user32: win.c:781: Test failed: rects do not match (3,26)-(157,26) / (0,0)-(0,0)
=== w1064v1809_2scr (32 bit report) ===
user32: win.c:781: Test failed: rects do not match (3,26)-(157,26) / (0,0)-(0,0)
=== w1064v1809_ja (32 bit report) ===
user32: win.c:3936: Test failed: message 0738 available win.c:4061: Test failed: hwnd 00020192 message 7fff win.c:4140: Test failed: hwnd 00020192/00020370 message 7fff win.c:4143: Test failed: hwnd 00020192/00020370 message 7fff
=== w1064v1809_zh_CN (32 bit report) ===
user32: win.c:9690: Test failed: Timed out waiting for the child process win.c:4061: Test failed: hwnd 00020388 message 0282 win.c:4140: Test failed: hwnd 00020388/000C03D6 message 0282 win.c:4143: Test failed: hwnd 00020388/000C03D6 message 0282
=== w1064v1809 (64 bit report) ===
user32: win.c:781: Test failed: rects do not match (3,26)-(157,26) / (0,0)-(0,0)
=== debiant (32 bit report) ===
user32: menu.c:2337: Test failed: test 27
=== debiant (32 bit Chinese:China report) ===
user32: win.c:11025: Test failed: 00FB0092: expected prev 0022013C, got 00000000 win.c:11039: Test failed: hwnd should NOT be topmost win.c:11041: Test failed: 00FB0092: expected NOT topmost win.c:10985: Test failed: 1: hwnd 00FB0092 is still topmost
We could also pass the mouse param through, but it wasn't before so we should keep the behavior unchanged.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/focus.c | 10 +++++----- dlls/user32/message.c | 2 +- dlls/user32/user_private.h | 1 + 3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c index f1c883167ed..09194bb08a7 100644 --- a/dlls/user32/focus.c +++ b/dlls/user32/focus.c @@ -74,7 +74,7 @@ static HWND set_focus_window( HWND hwnd ) /******************************************************************* * set_active_window */ -static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) +BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus, BOOL internal ) { HWND previous = GetActiveWindow(); BOOL ret; @@ -202,12 +202,12 @@ static BOOL set_foreground_window( HWND hwnd, BOOL mouse ) if (send_msg_old) /* old window belongs to other thread */ SendNotifyMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, 0 ); else if (send_msg_new) /* old window belongs to us but new one to other thread */ - ret = set_active_window( 0, NULL, mouse, TRUE ); + ret = set_active_window( 0, NULL, mouse, TRUE, FALSE );
if (send_msg_new) /* new window belongs to other thread */ SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 ); else /* new window belongs to us */ - ret = set_active_window( hwnd, NULL, mouse, TRUE ); + ret = set_active_window( hwnd, NULL, mouse, TRUE, FALSE ); } return ret; } @@ -249,7 +249,7 @@ HWND WINAPI SetActiveWindow( HWND hwnd ) return GetActiveWindow(); /* Windows doesn't seem to return an error here */ }
- if (!set_active_window( hwnd, &prev, FALSE, TRUE )) return 0; + if (!set_active_window( hwnd, &prev, FALSE, TRUE, FALSE )) return 0; return prev; }
@@ -296,7 +296,7 @@ HWND WINAPI SetFocus( HWND hwnd ) /* activate hwndTop if needed. */ if (hwndTop != GetActiveWindow()) { - if (!set_active_window( hwndTop, NULL, FALSE, FALSE )) return 0; + if (!set_active_window( hwndTop, NULL, FALSE, FALSE, FALSE )) return 0; if (!IsWindow( hwnd )) return 0; /* Abort if window destroyed */
/* Do not change focus if the window is no longer active */ diff --git a/dlls/user32/message.c b/dlls/user32/message.c index b02142991cd..006cc1670f4 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -1874,7 +1874,7 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR return WIN_SetStyle(hwnd, wparam, lparam); case WM_WINE_SETACTIVEWINDOW: if (!wparam && GetWindowThreadProcessId( GetForegroundWindow(), NULL ) == GetCurrentThreadId()) return 0; - return (LRESULT)SetActiveWindow( (HWND)wparam ); + return (LRESULT)set_active_window( (HWND)wparam, NULL, FALSE, TRUE, TRUE ); case WM_WINE_KEYBOARD_LL_HOOK: case WM_WINE_MOUSE_LL_HOOK: { diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 8fa54b9229a..19dfbbe48c0 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -246,6 +246,7 @@ extern struct rawinput_thread_data *rawinput_thread_data(void);
extern void CLIPBOARD_ReleaseOwner( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL FOCUS_MouseActivate( HWND hwnd ) DECLSPEC_HIDDEN; +extern BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus, BOOL internal ) DECLSPEC_HIDDEN; extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECLSPEC_HIDDEN; extern void free_dce( struct dce *dce, HWND hwnd ) DECLSPEC_HIDDEN; extern void invalidate_dce( struct tagWND *win, const RECT *rect ) DECLSPEC_HIDDEN;
We will need this to discard a specific internal message type without processing any of the other messages.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- server/queue.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/server/queue.c b/server/queue.c index c1016016051..75864743717 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2494,8 +2494,8 @@ DECL_HANDLER(post_quit_message) /* get a message from the current queue */ DECL_HANDLER(get_message) { + struct message *msg; struct timer *timer; - struct list *ptr; struct msg_queue *queue = get_current_queue(); user_handle_t get_win = get_user_full_handle( req->get_win ); unsigned int filter = req->flags >> 16; @@ -2513,9 +2513,12 @@ DECL_HANDLER(get_message) if (!filter) filter = QS_ALLINPUT;
/* first check for sent messages */ - if ((ptr = list_head( &queue->msg_list[SEND_MESSAGE] ))) + LIST_FOR_EACH_ENTRY( msg, &queue->msg_list[SEND_MESSAGE], struct message, entry ) { - struct message *msg = LIST_ENTRY( ptr, struct message, entry ); + /* skip filtered internal messages */ + if ((req->get_first & 0x80000000) && (req->get_last & 0x80000000) && + (req->get_first > msg->msg || req->get_last < msg->msg)) + continue; receive_message( queue, msg, reply ); return; }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77168
Your paranoid android.
=== debiant (32 bit Chinese:China report) ===
user32: msg.c:14613: Test failed: bad time 37b0f1 win.c:10361: Test failed: Expected foreground window 00410140, got 00D400CC
This will allow us to discard internal messages without processing them.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/message.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/message.c b/dlls/user32/message.c index 006cc1670f4..7d6ccd9f30b 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -2648,7 +2648,8 @@ static inline void call_sendmsg_callback( SENDASYNCPROC callback, HWND hwnd, UIN * available; -1 on error. * All pending sent messages are processed before returning. */ -static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, UINT changed_mask ) +static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, + UINT changed_mask, BOOL discard_internal ) { LRESULT result; struct user_thread_info *thread_info = get_user_thread_info(); @@ -2717,6 +2718,9 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, continue; }
+ if (discard_internal && (info.msg.message & 0x80000000)) + continue; + TRACE( "got type %d msg %x (%s) hwnd %p wp %lx lp %lx\n", info.type, info.msg.message, (info.type == MSG_WINEVENT) ? "MSG_WINEVENT" : SPY_GetMsgName(info.msg.message, info.msg.hwnd), @@ -2856,7 +2860,8 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, } else peek_message( msg, info.msg.hwnd, info.msg.message, - info.msg.message, flags | PM_REMOVE, changed_mask ); + info.msg.message, flags | PM_REMOVE, changed_mask, + discard_internal ); continue; } if (info.msg.message >= WM_DDE_FIRST && info.msg.message <= WM_DDE_LAST) @@ -2900,7 +2905,7 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, static inline void process_sent_messages(void) { MSG msg; - peek_message( &msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, 0 ); + peek_message( &msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, 0, FALSE ); }
@@ -3701,7 +3706,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH PeekMessageW( MSG *msg_out, HWND hwnd, UINT first, USER_CheckNotLock(); check_for_driver_events( 0 );
- ret = peek_message( &msg, hwnd, first, last, flags, 0 ); + ret = peek_message( &msg, hwnd, first, last, flags, 0, FALSE ); if (ret < 0) return FALSE;
if (!ret) @@ -3709,7 +3714,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH PeekMessageW( MSG *msg_out, HWND hwnd, UINT first, flush_window_surfaces( TRUE ); ret = wow_handlers.wait_message( 0, NULL, 0, QS_ALLINPUT, 0 ); /* if we received driver events, check again for a pending message */ - if (ret == WAIT_TIMEOUT || peek_message( &msg, hwnd, first, last, flags, 0 ) <= 0) return FALSE; + if (ret == WAIT_TIMEOUT || peek_message( &msg, hwnd, first, last, flags, 0, FALSE ) <= 0) + return FALSE; }
check_for_driver_events( msg.message ); @@ -3763,7 +3769,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetMessageW( MSG *msg, HWND hwnd, UINT first, UINT } else mask = QS_ALLINPUT;
- while (!(ret = peek_message( msg, hwnd, first, last, PM_REMOVE | (mask << 16), mask ))) + while (!(ret = peek_message( msg, hwnd, first, last, PM_REMOVE | (mask << 16), mask, FALSE ))) { wait_objects( 1, &server_queue, INFINITE, mask & (QS_SENDMESSAGE | QS_SMRESULT), mask, 0 ); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77169
Your paranoid android.
=== debiant (32 bit Chinese:China report) ===
user32: msg.c:14613: Test failed: bad time 37ba64
=== debiant (64 bit WoW report) ===
user32: msg.c:8798: Test failed: WaitForSingleObject failed 102 msg.c:8804: Test failed: destroy child on thread exit: 0: the msg 0x0082 was expected, but got msg 0x000f instead msg.c:8804: Test failed: destroy child on thread exit: 1: the msg 0x000f was expected, but got msg 0x0014 instead msg.c:8804: Test failed: destroy child on thread exit: 2: the msg sequence is not complete: expected 0014 - actual 0000
This discards the pending WM_WINE_SETACTIVEWINDOW messages when current thread becomes -or is already- foreground, and before setting the active window.
Although it's still not enough, it should help solving several focus inversions when WM messages arrive late, or when multiple windows are created without the application checking its messages.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/focus.c | 3 +++ dlls/user32/message.c | 12 ++++++++++++ dlls/user32/tests/win.c | 10 +++++----- dlls/user32/user_private.h | 1 + 4 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c index 09194bb08a7..cab557eb3a3 100644 --- a/dlls/user32/focus.c +++ b/dlls/user32/focus.c @@ -87,6 +87,9 @@ BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus, BOOL inte return TRUE; }
+ if (hwnd && !internal && GetWindowThreadProcessId( GetForegroundWindow(), NULL ) == GetCurrentThreadId()) + discard_internal_messages( WM_WINE_SETACTIVEWINDOW ); + /* call CBT hook chain */ cbt.fMouse = mouse; cbt.hWndActive = previous; diff --git a/dlls/user32/message.c b/dlls/user32/message.c index 7d6ccd9f30b..184853c243b 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -2909,6 +2909,18 @@ static inline void process_sent_messages(void) }
+/*********************************************************************** + * discard_internal_messages + * + * Remove all matching internal messages. + */ +void discard_internal_messages(UINT msg) +{ + MSG message; + peek_message( &message, 0, msg, msg, PM_REMOVE | PM_QS_SENDMESSAGE, 0, TRUE ); +} + + /*********************************************************************** * get_server_queue_handle * diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 9f082d16330..389731ff69d 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -3282,15 +3282,15 @@ static struct test_sfw_test_desc test_sfw_tests[] = { {1, FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, FALSE, 6, FALSE, 0}, {1, TRUE, FALSE, TRUE, FALSE, 0, TRUE, 1, FALSE, 6, FALSE, 0},
- {2, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 6, TRUE, 0, TRUE, 1}, - {2, TRUE, FALSE, FALSE, FALSE, 0, FALSE, 6, TRUE, 0, TRUE, 1}, - {2, FALSE, TRUE, FALSE, FALSE, 6, FALSE, 0, TRUE, 0, TRUE, 1}, + {2, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 6, FALSE, 0, FALSE, 1}, + {2, TRUE, FALSE, FALSE, FALSE, 0, FALSE, 6, FALSE, 0, FALSE, 1}, + {2, FALSE, TRUE, FALSE, FALSE, 6, FALSE, 0, FALSE, 0, FALSE, 1}, {2, TRUE, TRUE, FALSE, FALSE, 6, TRUE, 1, FALSE, 6, FALSE, 0}, - {2, FALSE, FALSE, TRUE, TRUE, 8, FALSE, 0, TRUE, 0, TRUE, 1}, + {2, FALSE, FALSE, TRUE, TRUE, 8, FALSE, 0, FALSE, 0, FALSE, 1}, {2, TRUE, FALSE, TRUE, TRUE, 8, TRUE, 1, FALSE, 6, FALSE, 0},
{0, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 6, FALSE, 0, FALSE, 1}, - {0, TRUE, FALSE, FALSE, FALSE, 0, FALSE, 6, TRUE, 0, TRUE, 1}, + {0, TRUE, FALSE, FALSE, FALSE, 0, FALSE, 6, FALSE, 0, FALSE, 1}, {0, FALSE, TRUE, FALSE, FALSE, 6, FALSE, 0, FALSE, 0, FALSE, 1}, {0, TRUE, TRUE, FALSE, FALSE, 6, TRUE, 1, FALSE, 6, FALSE, 0}, {0, FALSE, FALSE, TRUE, TRUE, 8, FALSE, 0, FALSE, 0, FALSE, 1}, diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 19dfbbe48c0..3348c58ca67 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -248,6 +248,7 @@ extern void CLIPBOARD_ReleaseOwner( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL FOCUS_MouseActivate( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus, BOOL internal ) DECLSPEC_HIDDEN; extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECLSPEC_HIDDEN; +extern void discard_internal_messages( UINT msg ); extern void free_dce( struct dce *dce, HWND hwnd ) DECLSPEC_HIDDEN; extern void invalidate_dce( struct tagWND *win, const RECT *rect ) DECLSPEC_HIDDEN; extern HDC get_display_dc(void) DECLSPEC_HIDDEN;
Hi Rémi,
On 14/08/2020 15:56, Rémi Bernon wrote:
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 19dfbbe48c0..3348c58ca67 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -248,6 +248,7 @@ extern void CLIPBOARD_ReleaseOwner( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL FOCUS_MouseActivate( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus, BOOL internal ) DECLSPEC_HIDDEN; extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECLSPEC_HIDDEN; +extern void discard_internal_messages( UINT msg ); extern void free_dce( struct dce *dce, HWND hwnd ) DECLSPEC_HIDDEN; extern void invalidate_dce( struct tagWND *win, const RECT *rect ) DECLSPEC_HIDDEN; extern HDC get_display_dc(void) DECLSPEC_HIDDEN;
Probably just a nitpick, but is there a reason this isn't DECLSPEC_HIDDEN?
On 2020-08-14 16:24, Gabriel Ivăncescu wrote:
Hi Rémi,
On 14/08/2020 15:56, Rémi Bernon wrote:
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 19dfbbe48c0..3348c58ca67 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -248,6 +248,7 @@ extern void CLIPBOARD_ReleaseOwner( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL FOCUS_MouseActivate( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus, BOOL internal ) DECLSPEC_HIDDEN; extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECLSPEC_HIDDEN; +extern void discard_internal_messages( UINT msg ); extern void free_dce( struct dce *dce, HWND hwnd ) DECLSPEC_HIDDEN; extern void invalidate_dce( struct tagWND *win, const RECT *rect ) DECLSPEC_HIDDEN; extern HDC get_display_dc(void) DECLSPEC_HIDDEN;
Probably just a nitpick, but is there a reason this isn't DECLSPEC_HIDDEN?
No reason indeed, thanks.
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77170
Your paranoid android.
=== w1064v1809 (32 bit report) ===
user32: win.c:781: Test failed: rects do not match (3,26)-(157,26) / (0,0)-(0,0)
=== w1064v1809_2scr (32 bit report) ===
user32: win.c:781: Test failed: rects do not match (3,26)-(157,26) / (0,0)-(0,0) win.c:4061: Test failed: hwnd 0004006E message 0738
=== w1064v1809_ar (32 bit report) ===
user32: win.c:9690: Test failed: Timed out waiting for the child process
=== w1064v1809_he (32 bit report) ===
user32: win.c:3936: Test failed: message 0738 available win.c:10186: Test failed: pos = 00e700d0 win.c:10190: Test failed: pos = 00e700d0 win.c:10194: Test failed: pos = 00e700d0
=== w1064v1809_ja (32 bit report) ===
user32: win.c:3936: Test failed: message 0738 available win.c:4061: Test failed: hwnd 00020304 message 7fff win.c:4140: Test failed: hwnd 00020304/000F02F8 message 7fff win.c:4143: Test failed: hwnd 00020304/000F02F8 message 7fff
=== w1064v1809_zh_CN (32 bit report) ===
user32: win.c:4061: Test failed: hwnd 00010372 message 0282 win.c:4140: Test failed: hwnd 00010372/000C03DE message 0282 win.c:4143: Test failed: hwnd 00010372/000C03DE message 0282
=== w1064v1809 (64 bit report) ===
user32: win.c:781: Test failed: rects do not match (3,26)-(157,26) / (0,0)-(0,0)
=== debiant (32 bit Chinese:China report) ===
user32: monitor: Timeout
When window is already active but has lost foreground, as shown by concurrent SetForegroundWindow tests.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/focus.c | 4 ++++ dlls/user32/tests/win.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c index cab557eb3a3..cc2714658b3 100644 --- a/dlls/user32/focus.c +++ b/dlls/user32/focus.c @@ -207,6 +207,10 @@ static BOOL set_foreground_window( HWND hwnd, BOOL mouse ) else if (send_msg_new) /* old window belongs to us but new one to other thread */ ret = set_active_window( 0, NULL, mouse, TRUE, FALSE );
+ /* already active, set_active_window will do no nothing */ + if (!send_msg_new && hwnd == GetActiveWindow()) + SendMessageW( hwnd, WM_NCACTIVATE, TRUE, (LPARAM)hwnd ); + if (send_msg_new) /* new window belongs to other thread */ SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 ); else /* new window belongs to us */ diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 389731ff69d..e4943b85a0d 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -3276,25 +3276,25 @@ struct test_sfw_test_desc
static struct test_sfw_test_desc test_sfw_tests[] = { {1, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 0, FALSE, 6, FALSE, 0}, - {1, TRUE, FALSE, FALSE, FALSE, 0, TRUE, 1, FALSE, 6, FALSE, 0}, + {1, TRUE, FALSE, FALSE, FALSE, 0, FALSE, 1, FALSE, 6, FALSE, 0}, {1, FALSE, TRUE, FALSE, FALSE, 0, FALSE, 0, FALSE, 6, FALSE, 0}, - {1, TRUE, TRUE, FALSE, FALSE, 0, TRUE, 1, FALSE, 6, FALSE, 0}, + {1, TRUE, TRUE, FALSE, FALSE, 0, FALSE, 1, FALSE, 6, FALSE, 0}, {1, FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, FALSE, 6, FALSE, 0}, - {1, TRUE, FALSE, TRUE, FALSE, 0, TRUE, 1, FALSE, 6, FALSE, 0}, + {1, TRUE, FALSE, TRUE, FALSE, 0, FALSE, 1, FALSE, 6, FALSE, 0},
{2, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 6, FALSE, 0, FALSE, 1}, {2, TRUE, FALSE, FALSE, FALSE, 0, FALSE, 6, FALSE, 0, FALSE, 1}, {2, FALSE, TRUE, FALSE, FALSE, 6, FALSE, 0, FALSE, 0, FALSE, 1}, - {2, TRUE, TRUE, FALSE, FALSE, 6, TRUE, 1, FALSE, 6, FALSE, 0}, + {2, TRUE, TRUE, FALSE, FALSE, 6, FALSE, 1, FALSE, 6, FALSE, 0}, {2, FALSE, FALSE, TRUE, TRUE, 8, FALSE, 0, FALSE, 0, FALSE, 1}, - {2, TRUE, FALSE, TRUE, TRUE, 8, TRUE, 1, FALSE, 6, FALSE, 0}, + {2, TRUE, FALSE, TRUE, TRUE, 8, FALSE, 1, FALSE, 6, FALSE, 0},
{0, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 6, FALSE, 0, FALSE, 1}, {0, TRUE, FALSE, FALSE, FALSE, 0, FALSE, 6, FALSE, 0, FALSE, 1}, {0, FALSE, TRUE, FALSE, FALSE, 6, FALSE, 0, FALSE, 0, FALSE, 1}, - {0, TRUE, TRUE, FALSE, FALSE, 6, TRUE, 1, FALSE, 6, FALSE, 0}, + {0, TRUE, TRUE, FALSE, FALSE, 6, FALSE, 1, FALSE, 6, FALSE, 0}, {0, FALSE, FALSE, TRUE, TRUE, 8, FALSE, 0, FALSE, 0, FALSE, 1}, - {0, TRUE, FALSE, TRUE, TRUE, 8, TRUE, 1, FALSE, 6, FALSE, 0}, + {0, TRUE, FALSE, TRUE, TRUE, 8, FALSE, 1, FALSE, 6, FALSE, 0}, };
static DWORD WINAPI test_sfw_thread(void *param)
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77171
Your paranoid android.
=== w1064v1507 (32 bit report) ===
user32: win.c:9690: Test failed: Timed out waiting for the child process
=== w1064v1809 (32 bit report) ===
user32: win.c:781: Test failed: rects do not match (3,26)-(157,26) / (0,0)-(0,0)
=== w1064v1809_2scr (32 bit report) ===
user32: win.c:781: Test failed: rects do not match (3,26)-(157,26) / (0,0)-(0,0) win.c:4061: Test failed: hwnd 000301CA message 0738
=== w1064v1809_he (32 bit report) ===
user32: win.c:9690: Test failed: Timed out waiting for the child process
=== w1064v1809_ja (32 bit report) ===
user32: win.c:3936: Test failed: message 0738 available win.c:4061: Test failed: hwnd 000202F0 message 7fff win.c:4140: Test failed: hwnd 000202F0/0005036C message 7fff win.c:4143: Test failed: hwnd 000202F0/0005036C message 7fff
=== w1064v1809_zh_CN (32 bit report) ===
user32: win.c:4061: Test failed: hwnd 0003018A message 0282 win.c:4140: Test failed: hwnd 0003018A/000A03C8 message 0282 win.c:4143: Test failed: hwnd 0003018A/000A03C8 message 0282
=== w1064v1809 (64 bit report) ===
user32: win.c:781: Test failed: rects do not match (3,26)-(157,26) / (0,0)-(0,0)