From b3d16ce501856b4ab62a805fb7ec8a6977574481 Mon Sep 17 00:00:00 2001 From: David Gow Date: Tue, 11 Apr 2023 16:08:11 +0800 Subject: [PATCH] winex11.drv: Don't reconfigure window on redundant position updates sync_window_position() calls XReconfigureWMWindow() to update the window with a new position or size. However, it unconditionally assumes that the size has changed, and sets the mask and calls XReconfigureWMWindow() anyway. In addition, it will toggle the fullscreen state on KWin, to work around the fact that _NET_WM_FULLSCREEN windows can't be moved there. Instead, only set the mask based on which properties have actually changed, and don't do anything (except updating shaped windows, if required) if the resulting mask is 0. This fixes an issue with the Elder Scrolls Online installer, which can cause Xorg (and even Xwayland) to hang due to ending up in a Reconfigure loop. Signed-off-by: David Gow --- dlls/winex11.drv/window.c | 41 +++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index d4d3c874201..ff4520fc08e 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1578,18 +1578,22 @@ static HWND sync_window_position( struct x11drv_win_data *data, if (changes.width <= 0 || changes.height <= 0) changes.width = changes.height = 1; if (changes.width > 65535) changes.width = 65535; if (changes.height > 65535) changes.height = 65535; - mask |= CWWidth | CWHeight; } /* only the size is allowed to change for the desktop window */ if (data->whole_window != root_window) { POINT pt = virtual_screen_to_root( data->whole_rect.left, data->whole_rect.top ); + POINT old_pt = virtual_screen_to_root( old_whole_rect->left, old_whole_rect->top ); changes.x = pt.x; changes.y = pt.y; - mask |= CWX | CWY; + if (changes.x != old_pt.x) mask |= CWX; + if (changes.y != old_pt.y) mask |= CWY; } + if (changes.width != old_whole_rect->right - old_whole_rect->left) mask |= CWWidth; + if (changes.height != old_whole_rect->bottom - old_whole_rect->top) mask |= CWHeight; + if (!(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW)) { /* find window that this one must be after */ @@ -1606,23 +1610,26 @@ static HWND sync_window_position( struct x11drv_win_data *data, /* and Above with a sibling doesn't work so well either, so we ignore it */ } - set_size_hints( data, style ); - set_mwm_hints( data, style, ex_style ); - /* KWin doesn't allow moving a window with _NET_WM_STATE_FULLSCREEN set. So we need to remove - * _NET_WM_STATE_FULLSCREEN before moving the window and restore it later */ - if (wm_is_kde( data->display ) && is_window_rect_full_screen( &data->whole_rect )) - { - original_rect = data->whole_rect; - SetRectEmpty( &data->whole_rect ); - } - update_net_wm_states( data ); - data->configure_serial = NextRequest( data->display ); - XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); - - if (!IsRectEmpty( &original_rect )) + if (mask) { - data->whole_rect = original_rect; + set_size_hints( data, style ); + set_mwm_hints( data, style, ex_style ); + /* KWin doesn't allow moving a window with _NET_WM_STATE_FULLSCREEN set. So we need to remove + * _NET_WM_STATE_FULLSCREEN before moving the window and restore it later */ + if (wm_is_kde( data->display ) && is_window_rect_full_screen( &data->whole_rect )) + { + original_rect = data->whole_rect; + SetRectEmpty( &data->whole_rect ); + } update_net_wm_states( data ); + data->configure_serial = NextRequest( data->display ); + XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); + + if (!IsRectEmpty( &original_rect )) + { + data->whole_rect = original_rect; + update_net_wm_states( data ); + } } #ifdef HAVE_LIBXSHAPE if (IsRectEmpty( old_window_rect ) != IsRectEmpty( &data->window_rect ))