[PATCH v2 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 -- v2: winewayland: Restore minimized windows when compositor sends configure. winewayland: Handle WS_MINIMIZE to suppress incorrect state transitions. winewayland: Fix use-after-release of window rects in configure handler. https://gitlab.winehq.org/wine/wine/-/merge_requests/10487
From: Cwooper <cwooperm@gmail.com> wayland_configure_window() accessed data->rects.window after calling wayland_win_data_release(data). Compute the final window rect while the data is still held, and keep only the RECT local across the release. --- dlls/winewayland.drv/window.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index 2c3d1f87408..ae89f3c0c09 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -575,6 +575,9 @@ static void wayland_configure_window(HWND hwnd) wayland_surface_coords_to_window(surface, width, height, &window_width, &window_height); + SetRect(&rect, 0, 0, window_width, window_height); + OffsetRect(&rect, data->rects.window.left, data->rects.window.top); + wayland_win_data_release(data); TRACE("processing=%dx%d,%#x\n", width, height, state); @@ -600,8 +603,6 @@ static void wayland_configure_window(HWND hwnd) flags |= SWP_NOSENDCHANGING; } - SetRect(&rect, 0, 0, window_width, window_height); - OffsetRect(&rect, data->rects.window.left, data->rects.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 ae89f3c0c09..c75197c826e 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 the last requested config placed the window at the offscreen sentinel position (-32000,-32000) with 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 | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index c75197c826e..88eee3421d7 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; @@ -583,6 +584,28 @@ static void wayland_configure_window(HWND hwnd) wayland_surface_coords_to_window(surface, width, height, &window_width, &window_height); + /* Detect a restore from an application-initiated minimize: the last + * requested config placed the window at the offscreen sentinel position + * with WS_MINIMIZE, and the compositor is now sending a configure. Ack + * the configure to avoid a protocol violation and send SC_RESTORE so + * Win32 runs the full restore sequence (clearing WS_MINIMIZE, restoring + * position/size, sending WM_SIZE, etc.), which triggers a new configure + * cycle. */ + restoring_from_minimize = surface->window.rect.left <= -32000 && + surface->window.rect.top <= -32000 && + surface->window.minimized; + 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; + } + SetRect(&rect, 0, 0, window_width, window_height); OffsetRect(&rect, data->rects.window.left, data->rects.window.top); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10487
On Thu Apr 16 18:03:47 2026 +0000, Cooper Morgan wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/10487/diffs?diff_id=260908&start_sha=19780d095b43033b69dee9d33f306304937b32d9#be6b1a6381414c8dae6f91e46942652a04a69f08_601_587) Good catch. Switched to `surface->window.rect` / `surface->window.minimized` so the check uses the last requested config. Since the saved locals weren't used for anything else now, I also restructured the use-after-release fix in the first commit to move the rect computation before the release, which lets me drop the saved locals entirely. Net result is cleaner now in both commits.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10487#note_136568
On Thu Apr 16 18:05:20 2026 +0000, Cooper Morgan wrote:
Good catch. Switched to `surface->window.rect` / `surface->window.minimized` so the check uses the last requested config. Since the saved locals weren't used for anything else now, I also restructured the use-after-release fix in the first commit to move the rect computation before the release, which lets me drop the saved locals entirely. Net result is cleaner now in both commits. I think it should use surface->processing instead?
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10487#note_136697
On Fri Apr 17 08:45:24 2026 +0000, Rémi Bernon wrote:
I think it should use surface->processing instead? surface-\>processing is wayland_surface_config and doesn't carry rect or minimized -- only width/height/state/serial. Could you elaborate?
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10487#note_136888
On Sat Apr 18 03:39:07 2026 +0000, Cooper Morgan wrote:
surface-\>processing is wayland_surface_config and doesn't carry rect or minimized -- only width/height/state/serial. Could you elaborate? Sorry, I just got confused with all the different "configs" around.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10487#note_136895
This merge request was approved by Rémi Bernon. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10487
On Sun Apr 19 02:07:29 2026 +0000, Rémi Bernon wrote:
Sorry, I just got confused with all the different "configs" around. No worries, thanks for the review! The configs can be tricky
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10487#note_137037
participants (3)
-
Cooper Morgan (@Cwooper) -
Cwooper -
Rémi Bernon (@rbernon)