winewayland: Clip huge window surfaces to the virtual screen rect.

This commit is contained in:
Rémi Bernon 2024-06-19 18:15:53 +02:00 committed by Alexandre Julliard
parent 98c669b1c2
commit 970c3f9d42
3 changed files with 49 additions and 23 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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))