This prevents WMs like KWin or Mutter from automatically maximizing windows which frames are larger than their monitor area.
The maximization otherwise gets fed back into the win32 state, and often confuses applications which are operating a fullscreen window change by resizing a window then later changing its decoration.
It isn't possible to tell between a maximization initiated by the user and one that is initiated by the WM responding to a window resize from us. This heuristic should hopefully be good enough, as it is unlikely that the user will ever be able to resize a window in a such a way that its *frame* covers a monitor entirely. Note that if the user resizes a window such that its *visible* area covers a monitor entirely, we are going to make it fullscreen already anyway.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/window.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index c5c5d0522c8..56621e63b1b 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2157,10 +2157,10 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru WND *win; HWND owner_hint, surface_win = 0, parent = NtUserGetAncestor( hwnd, GA_PARENT ); BOOL ret, is_fullscreen, is_layered, is_child, need_icons = FALSE; + UINT raw_dpi, monitor_dpi, dpi = get_thread_dpi(); struct window_rects old_rects; RECT extra_rects[3]; struct window_surface *old_surface; - UINT raw_dpi, monitor_dpi; HICON icon, icon_small; ICONINFO ii, ii_small;
@@ -2169,9 +2169,9 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru is_child = parent && parent != NtUserGetDesktopWindow();
if (is_child) monitor_dpi = get_win_monitor_dpi( parent, &raw_dpi ); - else monitor_dpi = monitor_dpi_from_rect( new_rects->window, get_thread_dpi(), &raw_dpi ); + else monitor_dpi = monitor_dpi_from_rect( new_rects->window, dpi, &raw_dpi );
- get_window_rects( hwnd, COORDS_PARENT, &old_rects, get_thread_dpi() ); + get_window_rects( hwnd, COORDS_PARENT, &old_rects, dpi ); if (IsRectEmpty( &valid_rects[0] ) || is_layered) valid_rects = NULL;
if (!(win = get_win_ptr( hwnd )) || win == WND_DESKTOP || win == WND_OTHER_PROCESS) return FALSE; @@ -2185,8 +2185,8 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru valid_rects = NULL; }
- if (is_child) monitor_rects = map_dpi_window_rects( *new_rects, get_thread_dpi(), raw_dpi ); - else monitor_rects = map_window_rects_virt_to_raw( *new_rects, get_thread_dpi() ); + if (is_child) monitor_rects = map_dpi_window_rects( *new_rects, dpi, raw_dpi ); + else monitor_rects = map_window_rects_virt_to_raw( *new_rects, dpi );
SERVER_START_REQ( set_window_pos ) { @@ -2223,7 +2223,7 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru if (get_window_long( win->parent, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL) { RECT client = {0}; - get_client_rect_rel( win->parent, COORDS_CLIENT, &client, get_thread_dpi() ); + get_client_rect_rel( win->parent, COORDS_CLIENT, &client, dpi ); mirror_rect( &client, &win->rects.window ); mirror_rect( &client, &win->rects.client ); mirror_rect( &client, &win->rects.visible );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/driver.c | 2 +- dlls/win32u/window.c | 22 ++++++++++++++++------ dlls/wineandroid.drv/window.c | 2 +- dlls/winemac.drv/macdrv.h | 2 +- dlls/winemac.drv/window.c | 7 ++++--- dlls/winewayland.drv/waylanddrv.h | 2 +- dlls/winewayland.drv/window.c | 4 ++-- dlls/winex11.drv/window.c | 4 ++-- dlls/winex11.drv/x11drv.h | 2 +- include/wine/gdi_driver.h | 3 ++- 10 files changed, 31 insertions(+), 19 deletions(-)
diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 75d45a708b1..6bfdbb04829 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -890,7 +890,7 @@ static void nulldrv_MoveWindowBits( HWND hwnd, const struct window_rects *old_re { }
-static void nulldrv_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, BOOL fullscreen, +static void nulldrv_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, const struct window_rects *new_rects, struct window_surface *surface ) { } diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 56621e63b1b..1e86d21ae07 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2145,6 +2145,12 @@ HICON get_window_icon_info( HWND hwnd, UINT type, HICON icon, ICONINFO *ret ) return NULL; }
+static BOOL is_fullscreen( const MONITORINFO *info, const RECT *rect ) +{ + return rect->left <= info->rcMonitor.left && rect->right >= info->rcMonitor.right && + rect->top <= info->rcMonitor.top && rect->bottom >= info->rcMonitor.bottom; +} + /*********************************************************************** * apply_window_pos * @@ -2156,8 +2162,8 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru struct window_rects monitor_rects; WND *win; HWND owner_hint, surface_win = 0, parent = NtUserGetAncestor( hwnd, GA_PARENT ); - BOOL ret, is_fullscreen, is_layered, is_child, need_icons = FALSE; UINT raw_dpi, monitor_dpi, dpi = get_thread_dpi(); + BOOL ret, is_layered, is_child, need_icons = FALSE; struct window_rects old_rects; RECT extra_rects[3]; struct window_surface *old_surface; @@ -2165,7 +2171,6 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru ICONINFO ii, ii_small;
is_layered = new_surface && new_surface->alpha_mask; - is_fullscreen = is_window_rect_full_screen( &new_rects->visible, get_thread_dpi() ); is_child = parent && parent != NtUserGetDesktopWindow();
if (is_child) monitor_dpi = get_win_monitor_dpi( parent, &raw_dpi ); @@ -2185,9 +2190,6 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru valid_rects = NULL; }
- if (is_child) monitor_rects = map_dpi_window_rects( *new_rects, dpi, raw_dpi ); - else monitor_rects = map_window_rects_virt_to_raw( *new_rects, dpi ); - SERVER_START_REQ( set_window_pos ) { req->handle = wine_server_user_handle( hwnd ); @@ -2249,6 +2251,14 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru icon_small = win->hIconSmall2 ? win->hIconSmall2 : win->hIconSmall; win->has_icons = need_icons = TRUE; } + + if (is_child) monitor_rects = map_dpi_window_rects( *new_rects, dpi, raw_dpi ); + else + { + MONITORINFO monitor_info = monitor_info_from_rect( new_rects->window, dpi ); + if (is_fullscreen( &monitor_info, &new_rects->visible )) swp_flags |= WINE_SWP_FULLSCREEN; + monitor_rects = map_window_rects_virt_to_raw( *new_rects, dpi ); + } }
release_win_ptr( win ); @@ -2316,7 +2326,7 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru if (!owner_hint) owner_hint = NtUserWindowFromPoint(new_rects->window.left - 1, new_rects->window.top - 1); if (owner_hint) owner_hint = NtUserGetAncestor(owner_hint, GA_ROOT);
- user_driver->pWindowPosChanged( hwnd, insert_after, owner_hint, swp_flags, is_fullscreen, &monitor_rects, + user_driver->pWindowPosChanged( hwnd, insert_after, owner_hint, swp_flags, &monitor_rects, get_driver_window_surface( new_surface, raw_dpi ) ); update_client_surfaces( hwnd );
diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index 81be65a065c..4a131540c19 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -1056,7 +1056,7 @@ BOOL ANDROID_CreateWindowSurface( HWND hwnd, BOOL layered, const RECT *surface_r /*********************************************************************** * ANDROID_WindowPosChanged */ -void ANDROID_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, BOOL fullscreen, +void ANDROID_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, const struct window_rects *new_rects, struct window_surface *surface ) { struct android_win_data *data; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 5b9515f086f..129616eee5a 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -150,7 +150,7 @@ extern void macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alph extern BOOL macdrv_WindowPosChanging(HWND hwnd, UINT swp_flags, BOOL shaped, const struct window_rects *rects); extern BOOL macdrv_GetWindowStyleMasks(HWND hwnd, UINT style, UINT ex_style, UINT *style_mask, UINT *ex_style_mask); extern BOOL macdrv_CreateWindowSurface(HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface); -extern void macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, BOOL fullscreen, +extern void macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, const struct window_rects *new_rects, struct window_surface *surface); extern void macdrv_DestroyCursorIcon(HCURSOR cursor); extern BOOL macdrv_GetCursorPos(LPPOINT pos); diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 10e719068ac..5787492250a 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1589,9 +1589,10 @@ BOOL macdrv_GetWindowStyleMasks(HWND hwnd, UINT style, UINT ex_style, UINT *styl /*********************************************************************** * WindowPosChanged (MACDRV.@) */ -void macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, BOOL fullscreen, +void macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, const struct window_rects *new_rects, struct window_surface *surface) { + BOOL fullscreen = swp_flags & WINE_SWP_FULLSCREEN; struct macdrv_thread_data *thread_data; struct macdrv_win_data *data; unsigned int new_style = NtUserGetWindowLongW(hwnd, GWL_STYLE); @@ -1604,8 +1605,8 @@ void macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT old_rects = data->rects; data->rects = *new_rects;
- TRACE("win %p/%p new_rects %s style %08x flags %08x fullscreen %u surface %p\n", hwnd, data->cocoa_window, - debugstr_window_rects(new_rects), new_style, swp_flags, fullscreen, surface); + TRACE("win %p/%p new_rects %s style %08x flags %08x surface %p\n", hwnd, data->cocoa_window, + debugstr_window_rects(new_rects), new_style, swp_flags, surface);
if (!data->cocoa_window) goto done;
diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 2ec87c768dd..7ab1f58ba64 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -451,7 +451,7 @@ void WAYLAND_SetWindowText(HWND hwnd, LPCWSTR text); LRESULT WAYLAND_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam, const POINT *pos); UINT WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manager, void *param); LRESULT WAYLAND_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); -void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, BOOL fullscreen, +void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, const struct window_rects *new_rects, struct window_surface *surface); BOOL WAYLAND_WindowPosChanging(HWND hwnd, UINT swp_flags, BOOL shaped, const struct window_rects *rects); BOOL WAYLAND_CreateWindowSurface(HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface); diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index 7816f832900..939be6e3c08 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -436,14 +436,14 @@ BOOL WAYLAND_WindowPosChanging(HWND hwnd, UINT swp_flags, BOOL shaped, const str /*********************************************************************** * WAYLAND_WindowPosChanged */ -void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, BOOL fullscreen, +void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, const struct window_rects *new_rects, struct window_surface *surface) { HWND toplevel = NtUserGetAncestor(hwnd, GA_ROOT); struct wayland_surface *toplevel_surface; struct wayland_client_surface *client; struct wayland_win_data *data, *toplevel_data; - BOOL managed; + BOOL managed, fullscreen = swp_flags & WINE_SWP_FULLSCREEN;
TRACE("hwnd %p new_rects %s after %p flags %08x\n", hwnd, debugstr_window_rects(new_rects), insert_after, swp_flags);
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index a042ac9bc52..251492af8d6 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -3114,13 +3114,13 @@ static BOOL get_desired_wm_state( DWORD style, const struct window_rects *rects /*********************************************************************** * WindowPosChanged (X11DRV.@) */ -void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, BOOL fullscreen, +void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, const struct window_rects *new_rects, struct window_surface *surface ) { struct x11drv_win_data *data; UINT ex_style = NtUserGetWindowLongW( hwnd, GWL_EXSTYLE ), new_style = NtUserGetWindowLongW( hwnd, GWL_STYLE ); struct window_rects old_rects; - BOOL is_managed, was_fullscreen, activate = !(swp_flags & SWP_NOACTIVATE); + BOOL is_managed, was_fullscreen, activate = !(swp_flags & SWP_NOACTIVATE), fullscreen = !!(swp_flags & WINE_SWP_FULLSCREEN);
if ((is_managed = is_window_managed( hwnd, swp_flags, fullscreen ))) make_owner_managed( hwnd );
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 63d6a316642..9983d62b114 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -247,7 +247,7 @@ extern BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *swp_ extern BOOL X11DRV_CreateWindowSurface( HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface ); extern void X11DRV_MoveWindowBits( HWND hwnd, const struct window_rects *old_rects, const struct window_rects *new_rects, const RECT *valid_rects ); -extern void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, BOOL fullscreen, +extern void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, const struct window_rects *new_rects, struct window_surface *surface ); extern BOOL X11DRV_SystemParametersInfo( UINT action, UINT int_param, void *ptr_param, UINT flags ); diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index cdc838d36d8..b4880bb52eb 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -353,6 +353,7 @@ struct gdi_device_manager };
#define WINE_DM_UNSUPPORTED 0x80000000 +#define WINE_SWP_FULLSCREEN 0x80000000
struct vulkan_driver_funcs; struct opengl_driver_funcs; @@ -424,7 +425,7 @@ struct user_driver_funcs BOOL (*pGetWindowStateUpdates)(HWND,UINT*,UINT*,RECT*,HWND*); BOOL (*pCreateWindowSurface)(HWND,BOOL,const RECT *,struct window_surface**); void (*pMoveWindowBits)(HWND,const struct window_rects *,const struct window_rects *,const RECT *); - void (*pWindowPosChanged)(HWND,HWND,HWND,UINT,BOOL,const struct window_rects*,struct window_surface*); + void (*pWindowPosChanged)(HWND,HWND,HWND,UINT,const struct window_rects*,struct window_surface*); /* system parameters */ BOOL (*pSystemParametersInfo)(UINT,UINT,void*,UINT); /* vulkan support */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/input.c | 27 ++++++++++++++++----------- dlls/win32u/sysparams.c | 26 -------------------------- dlls/win32u/win32u_private.h | 1 - 3 files changed, 16 insertions(+), 38 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 252ae78e6a0..084ee561f30 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2640,6 +2640,12 @@ static BOOL is_captured_by_system(void) return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) && info.hwndCapture && (info.flags & (GUI_INMOVESIZE | GUI_INMENUMODE)); }
+static BOOL is_fullscreen( const MONITORINFO *info, const RECT *rect ) +{ + return rect->left <= info->rcMonitor.left && rect->right >= info->rcMonitor.right && + rect->top <= info->rcMonitor.top && rect->bottom >= info->rcMonitor.bottom; +} + /*********************************************************************** * clip_fullscreen_window * @@ -2649,9 +2655,9 @@ BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) { struct user_thread_info *thread_info = get_user_thread_info(); MONITORINFO monitor_info = {.cbSize = sizeof(MONITORINFO)}; - RECT rect, virtual_rect; + RECT monitor_rect, window_rect, virtual_rect; DWORD style; - UINT dpi, ctx; + UINT ctx; BOOL ret;
if (hwnd == NtUserGetDesktopWindow()) return FALSE; @@ -2663,19 +2669,18 @@ BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) /* maximized windows don't count as full screen */ if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION) return FALSE;
- dpi = get_dpi_for_window( hwnd ); - if (!get_window_rect( hwnd, &rect, dpi )) return FALSE; - if (!is_window_rect_full_screen( &rect, dpi )) return FALSE; - if (is_captured_by_system()) return FALSE; - if (NtGetTickCount() - thread_info->clipping_reset < 1000) return FALSE; - if (!reset && clipping_cursor && thread_info->clipping_cursor) return FALSE; /* already clipping */ - ctx = set_thread_dpi_awareness_context( NTUSER_DPI_PER_MONITOR_AWARE ); + ret = get_window_rect( hwnd, &window_rect, get_thread_dpi() ); monitor_info = monitor_info_from_window( hwnd, MONITOR_DEFAULTTONEAREST ); virtual_rect = get_virtual_screen_rect( get_thread_dpi(), MDT_DEFAULT ); - rect = map_rect_virt_to_raw( monitor_info.rcMonitor, get_thread_dpi() ); + monitor_rect = map_rect_virt_to_raw( monitor_info.rcMonitor, get_thread_dpi() ); set_thread_dpi_awareness_context( ctx );
+ if (!ret || !is_fullscreen( &monitor_info, &window_rect )) return FALSE; + if (is_captured_by_system()) return FALSE; + if (NtGetTickCount() - thread_info->clipping_reset < 1000) return FALSE; + if (!reset && clipping_cursor && thread_info->clipping_cursor) return FALSE; /* already clipping */ + if (!grab_fullscreen) { if (!EqualRect( &monitor_info.rcMonitor, &virtual_rect )) return FALSE; @@ -2687,7 +2692,7 @@ BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) SERVER_START_REQ( set_cursor ) { req->flags = SET_CURSOR_CLIP | SET_CURSOR_FSCLIP; - req->clip = wine_server_rectangle( rect ); + req->clip = wine_server_rectangle( monitor_rect ); ret = !wine_server_call( req ); } SERVER_END_REQ; diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 93009f6e1e0..48b6e034be1 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2929,32 +2929,6 @@ RECT get_virtual_screen_rect( UINT dpi, MONITOR_DPI_TYPE type ) return rect; }
-BOOL is_window_rect_full_screen( const RECT *rect, UINT dpi ) -{ - struct monitor *monitor; - BOOL ret = FALSE; - - if (!lock_display_devices( FALSE )) return FALSE; - - LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry ) - { - RECT monrect; - - if (!is_monitor_active( monitor ) || monitor->is_clone) continue; - - monrect = monitor_get_rect( monitor, dpi, MDT_DEFAULT ); - if (rect->left <= monrect.left && rect->right >= monrect.right && - rect->top <= monrect.top && rect->bottom >= monrect.bottom) - { - ret = TRUE; - break; - } - } - - unlock_display_devices(); - return ret; -} - static UINT get_display_index( const UNICODE_STRING *name ) { static const WCHAR displayW[] = {'\','\','.','\','D','I','S','P','L','A','Y'}; diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index ba0a9834d9f..7bbbef49ebc 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -169,7 +169,6 @@ extern UINT set_thread_dpi_awareness_context( UINT context ); extern UINT get_thread_dpi_awareness_context(void); extern RECT get_virtual_screen_rect( UINT dpi, MONITOR_DPI_TYPE type ); extern BOOL is_exiting_thread( DWORD tid ); -extern BOOL is_window_rect_full_screen( const RECT *rect, UINT dpi ); extern POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to ); extern RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to ); extern HRGN map_dpi_region( HRGN region, UINT dpi_from, UINT dpi_to );
From: Rémi Bernon rbernon@codeweavers.com
This prevents WMs like KWin or Mutter from automatically maximizing windows which frames are larger than their monitor area.
The maximization otherwise gets fed back into the win32 state, and often confuses applications which are operating a fullscreen window change by resizing a window then later changing its decoration.
It isn't possible to tell between a maximization initiated by the user and one that is initiated by the WM responding to a window resize from us. This heuristic should hopefully be good enough, as it is unlikely that the user will ever be able to resize a window in a such a way that its *frame* covers a monitor entirely. Note that if the user resizes a window such that its *visible* area covers a monitor entirely, we are going to make it fullscreen already anyway. --- dlls/win32u/window.c | 2 ++ dlls/winex11.drv/window.c | 3 ++- dlls/winex11.drv/x11drv.h | 1 + include/wine/gdi_driver.h | 1 + 4 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 1e86d21ae07..abd7373bc7d 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2252,11 +2252,13 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru win->has_icons = need_icons = TRUE; }
+ if (win->dwStyle & WS_THICKFRAME) swp_flags |= WINE_SWP_RESIZABLE; if (is_child) monitor_rects = map_dpi_window_rects( *new_rects, dpi, raw_dpi ); else { MONITORINFO monitor_info = monitor_info_from_rect( new_rects->window, dpi ); if (is_fullscreen( &monitor_info, &new_rects->visible )) swp_flags |= WINE_SWP_FULLSCREEN; + if (is_fullscreen( &monitor_info, &new_rects->window )) swp_flags &= ~WINE_SWP_RESIZABLE; monitor_rects = map_window_rects_virt_to_raw( *new_rects, dpi ); } } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 251492af8d6..e66a2d75260 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -444,7 +444,7 @@ static BOOL is_window_managed( HWND hwnd, UINT swp_flags, BOOL fullscreen ) */ static inline BOOL is_window_resizable( struct x11drv_win_data *data, DWORD style ) { - if (style & WS_THICKFRAME) return TRUE; + if (data->is_resizable) return TRUE; /* Metacity needs the window to be resizable to make it fullscreen */ return data->is_fullscreen; } @@ -3131,6 +3131,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UIN was_fullscreen = data->is_fullscreen; data->rects = *new_rects; data->is_fullscreen = fullscreen; + data->is_resizable = !!(swp_flags & WINE_SWP_RESIZABLE);
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 ); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 9983d62b114..c9315934bee 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -662,6 +662,7 @@ struct x11drv_win_data UINT is_offscreen : 1; /* has been moved offscreen by the window manager */ UINT parent_invalid : 1; /* is the parent host window possibly invalid */ UINT reparenting : 1; /* window is being reparented, likely from a decoration change */ + UINT is_resizable : 1; /* window is allowed to be resized by the window manager */ Window embedder; /* window id of embedder */ Pixmap icon_pixmap; Pixmap icon_mask; diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index b4880bb52eb..2c5a46768f3 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -354,6 +354,7 @@ struct gdi_device_manager
#define WINE_DM_UNSUPPORTED 0x80000000 #define WINE_SWP_FULLSCREEN 0x80000000 +#define WINE_SWP_RESIZABLE 0x40000000
struct vulkan_driver_funcs; struct opengl_driver_funcs;
I found an edge case to this MR, I'll give out an example with slightly exaggerated numbers and ignoring DPI to show what it does.
For a **Monitor A** of **10x10px** size and a **Monitor B** of **100x100px** size, if we get a **Wine window** to be of size **50x50px** on Monitor B, everything works as usual.
But then Wine window can be moved in such a way where it covers the entirety of **Monitor A** (Covering 10x10px for **100pixels** in total) and a large portion of **Monitor B** (Covering 50x10px for **500pixels**)
This will make `get_monitor_from_rect` (That is called by `monitor_info_from_rect`) return monitor B as it covers 500pixels which is more than the 100pixels of monitor A, and as the monitor B isn't fully covered it will make `is_fullscreen` return false.
The only way for it to not cause issues would be for `get_monitor_from_rect` to act the exact same way the WMs does to pick a screen, which is not feasible as WMs may use different way to pick a window.
While I don't think it should change the MR in any way, I thought it deserved a comment, I'm not sure there is a way to do better without active support from the WM/compositor.