From: Rémi Bernon <rbernon@codeweavers.com> Since https://gitlab.winehq.org/wine/wine/-/merge_requests/10699 and the revert of f82b115dfcf3eefbbb533d31976d178e21bf1237 we now call again into the window message proc before the restored state is applied to the win32 side. Any call to SetWindowPos, and more precisely any call that ends up in apply_window_pos and drivers WindowPosChanged, will request the win32 state again to the host, racing with the restored state being applied. In most cases this will resolve on its own when SC_RESTORE overrides the requests with the restored state again, but it emits a spurious minize / restore state requests that can confuse some picky window managers. If we're unlucky enough we might even process the transient state before SC_RESTORE. --- dlls/win32u/message.c | 4 +++- dlls/winex11.drv/window.c | 35 ++++++++++++++++++++++++++--------- dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index d432eb3c1af..8c9a2aaef7c 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2235,7 +2235,7 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR RECT window_rect; HWND foreground; - if (!user_driver->pGetWindowStateUpdates( hwnd, &state_cmd, &swp_flags, &window_rect, &foreground )) return 0; + if (!user_driver->pGetWindowStateUpdates( hwnd, &state_cmd, &swp_flags, &window_rect, &foreground )) goto unlock; window_rect = map_rect_raw_to_virt( window_rect, get_thread_dpi() ); if (foreground) set_foreground_window( foreground, FALSE, TRUE ); @@ -2258,6 +2258,8 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR break; } + unlock: + user_driver->pGetWindowStateUpdates( hwnd, NULL, NULL, NULL, NULL ); /* unlock the host state */ return 0; } case WM_WINE_UPDATEWINDOWSTATE: diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 297695749a1..cbc6f0c5b4d 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -991,6 +991,7 @@ static void window_set_mwm_hints( struct x11drv_win_data *data, const MwmHints * const MwmHints *old_hints = &data->pending_state.mwm_hints; data->desired_state.mwm_hints = *new_hints; + if (data->state_locks) return; /* win32 state is being updated, delay the change */ if (!data->whole_window || !data->managed || data->embedded) return; /* no window or not managed, nothing to update */ if (!memcmp( old_hints, new_hints, sizeof(*new_hints) )) return; /* hints are the same, nothing to update */ @@ -1277,6 +1278,7 @@ static void window_set_net_wm_fullscreen_monitors( struct x11drv_win_data *data, data->desired_state.monitors = *new_monitors; if (!(data->pending_state.net_wm_state & (1 << NET_WM_STATE_FULLSCREEN)) || is_virtual_desktop()) return; /* window isn't fullscreen, delay updating */ + if (data->state_locks) return; /* win32 state is being updated, delay the change */ if (!data->whole_window || !data->managed || data->embedded) return; /* no window or not managed, nothing to update */ if (!memcmp( old_monitors, new_monitors, sizeof(*new_monitors) )) return; /* states are the same, nothing to update */ @@ -1334,6 +1336,7 @@ static void window_set_net_wm_state( struct x11drv_win_data *data, UINT new_stat new_state &= x11drv_init_thread_data()->net_wm_state_mask; data->desired_state.net_wm_state = new_state; + if (data->state_locks) return; /* win32 state is being updated, delay the change */ if (!data->whole_window || !data->managed || data->embedded) return; /* no window or not managed, nothing to update */ if (data->wm_state_serial) return; /* another WM_STATE update is pending, wait for it to complete */ /* we ignore and override previous _NET_WM_STATE update requests */ @@ -1421,6 +1424,7 @@ static void window_set_config( struct x11drv_win_data *data, RECT rect, BOOL abo data->desired_state.rect = *new_rect; data->desired_state.above = above; + if (data->state_locks) return; /* win32 state is being updated, delay the change */ if (!data->whole_window) return; /* no window, nothing to update */ if (EqualRect( old_rect, new_rect ) && (old_above || !above || data->managed)) return; /* rects are the same, no need to be raised, nothing to update */ if (window_needs_config_change_delay( data )) @@ -1575,6 +1579,7 @@ static void window_set_wm_state( struct x11drv_win_data *data, UINT new_state, B data->desired_state.wm_state = new_state; data->desired_state.activate = activate; + if (data->state_locks) return; /* win32 state is being updated, delay the change */ if (!data->whole_window) return; /* no window, nothing to update */ if (data->wm_state_serial && !data->current_state.wm_state != !data->pending_state.wm_state) return; /* another map/unmap WM_STATE update is pending, wait for it to complete */ @@ -1787,6 +1792,15 @@ static UINT window_update_client_config( struct x11drv_win_data *data ) return flags; } +static void window_request_desired_state( struct x11drv_win_data *data ) +{ + window_set_wm_state( data, data->desired_state.wm_state, data->desired_state.activate ); + window_set_net_wm_state( data, data->desired_state.net_wm_state ); + window_set_net_wm_fullscreen_monitors( data, &data->desired_state.monitors ); + window_set_mwm_hints( data, &data->desired_state.mwm_hints ); + window_set_config( data, data->desired_state.rect, FALSE ); +} + /*********************************************************************** * GetWindowStateUpdates (X11DRV.@) */ @@ -1796,6 +1810,17 @@ BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *swp_flags, struct x11drv_win_data *data; HWND old_foreground; + if (!state_cmd) + { + if ((data = get_win_data( hwnd ))) + { + if (!--data->state_locks) TRACE( "Unlocked window %p/%lx state\n", data->hwnd, data->whole_window ); + window_request_desired_state( data ); + release_win_data( data ); + } + return FALSE; + } + *state_cmd = *swp_flags = 0; *foreground = 0; @@ -1810,6 +1835,7 @@ BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *swp_flags, if ((data = get_win_data( hwnd ))) { + if (!data->state_locks++) TRACE( "Locked window %p/%lx state\n", data->hwnd, data->whole_window ); *state_cmd = window_update_client_state( data ); *swp_flags = window_update_client_config( data ); *rect = window_rect_from_visible( &data->rects, data->current_state.rect ); @@ -1850,15 +1876,6 @@ static BOOL handle_state_change( unsigned long serial, unsigned long *expect_ser return TRUE; } -static void window_request_desired_state( struct x11drv_win_data *data ) -{ - window_set_wm_state( data, data->desired_state.wm_state, data->desired_state.activate ); - window_set_net_wm_state( data, data->desired_state.net_wm_state ); - window_set_net_wm_fullscreen_monitors( data, &data->desired_state.monitors ); - window_set_mwm_hints( data, &data->desired_state.mwm_hints ); - window_set_config( data, data->desired_state.rect, FALSE ); -} - void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value, Time time ) { UINT *desired = &data->desired_state.wm_state, *pending = &data->pending_state.wm_state, *current = &data->current_state.wm_state; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 4325c99e5c5..9ed169996ce 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -709,6 +709,7 @@ struct x11drv_win_data unsigned long wm_normal_hints_serial;/* serial of last pending WM_NORMAL_HINTS request */ unsigned long configure_serial; /* serial of last pending configure request */ unsigned long net_wm_icon_serial; /* serial of last pending _NET_WM_ICON request */ + unsigned long state_locks; /* X11 state requests lock while updating win32 state */ }; extern struct x11drv_win_data *get_win_data( HWND hwnd ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11556