summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichel Dänzer <mdaenzer@redhat.com>2023-12-22 19:00:42 +0100
committerMarge Bot <emma+marge@anholt.net>2024-04-10 08:55:08 +0000
commit3a0fc2684a037591725585c50760fda6e3c3c765 (patch)
treeacd2b7ca69e84368e44b335733c088e0fdeaa785
parentdb248682b3ff8a39eb29469589e35ecddf008c36 (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.c4
-rw-r--r--hw/xwayland/xwayland-glamor-gbm.c2
-rw-r--r--hw/xwayland/xwayland-present.c2
-rw-r--r--hw/xwayland/xwayland-screen.c3
-rw-r--r--hw/xwayland/xwayland-screen.h1
-rw-r--r--hw/xwayland/xwayland-window-buffers.c15
-rw-r--r--hw/xwayland/xwayland-window.c117
-rw-r--r--hw/xwayland/xwayland-window.h15
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,