Module: wine Branch: master Commit: 970c3f9d42561456d88be60b35163bf6dd935c3e URL: https://gitlab.winehq.org/wine/wine/-/commit/970c3f9d42561456d88be60b35163bf...
Author: Rémi Bernon rbernon@codeweavers.com Date: Wed Jun 19 18:15:53 2024 +0200
winewayland: Clip huge window surfaces to the virtual screen rect.
---
dlls/winewayland.drv/waylanddrv.h | 3 +- dlls/winewayland.drv/window.c | 14 +++++---- dlls/winewayland.drv/window_surface.c | 55 +++++++++++++++++++++++++---------- 3 files changed, 49 insertions(+), 23 deletions(-)
diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index d0a8977f887..28e754b6562 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -236,6 +236,7 @@ void wayland_output_use_xdg_extension(struct wayland_output *output); * Wayland surface */
+BOOL get_surface_rect(const RECT *visible_rect, RECT *surface_rect); struct wayland_surface *wayland_surface_create(HWND hwnd); void wayland_surface_destroy(struct wayland_surface *surface); void wayland_surface_make_toplevel(struct wayland_surface *surface); @@ -272,7 +273,7 @@ void wayland_shm_buffer_unref(struct wayland_shm_buffer *shm_buffer); * Wayland window surface */
-void wayland_window_surface_update_wayland_surface(struct window_surface *surface, +void wayland_window_surface_update_wayland_surface(struct window_surface *surface, const RECT *visible_rect, struct wayland_surface *wayland_surface); void wayland_window_flush(HWND hwnd);
diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index 060a25d50c6..9d2432262b8 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -124,7 +124,7 @@ static void wayland_win_data_destroy(struct wayland_win_data *data)
if (data->window_surface) { - wayland_window_surface_update_wayland_surface(data->window_surface, NULL); + wayland_window_surface_update_wayland_surface(data->window_surface, NULL, NULL); window_surface_release(data->window_surface); } if (data->wayland_surface) wayland_surface_destroy(data->wayland_surface); @@ -200,20 +200,20 @@ static void reapply_cursor_clipping(void) NtUserSetThreadDpiAwarenessContext(context); }
-static void wayland_win_data_update_wayland_surface(struct wayland_win_data *data) +static void wayland_win_data_update_wayland_surface(struct wayland_win_data *data, const RECT *visible_rect) { struct wayland_surface *surface = data->wayland_surface; HWND parent = NtUserGetAncestor(data->hwnd, GA_PARENT); BOOL visible, xdg_visible; WCHAR text[1024];
- TRACE("hwnd=%p\n", data->hwnd); + TRACE("hwnd=%p, rect=%s\n", data->hwnd, wine_dbgstr_rect(visible_rect));
/* We don't want wayland surfaces for child windows. */ if (parent != NtUserGetDesktopWindow() && parent != 0) { if (data->window_surface) - wayland_window_surface_update_wayland_surface(data->window_surface, NULL); + wayland_window_surface_update_wayland_surface(data->window_surface, NULL, NULL); if (surface) wayland_surface_destroy(surface); surface = NULL; goto out; @@ -251,7 +251,7 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat pthread_mutex_unlock(&surface->mutex);
if (data->window_surface) - wayland_window_surface_update_wayland_surface(data->window_surface, surface); + wayland_window_surface_update_wayland_surface(data->window_surface, visible_rect, surface);
/* Size/position changes affect the effective pointer constraint, so update * it as needed. */ @@ -432,6 +432,7 @@ BOOL WAYLAND_WindowPosChanging(HWND hwnd, UINT swp_flags, const RECT *window_rec struct wayland_win_data *data = wayland_win_data_get(hwnd); HWND parent; BOOL visible, ret = FALSE; + RECT surface_rect;
TRACE("hwnd %p window %s client %s visible %s flags %08x\n", hwnd, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect), @@ -445,6 +446,7 @@ BOOL WAYLAND_WindowPosChanging(HWND hwnd, UINT swp_flags, const RECT *window_rec !(swp_flags & SWP_HIDEWINDOW);
if ((parent && parent != NtUserGetDesktopWindow()) || !visible) goto done; /* use default surface */ + if (!get_surface_rect( visible_rect, &surface_rect )) goto done; /* use default surface */
ret = TRUE;
@@ -484,7 +486,7 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, if (data->window_surface) window_surface_release(data->window_surface); data->window_surface = surface;
- wayland_win_data_update_wayland_surface(data); + wayland_win_data_update_wayland_surface(data, visible_rect); if (data->wayland_surface) wayland_win_data_update_wayland_state(data);
wayland_win_data_release(data); diff --git a/dlls/winewayland.drv/window_surface.c b/dlls/winewayland.drv/window_surface.c index 9377b05b4ce..c557bd30fe4 100644 --- a/dlls/winewayland.drv/window_surface.c +++ b/dlls/winewayland.drv/window_surface.c @@ -283,8 +283,8 @@ static void copy_pixel_region(char *src_pixels, RECT *src_rect, if (!intersect_rect(&rc, rgn_rect, src_rect)) continue; if (!intersect_rect(&rc, &rc, dst_rect)) continue;
- src = src_pixels + rc.top * src_stride + rc.left * bpp; - dst = dst_pixels + rc.top * dst_stride + rc.left * bpp; + src = src_pixels + (rc.top - src_rect->top) * src_stride + (rc.left - src_rect->left) * bpp; + dst = dst_pixels + (rc.top - dst_rect->top) * dst_stride + (rc.left - dst_rect->left) * bpp; width_bytes = (rc.right - rc.left) * bpp; height = rc.bottom - rc.top;
@@ -346,7 +346,8 @@ static BOOL wayland_window_surface_flush(struct window_surface *window_surface, goto done; }
- surface_damage_region = NtGdiCreateRectRgn(dirty->left, dirty->top, dirty->right, dirty->bottom); + surface_damage_region = NtGdiCreateRectRgn(rect->left + dirty->left, rect->top + dirty->top, + rect->left + dirty->right, rect->top + dirty->bottom); if (!surface_damage_region) { ERR("failed to create surface damage region\n"); @@ -486,7 +487,7 @@ failed: /*********************************************************************** * wayland_window_surface_update_wayland_surface */ -void wayland_window_surface_update_wayland_surface(struct window_surface *window_surface, +void wayland_window_surface_update_wayland_surface(struct window_surface *window_surface, const RECT *visible_rect, struct wayland_surface *wayland_surface) { struct wayland_window_surface *wws; @@ -497,27 +498,51 @@ void wayland_window_surface_update_wayland_surface(struct window_surface *window wws = wayland_window_surface_cast(window_surface); window_surface_lock(window_surface);
- TRACE("surface=%p hwnd=%p wayland_surface=%p\n", wws, window_surface->hwnd, wayland_surface); + TRACE("surface=%p hwnd=%p visible_rect=%s wayland_surface=%p\n", wws, window_surface->hwnd, + wine_dbgstr_rect(visible_rect), wayland_surface);
wws->wayland_surface = wayland_surface;
- /* We only need a buffer queue if we have a surface to commit to. */ - if (wws->wayland_surface && !wws->wayland_buffer_queue) - { - wws->wayland_buffer_queue = - wayland_buffer_queue_create(wws->info.bmiHeader.biWidth, - abs(wws->info.bmiHeader.biHeight)); - } - else if (!wws->wayland_surface && wws->wayland_buffer_queue) + if (wws->wayland_buffer_queue) { wayland_buffer_queue_destroy(wws->wayland_buffer_queue); wws->wayland_buffer_queue = NULL; }
+ /* We only need a buffer queue if we have a surface to commit to. */ + if (wws->wayland_surface) + { + wws->wayland_buffer_queue = + wayland_buffer_queue_create(visible_rect->right - visible_rect->left, + visible_rect->bottom - visible_rect->top); + } + window_surface_unlock(window_surface); }
+BOOL get_surface_rect(const RECT *visible_rect, RECT *surface_rect) +{ + RECT virtual_rect = NtUserGetVirtualScreenRect(); + + *surface_rect = *visible_rect; + + /* crop surfaces which are larger than the virtual screen rect, some applications create huge windows */ + if ((surface_rect->right - surface_rect->left > virtual_rect.right - virtual_rect.left || + surface_rect->bottom - surface_rect->top > virtual_rect.bottom - virtual_rect.top) && + !intersect_rect( surface_rect, surface_rect, &virtual_rect )) + return FALSE; + OffsetRect(surface_rect, -visible_rect->left, -visible_rect->top); + + /* round the surface coordinates to avoid re-creating them too often on resize */ + surface_rect->left &= ~127; + surface_rect->top &= ~127; + surface_rect->right = max(surface_rect->left + 128, (surface_rect->right + 127) & ~127); + surface_rect->bottom = max(surface_rect->top + 128, (surface_rect->bottom + 127) & ~127); + return TRUE; +} + + /*********************************************************************** * WAYLAND_CreateWindowSurface */ @@ -529,14 +554,12 @@ BOOL WAYLAND_CreateWindowSurface(HWND hwnd, UINT swp_flags, const RECT *visible_ TRACE("hwnd %p, swp_flags %08x, visible %s, surface %p\n", hwnd, swp_flags, wine_dbgstr_rect(visible_rect), surface);
if (!(data = wayland_win_data_get(hwnd))) return TRUE; /* use default surface */ + if (!get_surface_rect( visible_rect, &surface_rect )) goto done; /* use default surface */
/* Release the dummy surface wine provides for toplevels. */ if (*surface) window_surface_release(*surface); *surface = NULL;
- surface_rect = *visible_rect; - OffsetRect(&surface_rect, -surface_rect.left, -surface_rect.top); - /* Check if we can reuse our current window surface. */ if (data->window_surface && EqualRect(&data->window_surface->rect, &surface_rect))