This removes the window rect checks that were there to unmap visible windows when they are outside of the virtual screen. Since the recent changes to window config update, and the removal of WindowPosChanged re-entry guards, we now more accurately match the states between win32, winex11 and X server and it caused some windows to now be unmapped spuriously. This happens when the window manager positions the outside of what we believe is the virtual screen, for instance with embedded or FVWM virtual desktops.
I am not sure what unmapping offscreen windows is for exactly, I suspect it is to allow some windows to be moved offscreen even though the WM would probably not allow it with visible windows. I think that if windows are managed by the host WM, we should allow it to control and constraint the windows to be on-screen if it decides so. Alternatively we could perhaps decide to minimize them instead (as a winex11 internal state, without notifying the Win32 side of minimization), as unmapping the windows will also make them disappear from the window selector, and makes it impossible to focus them back.
From: Rémi Bernon rbernon@codeweavers.com
The desired_state.wm_state check should be enough to decide whether the window was supposed to be visible or not, and whether it needs to be unmapped.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57472 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57474 --- dlls/winex11.drv/window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 1a341adc921..1ed87650926 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2952,7 +2952,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UIN if (old_style & WS_VISIBLE) { if (((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE)) || - (!(new_style & WS_MINIMIZE) && !is_window_rect_mapped( &new_rects->window ) && is_window_rect_mapped( &old_rects.window ))) + (!(new_style & WS_MINIMIZE) && !is_window_rect_mapped( &new_rects->window ))) { release_win_data( data ); unmap_window( hwnd );
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57472 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57474 --- dlls/winex11.drv/window.c | 70 +++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 1ed87650926..102317d5695 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2922,19 +2922,26 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UIN
if (!(data = get_win_data( hwnd ))) return;
+ TRACE( "win %p/%lx new_rects %s style %08x flags %08x\n", hwnd, data->whole_window, + debugstr_window_rects(new_rects), new_style, swp_flags ); + old_style = new_style & ~(WS_VISIBLE | WS_MINIMIZE | WS_MAXIMIZE); if (data->desired_state.wm_state != WithdrawnState) old_style |= WS_VISIBLE; if (data->desired_state.wm_state == IconicState) old_style |= WS_MINIMIZE; if (data->desired_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) old_style |= WS_MAXIMIZE;
+ /* don't try mapping the window if it is outside of the virtual screen */ + if (!(new_style & WS_MINIMIZE) && !is_window_rect_mapped( &new_rects->window )) + { + swp_flags |= SWP_HIDEWINDOW; + new_style &= ~WS_VISIBLE; + } + old_rects = data->rects; was_fullscreen = data->is_fullscreen; data->rects = *new_rects; data->is_fullscreen = fullscreen;
- TRACE( "win %p/%lx new_rects %s style %08x flags %08x\n", hwnd, data->whole_window, - debugstr_window_rects(new_rects), new_style, swp_flags ); - XFlush( gdi_display ); /* make sure painting is done before we move the window */
sync_client_position( data, &old_rects ); @@ -2949,16 +2956,12 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UIN return; }
- if (old_style & WS_VISIBLE) + if ((old_style & WS_VISIBLE) && (swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE)) { - if (((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE)) || - (!(new_style & WS_MINIMIZE) && !is_window_rect_mapped( &new_rects->window ))) - { - release_win_data( data ); - unmap_window( hwnd ); - if (was_fullscreen) NtUserClipCursor( NULL ); - if (!(data = get_win_data( hwnd ))) return; - } + release_win_data( data ); + unmap_window( hwnd ); + if (was_fullscreen) NtUserClipCursor( NULL ); + if (!(data = get_win_data( hwnd ))) return; }
/* don't change position if we are about to minimize or maximize a managed window */ @@ -2981,8 +2984,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UIN #endif }
- if ((new_style & WS_VISIBLE) && - ((new_style & WS_MINIMIZE) || is_window_rect_mapped( &new_rects->window ))) + if (new_style & WS_VISIBLE) { if (!(old_style & WS_VISIBLE)) { @@ -3129,6 +3131,7 @@ void X11DRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw ) */ void X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags ) { + DWORD old_style, new_style = NtUserGetWindowLongW( hwnd, GWL_STYLE ); struct x11drv_win_data *data = get_win_data( hwnd );
if (data) @@ -3137,21 +3140,18 @@ void X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWO
if (data->whole_window) sync_window_opacity( data->display, data->whole_window, alpha, flags ); - data->layered = TRUE; - if (data->desired_state.wm_state == WithdrawnState) /* mapping is delayed until attributes are set */ - { - DWORD style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE );
- if ((style & WS_VISIBLE) && - ((style & WS_MINIMIZE) || is_window_rect_mapped( &data->rects.window ))) - { - release_win_data( data ); - map_window( hwnd, style ); - return; - } - } + old_style = new_style & ~(WS_VISIBLE | WS_MINIMIZE | WS_MAXIMIZE); + if (data->desired_state.wm_state != WithdrawnState) old_style |= WS_VISIBLE; + + /* don't try mapping the window if it is outside of the virtual screen */ + if (!(new_style & WS_MINIMIZE) && !is_window_rect_mapped( &data->rects.window )) new_style &= ~WS_VISIBLE; + release_win_data( data ); + + /* layered windows are mapped only once their attributes are set */ + if (!(old_style & WS_VISIBLE) && (new_style & WS_VISIBLE)) map_window( hwnd, new_style ); } else { @@ -3171,21 +3171,21 @@ void X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWO */ void X11DRV_UpdateLayeredWindow( HWND hwnd, UINT flags ) { + DWORD old_style, new_style = NtUserGetWindowLongW( hwnd, GWL_STYLE ); struct x11drv_win_data *data; - BOOL mapped;
if (!(data = get_win_data( hwnd ))) return; - mapped = data->desired_state.wm_state != WithdrawnState; + + old_style = new_style & ~(WS_VISIBLE | WS_MINIMIZE | WS_MAXIMIZE); + if (data->desired_state.wm_state != WithdrawnState) old_style |= WS_VISIBLE; + + /* don't try mapping the window if it is outside of the virtual screen */ + if (!(new_style & WS_MINIMIZE) && !is_window_rect_mapped( &data->rects.window )) new_style &= ~WS_VISIBLE; + release_win_data( data );
/* layered windows are mapped only once their attributes are set */ - if (!mapped) - { - DWORD style = NtUserGetWindowLongW( hwnd, GWL_STYLE ); - - if ((style & WS_VISIBLE) && ((style & WS_MINIMIZE) || is_window_rect_mapped( &data->rects.window ))) - map_window( hwnd, style ); - } + if (!(old_style & WS_VISIBLE) && (new_style & WS_VISIBLE)) map_window( hwnd, new_style ); }
From: Rémi Bernon rbernon@codeweavers.com
Depending on the window manager, the windows may not be inside what we think is the virtual screen. We should try to map them nonetheless if they are visible.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57472 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57474 --- dlls/winex11.drv/window.c | 13 ------------- dlls/winex11.drv/x11drv.h | 9 --------- 2 files changed, 22 deletions(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 102317d5695..14049525b8d 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2930,13 +2930,6 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UIN if (data->desired_state.wm_state == IconicState) old_style |= WS_MINIMIZE; if (data->desired_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) old_style |= WS_MAXIMIZE;
- /* don't try mapping the window if it is outside of the virtual screen */ - if (!(new_style & WS_MINIMIZE) && !is_window_rect_mapped( &new_rects->window )) - { - swp_flags |= SWP_HIDEWINDOW; - new_style &= ~WS_VISIBLE; - } - old_rects = data->rects; was_fullscreen = data->is_fullscreen; data->rects = *new_rects; @@ -3145,9 +3138,6 @@ void X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWO old_style = new_style & ~(WS_VISIBLE | WS_MINIMIZE | WS_MAXIMIZE); if (data->desired_state.wm_state != WithdrawnState) old_style |= WS_VISIBLE;
- /* don't try mapping the window if it is outside of the virtual screen */ - if (!(new_style & WS_MINIMIZE) && !is_window_rect_mapped( &data->rects.window )) new_style &= ~WS_VISIBLE; - release_win_data( data );
/* layered windows are mapped only once their attributes are set */ @@ -3179,9 +3169,6 @@ void X11DRV_UpdateLayeredWindow( HWND hwnd, UINT flags ) old_style = new_style & ~(WS_VISIBLE | WS_MINIMIZE | WS_MAXIMIZE); if (data->desired_state.wm_state != WithdrawnState) old_style |= WS_VISIBLE;
- /* don't try mapping the window if it is outside of the virtual screen */ - if (!(new_style & WS_MINIMIZE) && !is_window_rect_mapped( &data->rects.window )) new_style &= ~WS_VISIBLE; - release_win_data( data );
/* layered windows are mapped only once their attributes are set */ diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 860ba22eae4..607892b2f51 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -850,15 +850,6 @@ extern void xim_set_focus( HWND hwnd, BOOL focus );
#define XEMBED_MAPPED (1 << 0)
-static inline BOOL is_window_rect_mapped( const RECT *rect ) -{ - RECT virtual_rect = NtUserGetVirtualScreenRect( MDT_RAW_DPI ); - return (rect->left < virtual_rect.right && - rect->top < virtual_rect.bottom && - max( rect->right, rect->left + 1 ) > virtual_rect.left && - max( rect->bottom, rect->top + 1 ) > virtual_rect.top); -} - /* unixlib interface */
extern NTSTATUS x11drv_tablet_attach_queue( void *arg );
I am not sure what unmapping offscreen windows is for exactly, I suspect it is to allow some windows to be moved offscreen even though the WM would probably not allow it with visible windows. I think that if windows are managed by the host WM, we should allow it to control and constraint the windows to be on-screen if it decides so. Alternatively we could perhaps decide to minimize them instead (as a winex11 internal state, without notifying the Win32 side of minimization), as unmapping the windows will also make them disappear from the window selector, and makes it impossible to focus them back.
It was added because there are apps that move a window offscreen to hide it, and as you noted the WM usually wouldn't allow that.
iirc Disgaea 5 moves window outside of screen limit, renders video to it and blits to visible window.
Allowing VM to fit it into screen will break it. Some Windows apps also like to create a window bigger than fullscreen (e. g. targeting client area to be fullscreen).