[PATCH 0/3] MR10487: winewayland: Fix display freeze for games that fake-minimize
CryEngine games (e.g., Hunt: Showdown) fake-minimize during startup in exclusive fullscreen by setting WS_MINIMIZE and moving to (-32000,-32000). The driver sent xdg_toplevel_unset_fullscreen, causing the compositor to respond with a 0x0 configure that the surface never recovered from. - Fix a use-after-release on data-\>rects in wayland_configure_window - Detect WS_MINIMIZE and call xdg_toplevel_set_minimized instead of unsetting fullscreen/maximized - Handle restore by acking the configure and sending SC_RESTORE when the window is at the sentinel position with WS_MINIMIZE set Wine-Bug: http://bugs.winehq.org/show_bug.cgi?id=59577 -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10487
From: Cwooper <cwooperm@gmail.com> wayland_configure_window() accesses data->rects.window after calling wayland_win_data_release(data). Save the window position into local variables before the release. --- dlls/winewayland.drv/window.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index 2c3d1f87408..fff3eed36f6 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -495,6 +495,7 @@ static void wayland_configure_window(HWND hwnd) BOOL needs_exit_size_move = FALSE; struct wayland_win_data *data; RECT rect; + LONG saved_window_left, saved_window_top; if (!(data = wayland_win_data_get(hwnd))) return; if (!(surface = data->wayland_surface)) @@ -575,6 +576,11 @@ static void wayland_configure_window(HWND hwnd) wayland_surface_coords_to_window(surface, width, height, &window_width, &window_height); + /* Save window position before releasing data, since data->rects may be + * modified by another thread after release. */ + saved_window_left = data->rects.window.left; + saved_window_top = data->rects.window.top; + wayland_win_data_release(data); TRACE("processing=%dx%d,%#x\n", width, height, state); @@ -601,7 +607,7 @@ static void wayland_configure_window(HWND hwnd) } SetRect(&rect, 0, 0, window_width, window_height); - OffsetRect(&rect, data->rects.window.left, data->rects.window.top); + OffsetRect(&rect, saved_window_left, saved_window_top); NtUserSetRawWindowPos(hwnd, rect, flags, FALSE); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10487
From: Cwooper <cwooperm@gmail.com> When a window sets WS_MINIMIZE, the driver was sending xdg_toplevel_unset_fullscreen/unset_maximized, causing the compositor to respond with a 0x0 configure that stalls Vulkan present. Detect WS_MINIMIZE and call xdg_toplevel_set_minimized instead, suppressing the incorrect unset transitions. Wine-Bug: http://bugs.winehq.org/show_bug.cgi?id=59577 --- dlls/winewayland.drv/waylanddrv.h | 1 + dlls/winewayland.drv/window.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index ad41a1b474e..4aef4d2e9b9 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -235,6 +235,7 @@ struct wayland_window_config double scale; BOOL visible; BOOL managed; + BOOL minimized; }; struct wayland_client_surface diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index fff3eed36f6..ea98618ca36 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -159,6 +159,8 @@ static void wayland_win_data_get_config(struct wayland_win_data *data, TRACE("window=%s style=%#x\n", wine_dbgstr_rect(&conf->rect), style); + conf->minimized = !!(style & WS_MINIMIZE); + /* The fullscreen state is implied by the window position and style. */ if (data->is_fullscreen) { @@ -267,12 +269,14 @@ static void wayland_surface_update_state_toplevel(struct wayland_surface *surfac /* First do all state unsettings, before setting new state. Some * Wayland compositors misbehave if the order is reversed. */ if (!(surface->window.state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) && - (surface->current.state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED)) + (surface->current.state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) && + !surface->window.minimized) { xdg_toplevel_unset_maximized(surface->xdg_toplevel); } if (!(surface->window.state & WAYLAND_SURFACE_CONFIG_STATE_FULLSCREEN) && - (surface->current.state & WAYLAND_SURFACE_CONFIG_STATE_FULLSCREEN)) + (surface->current.state & WAYLAND_SURFACE_CONFIG_STATE_FULLSCREEN) && + !surface->window.minimized) { xdg_toplevel_unset_fullscreen(surface->xdg_toplevel); } @@ -287,6 +291,10 @@ static void wayland_surface_update_state_toplevel(struct wayland_surface *surfac { xdg_toplevel_set_fullscreen(surface->xdg_toplevel, NULL); } + if (surface->window.minimized) + { + xdg_toplevel_set_minimized(surface->xdg_toplevel); + } } else { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10487
From: Cwooper <cwooperm@gmail.com> When a window is at the offscreen sentinel position (-32000,-32000), has WS_MINIMIZE set, and the compositor sends a configure event, ack the configure to avoid a protocol violation and send SC_RESTORE to let Win32 handle the full restore sequence. This matches the XWayland behavior where the user clicks the taskbar to restore. Wine-Bug: http://bugs.winehq.org/show_bug.cgi?id=59577 --- dlls/winewayland.drv/window.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index ea98618ca36..3052429a7aa 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -501,6 +501,7 @@ static void wayland_configure_window(HWND hwnd) DWORD style; BOOL needs_enter_size_move = FALSE; BOOL needs_exit_size_move = FALSE; + BOOL restoring_from_minimize = FALSE; struct wayland_win_data *data; RECT rect; LONG saved_window_left, saved_window_top; @@ -589,6 +590,27 @@ static void wayland_configure_window(HWND hwnd) saved_window_left = data->rects.window.left; saved_window_top = data->rects.window.top; + /* Detect restore from minimize: the window is at the offscreen sentinel + * position (-32000,-32000) and the compositor is sending a configure. + * Send SC_RESTORE to let Win32 handle the full restore sequence (clearing + * WS_MINIMIZE, restoring position/size, sending WM_SIZE, etc.). + * We must ack the configure before returning to avoid a protocol + * violation, then let SC_RESTORE trigger a new configure cycle. */ + restoring_from_minimize = saved_window_left <= -32000 && + saved_window_top <= -32000 && + (NtUserGetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE); + if (restoring_from_minimize) + { + TRACE("hwnd=%p restoring from minimize\n", hwnd); + surface->current = surface->processing; + memset(&surface->processing, 0, sizeof(surface->processing)); + xdg_surface_ack_configure(surface->xdg_surface, + surface->current.serial); + wayland_win_data_release(data); + send_message(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); + return; + } + wayland_win_data_release(data); TRACE("processing=%dx%d,%#x\n", width, height, state); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10487
participants (2)
-
Cooper Morgan (@Cwooper) -
Cwooper