This is not strictly required and it does not even work all the time regardless of what MSDN says, but it helps, especially when multiple processes are creating windows.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
Note that this patch is completely optional and can be ignored. I had more consistent results with it when running the test on my Windows 10 VM though but it doesn't seem to change much for the testbot.
v2: For the whole series, mostly whitespace fixes, and a rework of the fix implementation to avoid messing with the message queues.
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..c001247b651 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;
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 | 336 +++++++++++++++++++++++++++++++++------- 1 file changed, 276 insertions(+), 60 deletions(-)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index c001247b651..92a7686cc5d 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -3240,40 +3240,292 @@ 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 +3599,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 +12203,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 +12306,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=77967
Your paranoid android.
=== w1064v1507 (32 bit report) ===
user32: win.c:9688: Test failed: Timed out waiting for the child process win.c:11139: Test failed: 0005015C: expected next 0006004E, got 00000000 win.c:11154: Test failed: 0004004C: expected next 00040044, got 00000000 win.c:11164: Test failed: 0004004C: expected next 00040044, got 00000000 win.c:11179: Test failed: 0004004C: expected next 00040044, got 00000000 win.c:11203: Test failed: 0004004C: expected next 00040044, got 00000000 win.c:11212: Test failed: 0004004C: expected next 00040044, got 00000000
=== 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:9688: Test failed: Timed out waiting for the child process
=== w1064v1809_ja (32 bit report) ===
user32: win.c:4059: Test failed: hwnd 00040062 message 7fff win.c:4138: Test failed: hwnd 00040062/008E0348 message 7fff win.c:4141: Test failed: hwnd 00040062/008E0348 message 7fff
=== w1064v1809_zh_CN (32 bit report) ===
user32: win.c:4059: Test failed: hwnd 0001038C message 0282 win.c:4138: Test failed: hwnd 0001038C/000B03DA message 0282 win.c:4141: Test failed: hwnd 0001038C/000B03DA message 0282
=== w1064v1809 (64 bit report) ===
user32: win.c:781: Test failed: rects do not match (3,26)-(157,26) / (0,0)-(0,0)
Instead of only checking that the window is foreground.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/message.c | 3 ++- dlls/user32/tests/win.c | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/message.c b/dlls/user32/message.c index aadec28b559..9d08aa22120 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -1873,7 +1873,8 @@ 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 92a7686cc5d..bdc7a8962e0 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=77968
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:4059: Test failed: hwnd 000201A4 message 0738
=== w1064v1809_he (32 bit report) ===
user32: win.c:3934: Test failed: message 0738 available
=== w1064v1809_ja (32 bit report) ===
user32: win.c:4059: Test failed: hwnd 000202F0 message 7fff win.c:4138: Test failed: hwnd 000202F0/001002A6 message 7fff win.c:4141: Test failed: hwnd 000202F0/001002A6 message 7fff
=== w1064v1809_zh_CN (32 bit report) ===
user32: win.c:4059: Test failed: hwnd 000202DE message 0282 win.c:4138: Test failed: hwnd 000202DE/000D03D4 message 0282 win.c:4141: Test failed: hwnd 000202DE/000D03D4 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: monitor: Timeout
=== debiant (32 bit Japanese:Japan report) ===
user32: win.c:10357: Test failed: GetActiveWindow() = 00000000 win.c:10357: Test failed: GetFocus() = 00000000 win.c:10359: Test failed: Expected foreground window 00020052, got 00E200A2 win.c:10362: Test failed: Received WM_ACTIVATEAPP(0), did not expect it. win.c:10369: Test failed: Expected foreground window 00020052, got 00000000 win.c:10371: Test failed: GetActiveWindow() = 00000000 win.c:10371: Test failed: GetFocus() = 00000000 win.c:10379: Test failed: Received WM_ACTIVATEAPP(1), did not expect it.
=== debiant (32 bit Chinese:China report) ===
user32: clipboard.c:760: Test failed: 6: gle 5 clipboard.c:765: Test failed: 6.0: got 0000 instead of 0008 clipboard.c:805: Test failed: 6: gle 1418 clipboard.c:815: Test failed: 6: count 3 clipboard.c:818: Test failed: 6: gle 1418 clipboard.c:853: Test failed: 6.0: formats 00000000 have been rendered clipboard.c:858: Test failed: 6.0: formats 00000000 have been rendered clipboard.c:853: Test failed: 6.1: formats 00000000 have been rendered clipboard.c:858: Test failed: 6.1: formats 00000000 have been rendered clipboard.c:853: Test failed: 6.2: formats 00000000 have been rendered clipboard.c:858: Test failed: 6.2: formats 00000000 have been rendered monitor: Timeout
=== debiant (32 bit WoW report) ===
user32: monitor: Timeout
=== debiant (64 bit WoW report) ===
user32: monitor: Timeout
So that we can correctly track out of order window activation requests from other threads calling SetForegroundWindow and process or discard them correctly.
A new generation is created every time the foreground thread changes its active or focus window state, so that any previously sent activation messages are discarded (with some tricky details shown by the tests).
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v2: Use a generation counter instead of discarding messages and messing with the message queues.
dlls/user32/focus.c | 65 ++++++++++++++++++++++++++++++-------- dlls/user32/message.c | 2 +- dlls/user32/tests/win.c | 46 ++++++++++++--------------- dlls/user32/user_private.h | 1 + server/protocol.def | 4 +++ server/queue.c | 6 ++++ 6 files changed, 83 insertions(+), 41 deletions(-)
diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c index f1c883167ed..b88a711b05e 100644 --- a/dlls/user32/focus.c +++ b/dlls/user32/focus.c @@ -70,17 +70,41 @@ static HWND set_focus_window( HWND hwnd ) return previous; }
+static void get_active_window( HWND *active, DWORD *active_gen ) +{ + *active = NULL; + *active_gen = 0; + SERVER_START_REQ( get_thread_input ) + { + req->tid = GetCurrentThreadId(); + if (wine_server_call_err( req )) return; + *active = wine_server_ptr_handle( reply->active ); + *active_gen = reply->active_gen; + } + SERVER_END_REQ; +} +
/******************************************************************* * 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, DWORD generation ) { - HWND previous = GetActiveWindow(); + HWND previous; BOOL ret; - DWORD old_thread, new_thread; + DWORD old_thread, new_thread, previous_gen; CBTACTIVATESTRUCT cbt;
+ TRACE( "hwnd %p, prev %p, mouse %d, focus %d, generation %u\n", hwnd, prev, mouse, focus, generation ); + + get_active_window( &previous, &previous_gen ); + + if ((generation - previous_gen) > 1) + { + WARN( "ignoring out of order generation %u, previous_gen %u\n", generation, previous_gen ); + return FALSE; + } + if (previous == hwnd) { if (prev) *prev = hwnd; @@ -102,6 +126,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) SERVER_START_REQ( set_active_window ) { req->handle = wine_server_user_handle( hwnd ); + req->generation = generation; if ((ret = !wine_server_call_err( req ))) previous = wine_server_ptr_handle( reply->previous ); } @@ -182,6 +207,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) */ static BOOL set_foreground_window( HWND hwnd, BOOL mouse ) { + DWORD active_gen_old, active_gen_new; BOOL ret, send_msg_old = FALSE, send_msg_new = FALSE; HWND previous = 0;
@@ -192,7 +218,9 @@ static BOOL set_foreground_window( HWND hwnd, BOOL mouse ) { previous = wine_server_ptr_handle( reply->previous ); send_msg_old = reply->send_msg_old; + active_gen_old = reply->active_gen_old; send_msg_new = reply->send_msg_new; + active_gen_new = reply->active_gen_new; } } SERVER_END_REQ; @@ -200,14 +228,14 @@ static BOOL set_foreground_window( HWND hwnd, BOOL mouse ) if (ret && previous != hwnd) { if (send_msg_old) /* old window belongs to other thread */ - SendNotifyMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, 0 ); + SendNotifyMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, (LPARAM)active_gen_old ); 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, active_gen_old + 1 );
if (send_msg_new) /* new window belongs to other thread */ - SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 ); + SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, (LPARAM)active_gen_new ); else /* new window belongs to us */ - ret = set_active_window( hwnd, NULL, mouse, TRUE ); + ret = set_active_window( hwnd, NULL, mouse, TRUE, active_gen_new + 1 ); } return ret; } @@ -229,10 +257,13 @@ BOOL FOCUS_MouseActivate( HWND hwnd ) */ HWND WINAPI SetActiveWindow( HWND hwnd ) { - HWND prev; + HWND active = NULL; + DWORD active_gen = 0;
TRACE( "%p\n", hwnd );
+ get_active_window( &active, &active_gen ); + if (hwnd) { LONG style; @@ -246,11 +277,13 @@ HWND WINAPI SetActiveWindow( HWND hwnd )
style = GetWindowLongW( hwnd, GWL_STYLE ); if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) - return GetActiveWindow(); /* Windows doesn't seem to return an error here */ + return active; /* Windows doesn't seem to return an error here */ }
- if (!set_active_window( hwnd, &prev, FALSE, TRUE )) return 0; - return prev; + if (GetWindowThreadProcessId( GetForegroundWindow(), NULL ) == GetCurrentThreadId()) + active_gen++; + if (!set_active_window( hwnd, &active, FALSE, TRUE, active_gen )) return 0; + return active; }
@@ -259,8 +292,9 @@ HWND WINAPI SetActiveWindow( HWND hwnd ) */ HWND WINAPI SetFocus( HWND hwnd ) { - HWND hwndTop = hwnd; + HWND hwndTop = hwnd, active; HWND previous = GetFocus(); + DWORD active_gen;
TRACE( "%p prev %p\n", hwnd, previous );
@@ -294,9 +328,12 @@ HWND WINAPI SetFocus( HWND hwnd ) if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous, TRUE )) return 0;
/* activate hwndTop if needed. */ - if (hwndTop != GetActiveWindow()) + get_active_window( &active, &active_gen ); + if (hwndTop != active) { - if (!set_active_window( hwndTop, NULL, FALSE, FALSE )) return 0; + if (GetWindowThreadProcessId( GetForegroundWindow(), NULL ) == GetCurrentThreadId()) + active_gen++; + if (!set_active_window( hwndTop, NULL, FALSE, FALSE, active_gen )) 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 9d08aa22120..1f5eebf7248 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -1875,7 +1875,7 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR 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, (DWORD)lparam ); 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 bdc7a8962e0..75a4cdc42d5 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -3268,33 +3268,31 @@ struct test_sfw_test_desc 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, 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, 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, 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, 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, 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}, + {1, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 0, 6, 0}, + {1, TRUE, FALSE, FALSE, FALSE, 0, TRUE, 1, 6, 0}, + {1, FALSE, TRUE, FALSE, FALSE, 0, FALSE, 0, 6, 0}, + {1, TRUE, TRUE, FALSE, FALSE, 0, TRUE, 1, 6, 0}, + {1, FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, 6, 0}, + {1, TRUE, FALSE, TRUE, FALSE, 0, TRUE, 1, 6, 0}, + + {2, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 6, 0, 1}, + {2, TRUE, FALSE, FALSE, FALSE, 0, FALSE, 6, 0, 1}, + {2, FALSE, TRUE, FALSE, FALSE, 6, FALSE, 0, 0, 1}, + {2, TRUE, TRUE, FALSE, FALSE, 6, TRUE, 1, 6, 0}, + {2, FALSE, FALSE, TRUE, TRUE, 8, FALSE, 0, 0, 1}, + {2, TRUE, FALSE, TRUE, TRUE, 8, TRUE, 1, 6, 0}, + + {0, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 6, 0, 1}, + {0, TRUE, FALSE, FALSE, FALSE, 0, FALSE, 6, 0, 1}, + {0, FALSE, TRUE, FALSE, FALSE, 6, FALSE, 0, 0, 1}, + {0, TRUE, TRUE, FALSE, FALSE, 6, TRUE, 1, 6, 0}, + {0, FALSE, FALSE, TRUE, TRUE, 8, FALSE, 0, 0, 1}, + {0, TRUE, FALSE, TRUE, TRUE, 8, TRUE, 1, 6, 0}, };
static DWORD WINAPI test_sfw_thread( void *param ) @@ -3368,16 +3366,12 @@ static DWORD WINAPI test_sfw_thread( void *param ) 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 ); diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 8fa54b9229a..aa310c65cfd 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, DWORD generation ) 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; diff --git a/server/protocol.def b/server/protocol.def index 92290af701c..1b1fdf6fda9 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2768,6 +2768,7 @@ enum coords_relative user_handle_t focus; /* handle to the focus window */ user_handle_t capture; /* handle to the capture window */ user_handle_t active; /* handle to the active window */ + unsigned int active_gen; /* generation of the last set_active_window */ user_handle_t foreground; /* handle to the global foreground window */ user_handle_t menu_owner; /* handle to the menu owner */ user_handle_t move_size; /* handle to the moving/resizing window */ @@ -2807,7 +2808,9 @@ enum coords_relative @REPLY user_handle_t previous; /* handle to the previous foreground window */ int send_msg_old; /* whether we have to send a msg to the old window */ + unsigned int active_gen_old;/* set_active_window generation for the old window */ int send_msg_new; /* whether we have to send a msg to the new window */ + unsigned int active_gen_new;/* set_active_window generation for the new window */ @END
/* Set the current thread focus window */ @@ -2820,6 +2823,7 @@ enum coords_relative /* Set the current thread active window */ @REQ(set_active_window) user_handle_t handle; /* handle to the active window */ + unsigned int generation; /* set_active_window generation number */ @REPLY user_handle_t previous; /* handle to the previous active window */ @END diff --git a/server/queue.c b/server/queue.c index c1016016051..65cc9e9eb76 100644 --- a/server/queue.c +++ b/server/queue.c @@ -104,6 +104,7 @@ struct thread_input user_handle_t focus; /* focus window */ user_handle_t capture; /* capture window */ user_handle_t active; /* active window */ + unsigned int active_gen; /* set_active_window generation */ user_handle_t menu_owner; /* current menu owner window */ user_handle_t move_size; /* current moving/resizing window */ user_handle_t caret; /* caret window */ @@ -253,6 +254,7 @@ static struct thread_input *create_thread_input( struct thread *thread ) input->focus = 0; input->capture = 0; input->active = 0; + input->active_gen = 0; input->menu_owner = 0; input->move_size = 0; input->cursor = 0; @@ -2929,6 +2931,7 @@ DECL_HANDLER(get_thread_input) reply->focus = input->focus; reply->capture = input->capture; reply->active = input->active; + reply->active_gen = input->active_gen; reply->menu_owner = input->menu_owner; reply->move_size = input->move_size; reply->caret = input->caret; @@ -3026,6 +3029,7 @@ DECL_HANDLER(set_foreground_window) reply->previous = desktop->foreground_input ? desktop->foreground_input->active : 0; reply->send_msg_old = (reply->previous && desktop->foreground_input != queue->input); reply->send_msg_new = FALSE; + reply->active_gen_old = desktop->foreground_input ? desktop->foreground_input->active_gen : 0;
if (is_valid_foreground_window( req->handle ) && (thread = get_window_thread( req->handle )) && @@ -3033,6 +3037,7 @@ DECL_HANDLER(set_foreground_window) { set_foreground_input( desktop, thread->queue->input ); reply->send_msg_new = (desktop->foreground_input != queue->input); + reply->active_gen_new = desktop->foreground_input ? desktop->foreground_input->active_gen : 0; } else set_win32_error( ERROR_INVALID_WINDOW_HANDLE );
@@ -3067,6 +3072,7 @@ DECL_HANDLER(set_active_window) { reply->previous = queue->input->active; queue->input->active = get_user_full_handle( req->handle ); + queue->input->active_gen = req->generation; } else set_error( STATUS_INVALID_HANDLE ); }
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=77969
Your paranoid android.
=== w1064v1507 (32 bit report) ===
user32: win.c:9682: Test failed: Timed out waiting for the child process win.c:11133: Test failed: 000601B0: expected next 00070018, got 00000000 win.c:11148: Test failed: 00030214: expected next 0003020C, got 00000000 win.c:11158: Test failed: 00030214: expected next 0003020C, got 00000000 win.c:11173: Test failed: 00030214: expected next 0003020C, got 00000000 win.c:11197: Test failed: 00030214: expected next 0003020C, got 00000000 win.c:11206: Test failed: 00030214: expected next 0003020C, got 00000000
=== 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_ar (32 bit report) ===
user32: win.c:9682: Test failed: Timed out waiting for the child process
=== w1064v1809_he (32 bit report) ===
user32: win.c:3928: Test failed: message 0738 available
=== w1064v1809_ja (32 bit report) ===
user32: win.c:4053: Test failed: hwnd 000202FE message 7fff win.c:4132: Test failed: hwnd 000202FE/001400EC message 7fff win.c:4135: Test failed: hwnd 000202FE/001400EC message 7fff
=== w1064v1809_zh_CN (32 bit report) ===
user32: win.c:9682: Test failed: Timed out waiting for the child process win.c:4053: Test failed: hwnd 0002038A message 0282 win.c:4132: Test failed: hwnd 0002038A/000D008A message 0282 win.c:4135: Test failed: hwnd 0002038A/000D008A 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: monitor: Timeout
=== debiant (32 bit Chinese:China report) ===
user32: clipboard.c:1626: Test failed: gle 5 clipboard.c:1628: Test failed: expected moveable mem 00000000 clipboard.c:1633: Test failed: expected moveable mem 00000000 clipboard.c:1638: Test failed: expected moveable mem 00000000 clipboard.c:1644: Test failed: expected moveable mem 00000000 clipboard.c:1650: Test failed: expected bitmap 00000000 clipboard.c:1651: Test failed: different bitmap 00000000 / 0046003F clipboard.c:1654: Test failed: expected bitmap 00000000 clipboard.c:1655: Test failed: different bitmap 00000000 / 000B0045 clipboard.c:1658: Test failed: expected palette 00000000 clipboard.c:1659: Test failed: different palette 00000000 / 000C0041 clipboard.c:1662: Test failed: expected fixed mem 00000000 clipboard.c:1664: Test failed: expected fixed mem 00000000 clipboard.c:1666: Test failed: gle 1418 monitor: Timeout
=== debiant (32 bit WoW report) ===
user32: monitor: Timeout
=== debiant (64 bit WoW report) ===
user32: win.c:10353: Test failed: Expected foreground window 000D013E, got 00000000
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 | 42 ++++++++++++++++++++--------------------- 2 files changed, 24 insertions(+), 22 deletions(-)
diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c index b88a711b05e..db4fe0dfb15 100644 --- a/dlls/user32/focus.c +++ b/dlls/user32/focus.c @@ -232,6 +232,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, active_gen_old + 1 );
+ /* 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, (LPARAM)active_gen_new ); else /* new window belongs to us */ diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 75a4cdc42d5..cff334368b9 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -3266,33 +3266,32 @@ struct test_sfw_test_desc
BOOL todo_msgcount_before_set_foreground; int msgcount_before_set_foreground; - BOOL todo_msgcount_after_set_foreground; int msgcount_after_set_foreground; int msgcount_after_peek_message; int expected_window; };
static struct test_sfw_test_desc test_sfw_tests[] = { - {1, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 0, 6, 0}, - {1, TRUE, FALSE, FALSE, FALSE, 0, TRUE, 1, 6, 0}, - {1, FALSE, TRUE, FALSE, FALSE, 0, FALSE, 0, 6, 0}, - {1, TRUE, TRUE, FALSE, FALSE, 0, TRUE, 1, 6, 0}, - {1, FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, 6, 0}, - {1, TRUE, FALSE, TRUE, FALSE, 0, TRUE, 1, 6, 0}, - - {2, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 6, 0, 1}, - {2, TRUE, FALSE, FALSE, FALSE, 0, FALSE, 6, 0, 1}, - {2, FALSE, TRUE, FALSE, FALSE, 6, FALSE, 0, 0, 1}, - {2, TRUE, TRUE, FALSE, FALSE, 6, TRUE, 1, 6, 0}, - {2, FALSE, FALSE, TRUE, TRUE, 8, FALSE, 0, 0, 1}, - {2, TRUE, FALSE, TRUE, TRUE, 8, TRUE, 1, 6, 0}, - - {0, FALSE, FALSE, FALSE, FALSE, 0, FALSE, 6, 0, 1}, - {0, TRUE, FALSE, FALSE, FALSE, 0, FALSE, 6, 0, 1}, - {0, FALSE, TRUE, FALSE, FALSE, 6, FALSE, 0, 0, 1}, - {0, TRUE, TRUE, FALSE, FALSE, 6, TRUE, 1, 6, 0}, - {0, FALSE, FALSE, TRUE, TRUE, 8, FALSE, 0, 0, 1}, - {0, TRUE, FALSE, TRUE, TRUE, 8, TRUE, 1, 6, 0}, + {1, FALSE, FALSE, FALSE, FALSE, 0, 0, 6, 0}, + {1, TRUE, FALSE, FALSE, FALSE, 0, 1, 6, 0}, + {1, FALSE, TRUE, FALSE, FALSE, 0, 0, 6, 0}, + {1, TRUE, TRUE, FALSE, FALSE, 0, 1, 6, 0}, + {1, FALSE, FALSE, TRUE, FALSE, 0, 0, 6, 0}, + {1, TRUE, FALSE, TRUE, FALSE, 0, 1, 6, 0}, + + {2, FALSE, FALSE, FALSE, FALSE, 0, 6, 0, 1}, + {2, TRUE, FALSE, FALSE, FALSE, 0, 6, 0, 1}, + {2, FALSE, TRUE, FALSE, FALSE, 6, 0, 0, 1}, + {2, TRUE, TRUE, FALSE, FALSE, 6, 1, 6, 0}, + {2, FALSE, FALSE, TRUE, TRUE, 8, 0, 0, 1}, + {2, TRUE, FALSE, TRUE, TRUE, 8, 1, 6, 0}, + + {0, FALSE, FALSE, FALSE, FALSE, 0, 6, 0, 1}, + {0, TRUE, FALSE, FALSE, FALSE, 0, 6, 0, 1}, + {0, FALSE, TRUE, FALSE, FALSE, 6, 0, 0, 1}, + {0, TRUE, TRUE, FALSE, FALSE, 6, 1, 6, 0}, + {0, FALSE, FALSE, TRUE, TRUE, 8, 0, 0, 1}, + {0, TRUE, FALSE, TRUE, TRUE, 8, 1, 6, 0}, };
static DWORD WINAPI test_sfw_thread( void *param ) @@ -3357,7 +3356,6 @@ static DWORD WINAPI test_sfw_thread( void *param )
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 );
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=77970
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:4051: Test failed: hwnd 000301A2 message 0738
=== w1064v1809_ja (32 bit report) ===
user32: win.c:9665: Test failed: didn't get start_event win.c:9669: Test failed: WindowFromPoint returned 00050300, expected 00000000 win.c:9677: Test failed: WindowFromPoint returned 00050300, expected 00000000 win.c:9680: Test failed: Timed out waiting for the child process win.c:9578: Test failed: WindowFromPoint returned 000300D8, expected 00050300 win.c:9585: Test failed: WindowFromPoint returned 000300D8, expected 00050080 win.c:9591: Test failed: CreateWindowEx failed win.c:9606: Test failed: transparent window didn't get WM_NCHITTEST message win.c:9607: Test failed: button under static window didn't get WM_LBUTTONUP win.c:4051: Test failed: hwnd 000202F4 message 7fff win.c:4130: Test failed: hwnd 000202F4/000202E6 message 7fff win.c:4133: Test failed: hwnd 000202F4/000202E6 message 7fff
=== w1064v1809_zh_CN (32 bit report) ===
user32: win.c:9665: Test failed: didn't get start_event win.c:9669: Test failed: WindowFromPoint returned 000203E4, expected 00000000 win.c:9677: Test failed: WindowFromPoint returned 000203E0, expected 00000000 win.c:9606: Test failed: transparent window didn't get WM_NCHITTEST message win.c:9607: Test failed: button under static window didn't get WM_LBUTTONUP win.c:4051: Test failed: hwnd 00010388 message 0282 win.c:4130: Test failed: hwnd 00010388/000C03AC message 0282 win.c:4133: Test failed: hwnd 00010388/000C03AC 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: monitor: Timeout
=== debiant (32 bit Chinese:China report) ===
user32: clipboard.c:760: Test failed: 5: gle 5 clipboard.c:765: Test failed: 5.0: got 0000 instead of 0002 clipboard.c:805: Test failed: 5: gle 1418 clipboard.c:815: Test failed: 5: count 3 clipboard.c:818: Test failed: 5: gle 1418 clipboard.c:852: Test failed: 5: format 0002 got data 00070042 clipboard.c:853: Test failed: 5.0: formats 00000000 have been rendered clipboard.c:858: Test failed: 5.0: formats 00000000 have been rendered clipboard.c:852: Test failed: 5: format 0008 got data 00BF88D8 clipboard.c:853: Test failed: 5.1: formats 00000000 have been rendered clipboard.c:858: Test failed: 5.1: formats 00000000 have been rendered clipboard.c:852: Test failed: 5: format 0011 got data 00BF8AA8 clipboard.c:853: Test failed: 5.2: formats 00000000 have been rendered clipboard.c:858: Test failed: 5.2: formats 00000000 have been rendered monitor: Timeout win.c:10351: Test failed: Expected foreground window 000D013E, got 00D400CC
=== debiant (32 bit WoW report) ===
user32: monitor: Timeout win.c:11736: Test failed: got normal pos (200,88)-(400,288) win.c:11739: Test failed: got window rect (200,88)-(400,288) win.c:11752: Test failed: got normal pos (200,88)-(400,288)
=== debiant (64 bit WoW report) ===
user32: monitor: Timeout
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=77966
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:3849: Test failed: hwnd 00060052 message 0738
=== w1064v1809_ar (32 bit report) ===
user32: win.c:9478: Test failed: Timed out waiting for the child process
=== w1064v1809_he (32 bit report) ===
user32: win.c:3855: Test failed: message 0738 available win.c:9974: Test failed: pos = 00e700d0 win.c:9978: Test failed: pos = 00e700d0 win.c:9982: Test failed: pos = 00e700d0
=== w1064v1809_ja (32 bit report) ===
user32: win.c:3849: Test failed: hwnd 000202EE message 7fff win.c:3928: Test failed: hwnd 000202EE/00250302 message 7fff win.c:3931: Test failed: hwnd 000202EE/00250302 message 7fff
=== w1064v1809_zh_CN (32 bit report) ===
user32: win.c:3849: Test failed: hwnd 0003008E message 0282 win.c:3928: Test failed: hwnd 0003008E/000C03A2 message 0282 win.c:3931: Test failed: hwnd 0003008E/000C03A2 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:3849: Test failed: hwnd 0000000000040066 message 0738