diff options
author | Michel Dänzer <mdaenzer@redhat.com> | 2023-12-22 19:00:42 +0100 |
---|---|---|
committer | Marge Bot <emma+marge@anholt.net> | 2024-04-10 08:55:08 +0000 |
commit | 3a0fc2684a037591725585c50760fda6e3c3c765 (patch) | |
tree | acd2b7ca69e84368e44b335733c088e0fdeaa785 | |
parent | db248682b3ff8a39eb29469589e35ecddf008c36 (diff) |
xwayland: Add xwl_window::surface_window
It may track a non-toplevel window which fully covers the area of the
window pixmap / Wayland surface. It is now used instead of
xwl_window::toplevel for updating the Wayland surface contents.
The surface_window can now hit the Present page flip path while it's
automatically redirected.
v2:
* Use "surface_window" instead of "surf_win". (Olivier Fourdan)
* Add comment describing surface_window, and describe what
surface_window/toplevel are useful for respectively. (Olivier Fourdan)
* Use surface_window in xwl_realize_window.
v3:
* Backtrack up to the closest opaque ancestor in
xwl_window_update_surface_window. (Olivier Fourdan)
v4:
* Clean up logic for determining the surface window in
xwl_window_update_surface_window, and document it better.
* Handle window_get_damage(xwl_window->surface_window) returning NULL
in xwl_window_update_surface_window.
* Call xwl_window_update_surface_window after xwl_window_buffers_init
in ensure_surface_for_window, since the former may call
xwl_window_buffers_dispose.
* Rename surf/win_pix to surface/window_pixmap in
xwl_window_update_surface_window.
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1300>
-rw-r--r-- | hw/xwayland/xwayland-dmabuf.c | 4 | ||||
-rw-r--r-- | hw/xwayland/xwayland-glamor-gbm.c | 2 | ||||
-rw-r--r-- | hw/xwayland/xwayland-present.c | 2 | ||||
-rw-r--r-- | hw/xwayland/xwayland-screen.c | 3 | ||||
-rw-r--r-- | hw/xwayland/xwayland-screen.h | 1 | ||||
-rw-r--r-- | hw/xwayland/xwayland-window-buffers.c | 15 | ||||
-rw-r--r-- | hw/xwayland/xwayland-window.c | 117 | ||||
-rw-r--r-- | hw/xwayland/xwayland-window.h | 15 |
8 files changed, 129 insertions, 30 deletions
diff --git a/hw/xwayland/xwayland-dmabuf.c b/hw/xwayland/xwayland-dmabuf.c index 97c501273..8119e1ddb 100644 --- a/hw/xwayland/xwayland-dmabuf.c +++ b/hw/xwayland/xwayland-dmabuf.c @@ -735,7 +735,7 @@ xwl_window_dmabuf_feedback_done(void *data, struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback) { struct xwl_window *xwl_window = data; - uint32_t format = wl_drm_format_for_depth(xwl_window->toplevel->drawable.depth); + uint32_t format = wl_drm_format_for_depth(xwl_window->surface_window->drawable.depth); xwl_dmabuf_feedback_done(&xwl_window->feedback, dmabuf_feedback); @@ -743,7 +743,7 @@ xwl_window_dmabuf_feedback_done(void *data, xwl_feedback_is_modifier_supported(&xwl_window->feedback, format, DRM_FORMAT_MOD_INVALID, TRUE); DebugF("XWAYLAND: Window 0x%x can%s get implicit scanout support\n", - xwl_window->toplevel->drawable.id, + xwl_window->surface_window->drawable.id, xwl_window->has_implicit_scanout_support ? "" : "not"); /* If the linux-dmabuf v4 per-surface feedback changed, make sure the diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c index 1198ca16b..745a9ed38 100644 --- a/hw/xwayland/xwayland-glamor-gbm.c +++ b/hw/xwayland/xwayland-glamor-gbm.c @@ -412,7 +412,7 @@ PixmapPtr xwl_glamor_create_pixmap_for_window(struct xwl_window *xwl_window) { struct xwl_screen *xwl_screen = xwl_window->xwl_screen; - WindowPtr window = xwl_window->toplevel; + WindowPtr window = xwl_window->surface_window; unsigned border_width = 2 * window->borderWidth; if (!xwl_screen->glamor) diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c index 1ac099da9..9def82fcd 100644 --- a/hw/xwayland/xwayland-present.c +++ b/hw/xwayland/xwayland-present.c @@ -785,7 +785,7 @@ xwl_present_check_flip(RRCrtcPtr crtc, * window's, e.g. because a client redirected this window or one of its * parents. */ - if (screen->GetWindowPixmap(xwl_window->toplevel) != screen->GetWindowPixmap(present_window)) + if (screen->GetWindowPixmap(xwl_window->surface_window) != screen->GetWindowPixmap(present_window)) return FALSE; /* diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c index 701425c08..135ae7b74 100644 --- a/hw/xwayland/xwayland-screen.c +++ b/hw/xwayland/xwayland-screen.c @@ -1110,6 +1110,9 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) xwl_screen->ChangeWindowAttributes = pScreen->ChangeWindowAttributes; pScreen->ChangeWindowAttributes = xwl_change_window_attributes; + xwl_screen->ClipNotify = pScreen->ClipNotify; + pScreen->ClipNotify = xwl_clip_notify; + xwl_screen->ResizeWindow = pScreen->ResizeWindow; pScreen->ResizeWindow = xwl_resize_window; diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h index 2b3bdb29e..9653d82c9 100644 --- a/hw/xwayland/xwayland-screen.h +++ b/hw/xwayland/xwayland-screen.h @@ -68,6 +68,7 @@ struct xwl_screen { int nokeymap; int hidpi; + ClipNotifyProcPtr ClipNotify; CreateScreenResourcesProcPtr CreateScreenResources; CloseScreenProcPtr CloseScreen; CreateWindowProcPtr CreateWindow; diff --git a/hw/xwayland/xwayland-window-buffers.c b/hw/xwayland/xwayland-window-buffers.c index bdae04945..2e8b0859c 100644 --- a/hw/xwayland/xwayland-window-buffers.c +++ b/hw/xwayland/xwayland-window-buffers.c @@ -339,7 +339,7 @@ xwl_window_allocate_pixmap(struct xwl_window *xwl_window) return window_pixmap; #endif /* XWL_HAS_GLAMOR */ - window_pixmap = screen->GetWindowPixmap(xwl_window->toplevel); + window_pixmap = screen->GetWindowPixmap(xwl_window->surface_window); return screen->CreatePixmap(screen, window_pixmap->drawable.width, window_pixmap->drawable.height, @@ -358,7 +358,7 @@ xwl_window_realloc_pixmap(struct xwl_window *xwl_window) if (!new_window_pixmap) return; - window = xwl_window->toplevel; + window = xwl_window->surface_window; screen = window->drawable.pScreen; window_pixmap = screen->GetWindowPixmap(window); copy_pixmap_area(window_pixmap, @@ -366,7 +366,7 @@ xwl_window_realloc_pixmap(struct xwl_window *xwl_window) 0, 0, window_pixmap->drawable.width, window_pixmap->drawable.height); - xwl_window_set_pixmap(xwl_window->toplevel, new_window_pixmap); + xwl_window_set_pixmap(xwl_window->surface_window, new_window_pixmap); screen->DestroyPixmap(window_pixmap); } @@ -414,11 +414,12 @@ PixmapPtr xwl_window_swap_pixmap(struct xwl_window *xwl_window) { struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + WindowPtr surface_window = xwl_window->surface_window; struct xwl_window_buffer *xwl_window_buffer; PixmapPtr window_pixmap; Bool implicit_sync = TRUE; - window_pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->toplevel); + window_pixmap = (*xwl_screen->screen->GetWindowPixmap) (surface_window); xwl_window_buffer_add_damage_region(xwl_window); @@ -441,8 +442,8 @@ xwl_window_swap_pixmap(struct xwl_window *xwl_window) while (nBox--) { copy_pixmap_area(window_pixmap, xwl_window_buffer->pixmap, - pBox->x1 + xwl_window->toplevel->borderWidth, - pBox->y1 + xwl_window->toplevel->borderWidth, + pBox->x1 + surface_window->borderWidth, + pBox->y1 + surface_window->borderWidth, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1); @@ -451,7 +452,7 @@ xwl_window_swap_pixmap(struct xwl_window *xwl_window) RegionEmpty(xwl_window_buffer->damage_region); xorg_list_del(&xwl_window_buffer->link_buffer); - xwl_window_set_pixmap(xwl_window->toplevel, xwl_window_buffer->pixmap); + xwl_window_set_pixmap(surface_window, xwl_window_buffer->pixmap); /* Can't re-use client pixmap as a window buffer */ if (xwl_is_client_pixmap(window_pixmap)) { diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c index e85827b82..11a6b3adc 100644 --- a/hw/xwayland/xwayland-window.c +++ b/hw/xwayland/xwayland-window.c @@ -87,7 +87,7 @@ window_get_damage(WindowPtr window) RegionPtr xwl_window_get_damage_region(struct xwl_window *xwl_window) { - return DamageRegion(window_get_damage(xwl_window->toplevel)); + return DamageRegion(window_get_damage(xwl_window->surface_window)); } struct xwl_window * @@ -135,7 +135,7 @@ xwl_window_set_allow_commits(struct xwl_window *xwl_window, Bool allow, DebugF("XWAYLAND: win %d allow_commits = %d (%s)\n", xwl_window->toplevel->drawable.id, allow, debug_msg); - damage = window_get_damage(xwl_window->toplevel); + damage = window_get_damage(xwl_window->surface_window); if (allow && xorg_list_is_empty(&xwl_window->link_damage) && damage && @@ -202,7 +202,7 @@ damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data) if (xorg_list_is_empty(&xwl_window->link_damage)) xorg_list_add(&xwl_window->link_damage, &xwl_screen->damage_window_list); - window_pixmap = xwl_screen->screen->GetWindowPixmap(xwl_window->toplevel); + window_pixmap = xwl_screen->screen->GetWindowPixmap(xwl_window->surface_window); if (xwl_is_client_pixmap(window_pixmap)) xwl_screen->screen->DestroyPixmap(xwl_window_swap_pixmap(xwl_window)); } @@ -215,18 +215,18 @@ damage_destroy(DamagePtr pDamage, void *data) static Bool register_damage(struct xwl_window *xwl_window) { - WindowPtr toplevel = xwl_window->toplevel; + WindowPtr surface_window = xwl_window->surface_window; DamagePtr damage; damage = DamageCreate(damage_report, damage_destroy, DamageReportNonEmpty, - FALSE, toplevel->drawable.pScreen, xwl_window); + FALSE, surface_window->drawable.pScreen, xwl_window); if (damage == NULL) { ErrorF("Failed creating damage\n"); return FALSE; } - DamageRegister(&toplevel->drawable, damage); - dixSetPrivate(&toplevel->devPrivates, &xwl_damage_private_key, damage); + DamageRegister(&surface_window->drawable, damage); + dixSetPrivate(&surface_window->devPrivates, &xwl_damage_private_key, damage); return TRUE; } @@ -234,17 +234,17 @@ register_damage(struct xwl_window *xwl_window) static void unregister_damage(struct xwl_window *xwl_window) { - WindowPtr toplevel = xwl_window->toplevel; + WindowPtr surface_window = xwl_window->surface_window; DamagePtr damage; - damage = dixLookupPrivate(&toplevel->devPrivates, &xwl_damage_private_key); + damage = dixLookupPrivate(&surface_window->devPrivates, &xwl_damage_private_key); if (!damage) return; DamageUnregister(damage); DamageDestroy(damage); - dixSetPrivate(&toplevel->devPrivates, &xwl_damage_private_key, NULL); + dixSetPrivate(&surface_window->devPrivates, &xwl_damage_private_key, NULL); } static Bool @@ -540,15 +540,15 @@ xwl_window_check_resolution_change_emulation(struct xwl_window *xwl_window) Bool xwl_window_is_toplevel(WindowPtr window) { - if (window_is_wm_window(window)) + if (!window->parent || window_is_wm_window(window)) return FALSE; /* CSD and override-redirect toplevel windows */ - if (window_get_damage(window)) + if (!window->parent->parent) return TRUE; /* Normal toplevel client windows, reparented to a window-manager window */ - return window->parent && window_is_wm_window(window->parent); + return window_is_wm_window(window->parent); } static void @@ -1221,6 +1221,65 @@ err_surf: return FALSE; } +static void +xwl_window_update_surface_window(struct xwl_window *xwl_window) +{ + WindowPtr surface_window = xwl_window->toplevel; + ScreenPtr screen = surface_window->drawable.pScreen; + PixmapPtr surface_pixmap; + DamagePtr window_damage; + RegionRec damage_region; + WindowPtr window; + + surface_pixmap = screen->GetWindowPixmap(surface_window); + + for (window = surface_window->firstChild; window; window = window->firstChild) { + PixmapPtr window_pixmap; + + if (!RegionEqual(&window->winSize, &surface_window->winSize)) + break; + + /* The surface window must be top-level for its window pixmap */ + window_pixmap = screen->GetWindowPixmap(window); + if (window_pixmap == surface_pixmap) + continue; + + surface_pixmap = window_pixmap; + + /* A descendant with alpha channel cannot be the surface window, since + * any non-opaque areas need to take the contents of ancestors into + * account. + */ + if (window->drawable.depth == 32) + continue; + + surface_window = window; + } + + if (xwl_window->surface_window == surface_window) + return; + + window_damage = window_get_damage(xwl_window->surface_window); + if (window_damage) { + RegionInit(&damage_region, NullBox, 1); + RegionCopy(&damage_region, DamageRegion(window_damage)); + unregister_damage(xwl_window); + } + + if (surface_window->drawable.depth != xwl_window->surface_window->drawable.depth) + xwl_window_buffers_dispose(xwl_window); + + xwl_window->surface_window = surface_window; + register_damage(xwl_window); + + if (window_damage) { + RegionPtr new_region = DamageRegion(window_get_damage(surface_window)); + + RegionUnion(new_region, new_region, &damage_region); + RegionUninit(&damage_region); + } +} + static struct xwl_window * ensure_surface_for_window(WindowPtr window) { @@ -1250,6 +1309,7 @@ ensure_surface_for_window(WindowPtr window) xwl_window->xwl_screen = xwl_screen; xwl_window->toplevel = window; + xwl_window->surface_window = window; xwl_window->fractional_scale_numerator = FRACTIONAL_SCALE_DENOMINATOR; xwl_window->viewport_scale_x = 1.0; xwl_window->viewport_scale_y = 1.0; @@ -1290,6 +1350,8 @@ ensure_surface_for_window(WindowPtr window) xwl_window_buffers_init(xwl_window); + xwl_window_update_surface_window(xwl_window); + xwl_window_init_allow_commits(xwl_window); /* When a new window-manager window is realized, then the randr emulation @@ -1360,7 +1422,7 @@ xwl_realize_window(WindowPtr window) if (!xwl_window) return FALSE; - if (window == xwl_window->toplevel && + if (window == xwl_window->surface_window && !window_get_damage(window)) return register_damage(xwl_window); @@ -1572,6 +1634,22 @@ xwl_change_window_attributes(WindowPtr window, unsigned long mask) } void +xwl_clip_notify(WindowPtr window, int dx, int dy) +{ + ScreenPtr screen = window->drawable.pScreen; + struct xwl_screen *xwl_screen = xwl_screen_get(screen); + struct xwl_window *xwl_window = xwl_window_from_window(window); + + screen->ClipNotify = xwl_screen->ClipNotify; + (*screen->ClipNotify) (window, dx, dy); + xwl_screen->ClipNotify = screen->ClipNotify; + screen->ClipNotify = xwl_clip_notify; + + if (xwl_window) + xwl_window_update_surface_window(xwl_window); +} + +void xwl_resize_window(WindowPtr window, int x, int y, unsigned int width, unsigned int height, @@ -1696,6 +1774,7 @@ static Bool xwl_window_attach_buffer(struct xwl_window *xwl_window) { struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + WindowPtr surface_window = xwl_window->surface_window; RegionPtr region; BoxPtr box; struct wl_buffer *buffer; @@ -1720,15 +1799,15 @@ xwl_window_attach_buffer(struct xwl_window *xwl_window) if (RegionNumRects(region) > 256) { box = RegionExtents(region); xwl_surface_damage(xwl_screen, xwl_window->surface, - box->x1 + xwl_window->toplevel->borderWidth, - box->y1 + xwl_window->toplevel->borderWidth, + box->x1 + surface_window->borderWidth, + box->y1 + surface_window->borderWidth, box->x2 - box->x1, box->y2 - box->y1); } else { box = RegionRects(region); for (i = 0; i < RegionNumRects(region); i++, box++) { xwl_surface_damage(xwl_screen, xwl_window->surface, - box->x1 + xwl_window->toplevel->borderWidth, - box->y1 + xwl_window->toplevel->borderWidth, + box->x1 + surface_window->borderWidth, + box->y1 + surface_window->borderWidth, box->x2 - box->x1, box->y2 - box->y1); } } @@ -1745,7 +1824,7 @@ xwl_window_post_damage(struct xwl_window *xwl_window) return; xwl_window_create_frame_callback(xwl_window); - DamageEmpty(window_get_damage(xwl_window->toplevel)); + DamageEmpty(window_get_damage(xwl_window->surface_window)); } Bool diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h index 7c75f9b80..fefb4969c 100644 --- a/hw/xwayland/xwayland-window.h +++ b/hw/xwayland/xwayland-window.h @@ -66,9 +66,23 @@ struct xwl_window { /* Top-level window for the Wayland surface: * - With rootful, the root window itself * - With rootless, a direct child of the root window + * Mainly useful when the top-level window is needed, can also be used for + * the X dimensions of the Wayland surface though. */ WindowPtr toplevel; + /* The window associated with the Wayland surface: + * - If the top-level window has descendants which: + * - Cover it completely + * - Have no alpha channel + * - Use a different window pixmap than their parent for storage + * then the surface window is the lowest-level such descendant. + * - Otherwise it's the top-level window itself. + * Mainly useful for code dealing with (buffers for) the Wayland surface, + * can also be used for the X dimensions of the Wayland surface though. + */ + WindowPtr surface_window; + struct xorg_list link_damage; struct xorg_list link_window; struct wl_callback *frame_callback; @@ -114,6 +128,7 @@ int xwl_window_get_max_output_scale(struct xwl_window *xwl_window); Bool xwl_realize_window(WindowPtr window); Bool xwl_unrealize_window(WindowPtr window); Bool xwl_change_window_attributes(WindowPtr window, unsigned long mask); +void xwl_clip_notify(WindowPtr window, int dx, int dy); void xwl_resize_window(WindowPtr window, int x, int y, unsigned int width, unsigned int height, |