-- v2: winex11: Respect swp_flags when syncing window position.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Since 895ca2eda64f506b936999cdd8f14e224eef6a7f, we're not telling Win32 side of the fact the window moved offscreen. This means any SetWindowPos sent afterwards has potential to resync the Window and "put it on screen again", even if such operation has SWP_NOMOVE or SWP_NOSIZE. This causes some fullscreen apps to follow the workspace/desktop instead of remaining offscreen.
Fixes a regression introduced by 895ca2eda64f506b936999cdd8f14e224eef6a7f.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/winex11.drv/window.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 1d43c4edbdb..9c92f9e8a7f 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1778,6 +1778,7 @@ static void sync_window_position( struct x11drv_win_data *data, UINT swp_flags ) DWORD style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); DWORD ex_style = NtUserGetWindowLongW( data->hwnd, GWL_EXSTYLE ); BOOL above = FALSE; + RECT new_rect;
if (data->managed && data->desired_state.wm_state == IconicState) return;
@@ -1795,7 +1796,19 @@ static void sync_window_position( struct x11drv_win_data *data, UINT swp_flags ) set_size_hints( data, style ); set_mwm_hints( data, style, ex_style ); update_net_wm_states( data ); - window_set_config( data, &data->rects.visible, above ); + + new_rect = data->rects.visible; + if (swp_flags & SWP_NOSIZE) + { + new_rect.right = new_rect.left + data->desired_state.rect.right - data->desired_state.rect.left; + new_rect.bottom = new_rect.top + data->desired_state.rect.bottom - data->desired_state.rect.top; + } + if (swp_flags & SWP_NOMOVE) + { + OffsetRect( &new_rect, data->desired_state.rect.left - new_rect.left, + data->desired_state.rect.top - new_rect.top ); + } + window_set_config( data, &new_rect, above ); }
On Thu Jan 9 19:49:25 2025 +0000, Gabriel Ivăncescu wrote:
Merge request https://gitlab.winehq.org/wine/wine/-/merge_requests/7116 was
reviewed by Rémi Bernon
--
Rémi Bernon started a new discussion on dlls/winex11.drv/window.c: https://gitlab.winehq.org/wine/wine/-/merge_requests/7116#note_91691
- }
- new_rect.right = new_rect.left + new_width;
- new_rect.bottom = new_rect.top + new_height;
What about shortening it like this? Also using `desired_state` is probably better here, in case window config request is being delayed.
new_rect = data->rects.visible; if (swp_flags & SWP_NOSIZE) { new_rect.right = new_rect.left + data->desired_state.rect.right - data->desired_state.rect.left; new_rect.bottom = new_rect.top + data->desired_state.rect.bottom - data->desired_state.rect.top; } if (swp_flags & SWP_NOMOVE) { OffsetRect( &new_rect, data->desired_state.rect.left - new_rect.left, data->desired_state.rect.top - new_rect.top ); }
Sure. For `desired_state`, I'm a bit confused of how it all works, I just took it from `window_set_config` old_rect. But yes that works too.
`desired_state` is the X window state that would match the current Win32 state, `pending_state` which is the state that was last requested to the X server, `current_state` is the state that corresponds to the last window config/state notify event we've received.
Obviously `current_state` differs from `pending_state` as soon as we're requesting a change, until we've received the corresponding notify. `pending_state` and `desired_state` may differ when we decide to delay some requests, if there's some requested changes already pending.
When the notify event is received, we'll either continue by requesting the `desired_state` again, if the notify matches our expectations, or, if it does not, we will temporarily ignore the `desired_state` and notify the Win32 state of an unexpected window config/state change.
This merge request was approved by Rémi Bernon.
On Thu Jan 9 19:52:35 2025 +0000, Rémi Bernon wrote:
`desired_state` is the X window state that would match the current Win32 state, `pending_state` which is the state that was last requested to the X server, `current_state` is the state that corresponds to the last window config/state notify event we've received. Obviously `current_state` differs from `pending_state` as soon as we're requesting a change, until we've received the corresponding notify. `pending_state` and `desired_state` may differ when we decide to delay some requests, if there's some requested changes already pending, as requesting changes while other are still pending is often confusing window managers, or is simply invalid (for window map/unmap requests). When the notify event is received, we'll either continue by requesting any delayed `desired_state` change, if the notify matches our expectations, or, if it does not, we will temporarily ignore the `desired_state` and notify the Win32 side of an unexpected window config/state change.
Thank you, that clears it up. One last question: why do we have to request the `desired_state` again after receiving a notify and it matches? Isn't it a no-op?
On Thu Jan 9 20:42:56 2025 +0000, Gabriel Ivăncescu wrote:
Thank you, that clears it up. One last question: why do we have to request the `desired_state` again after receiving a notify and it matches? Isn't it a no-op?
The notify would match the `pending_state`, the desired_state may have been updated in between if the Win32 application has changed something, and we need to request these changes if we have decided to delay the requests.