[PATCH 0/1] MR10699: Revert "win32u: Don't forcefully activate windows before restoring them."
This reverts commit f82b115dfcf3eefbbb533d31976d178e21bf1237. f82b115d was intended to fix SDL3 applications unexpectedly switching to the native display mode. However, after further investigations, the bug is caused by other issues rather than the NtUserSetActiveWindow() call. In fact, by tracing the message sequence when restoring a window, there should be a WM_ACTIVATE message before WM_SYSCOMMAND SC_RESTORE. Fix Warhammer: Vermintide 2 (552500) failing to enter fullscreen mode after focus loss. The game needs a WM_ACTIVATE message before WM_SYSCOMMAND SC_RESTORE. The SDL3 application unexpectedly switches to the native display mode bug is caused by the following: **(1) The 16-bit display mode format gets overwritten** Please see https://gitlab.winehq.org/wine/wine/-/merge_requests/10697 for details. **(2) Window managers restore minimized windows with the current display mode** For example, an SDL3 game on a 1920x1080 monitor uses 1024x768 display mode. When the game gets minimized, say by Alt+Tab, it will set the display mode back to 1920x1080. When the game window gets restored, the window manager will resize the window to 1920x1080 because the window still has __NET_WM_STATE_FULLSCREEN set even though it's minimized. So a WM_WINDOWPOSCHANGE (1920x1080) is sent to the game window. The game processes the WM_WINDOWPOSCHANGE and changes to the previous 1024x768 display mode. So a WM_WINDOWPOSCHANGE (1024x768) will be sent later once the WM finishes processing the display change event. However, there might be a delay between the WM_WINDOWPOSCHANGE (1920x1080) and WM_WINDOWPOSCHANGE (1024x768). So if the game finishes WM_WINDOWPOSCHANGE (1920x1080) and it can't find more messages, then it will trigger a render update and use the current window size (1920x1080) to adjust the display mode, causing it to revert to the native display mode instead of the specified one. See SDL3 testwm.c main message loop for example. The root cause is the difference in the behavior of WM on Linux and Windows. Windows still uses the old window size when restoring a window, even though the display mode is changed. The presence of `__NET_WM_STATE_FULLSCREEN` on Linux makes the WM choose the current display size instead of the previous window size. I tried removing `__NET_WM_STATE_FULLSCREEN` for a window when it gets minimized. But it will trigger unexpected size changes because removing `__NET_WM_STATE_FULLSCREEN` causes WMs to restore the window to its previous size before fullscreen. Unfortunately, I haven't thought of a reliable way to fix this. Anyway, it did prove that it's not related to the NtUserSetActiveWindow() call. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10699
From: Zhiyi Zhang <zzhang@codeweavers.com> This reverts commit f82b115dfcf3eefbbb533d31976d178e21bf1237. f82b115d was intended to fix SDL3 applications unexpectedly switching to the native display mode. However, after further investigations, the bug is caused by other issues rather than the NtUserSetActiveWindow() call. In fact, by tracing the message sequence when restoring a window, there should be a WM_ACTIVATE message before WM_SYSCOMMAND SC_RESTORE. Fix Warhammer: Vermintide 2 (552500) failing to enter fullscreen mode after focus loss. The game needs a WM_ACTIVATE message before WM_SYSCOMMAND SC_RESTORE. --- dlls/win32u/message.c | 5 +++-- dlls/winemac.drv/window.c | 1 + dlls/winex11.drv/window.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index fe0cd2a61fe..7a54d30e416 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2231,13 +2231,14 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR window_rect = map_rect_raw_to_virt( window_rect, get_thread_dpi() ); if (foreground) set_foreground_window( foreground, FALSE, TRUE ); - switch (state_cmd) + switch (LOWORD(state_cmd)) { case SC_RESTORE: + if (HIWORD(state_cmd)) NtUserSetActiveWindow( hwnd ); NtUserSetInternalWindowPos( hwnd, SW_SHOW, &window_rect, NULL ); /* fallthrough */ default: - send_message( hwnd, WM_SYSCOMMAND, state_cmd, 0 ); + send_message( hwnd, WM_SYSCOMMAND, LOWORD(state_cmd), 0 ); break; case 0: if (!swp_flags) break; diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 5236cda0baa..2cc11b7dc1e 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1877,6 +1877,7 @@ void macdrv_window_did_unminimize(HWND hwnd) { TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window); release_win_data(data); + NtUserSetActiveWindow(hwnd); send_message(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); return; } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index a83359b2d74..d2d53a40be3 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1700,8 +1700,9 @@ static UINT window_update_client_state( struct x11drv_win_data *data ) } else if (old_style & (WS_MINIMIZE | WS_MAXIMIZE)) { + BOOL activate = (old_style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE); TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window ); - return SC_RESTORE; + return MAKELONG(SC_RESTORE, activate); } } if (!(old_style & WS_MINIMIZE) && (new_style & WS_MINIMIZE)) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10699
This merge request was approved by Rémi Bernon. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10699
participants (3)
-
Rémi Bernon (@rbernon) -
Zhiyi Zhang -
Zhiyi Zhang (@zhiyi)