From fca63f8fb8e09d6c76f94e5682e9dc7d32495b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 15 Feb 2024 18:27:27 +0100 Subject: [PATCH] xwayland/present: Add xwl_present_maybe_(un)redirect_window A later commit will use these to (un)redirect the surface window on demand. Not used yet, so no functional change intended. v2: * Use "surface_window_damage" instead of "surf_win_damage". (Olivier Fourdan) * Slightly simplify logic in xwl_unrealize_window. v3: * Add comment in xwl_present_maybe_unredirect_window explaining why we use a timer. (Olivier Fourdan) v4: * Rename unredir_timer field to unredirect_timer. Part-of: --- hw/xwayland/xwayland-present.c | 63 ++++++++++++++++++++++++++++++++++ hw/xwayland/xwayland-present.h | 6 ++++ hw/xwayland/xwayland-window.c | 7 ++-- hw/xwayland/xwayland-window.h | 2 ++ 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c index 9def82fcd..ff0a560db 100644 --- a/hw/xwayland/xwayland-present.c +++ b/hw/xwayland/xwayland-present.c @@ -25,6 +25,7 @@ #include +#include #ifdef XWL_HAS_GLAMOR #include #endif @@ -484,6 +485,7 @@ xwl_present_cleanup(WindowPtr window) /* Clear timer */ xwl_present_free_timer(xwl_present_window); + TimerFree(xwl_present_window->unredirect_timer); /* Remove from privates so we don't try to access it later */ dixSetPrivate(&window->devPrivates, @@ -1263,6 +1265,67 @@ xwl_present_unrealize_window(struct xwl_present_window *xwl_present_window) xwl_present_reset_timer(xwl_present_window); } +Bool +xwl_present_maybe_redirect_window(WindowPtr window, PixmapPtr pixmap) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window); + struct xwl_window *xwl_window = xwl_window_from_window(window); + + if (xwl_present_window->redirect_failed) + return FALSE; + + if (compRedirectWindow(serverClient, window, CompositeRedirectManual) != Success) { + xwl_present_window->redirect_failed = TRUE; + return FALSE; + } + + xwl_window_update_surface_window(xwl_window); + if (xwl_window->surface_window != window) { + compUnredirectWindow(serverClient, window, CompositeRedirectManual); + xwl_present_window->redirect_failed = TRUE; + return FALSE; + } + + if (!xwl_window->surface_window_damage) + xwl_window->surface_window_damage = RegionCreate(NullBox, 1); + + xwl_present_window->redirected = TRUE; + return TRUE; +} + +static CARD32 +unredirect_window(OsTimerPtr timer, CARD32 time, void *arg) +{ + WindowPtr window = arg; + struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window); + + compUnredirectWindow(serverClient, window, CompositeRedirectManual); + xwl_present_window->redirected = FALSE; + + xwl_present_window->unredirect_timer = NULL; + return 0; +} + +Bool +xwl_present_maybe_unredirect_window(WindowPtr window) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window); + + if (!xwl_present_window || !xwl_present_window->redirected) + return FALSE; + + /* This function may get called from composite layer code, in which case + * calling compUnredirectWindow would blow up. To avoid this, set up a timer + * which will call it "as soon as possible". + */ + if (!xwl_present_window->unredirect_timer) { + xwl_present_window->unredirect_timer = + TimerSet(NULL, 0, 1, unredirect_window, window); + } + + return TRUE; +} + Bool xwl_present_init(ScreenPtr screen) { diff --git a/hw/xwayland/xwayland-present.h b/hw/xwayland/xwayland-present.h index c0efaa6bf..808e54182 100644 --- a/hw/xwayland/xwayland-present.h +++ b/hw/xwayland/xwayland-present.h @@ -54,6 +54,10 @@ struct xwl_present_window { present_vblank_ptr flip_active; uint64_t blocking_event; + + OsTimerPtr unredirect_timer; + Bool redirected; + Bool redirect_failed; }; struct xwl_present_event { @@ -77,5 +81,7 @@ void xwl_present_frame_callback(struct xwl_present_window *xwl_present_window); Bool xwl_present_init(ScreenPtr screen); void xwl_present_cleanup(WindowPtr window); void xwl_present_unrealize_window(struct xwl_present_window *xwl_present_window); +Bool xwl_present_maybe_redirect_window(WindowPtr window, PixmapPtr pixmap); +Bool xwl_present_maybe_unredirect_window(WindowPtr window); #endif /* XWAYLAND_PRESENT_H */ diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c index 93b689525..fe2983a25 100644 --- a/hw/xwayland/xwayland-window.c +++ b/hw/xwayland/xwayland-window.c @@ -1221,7 +1221,7 @@ err_surf: return FALSE; } -static void +void xwl_window_update_surface_window(struct xwl_window *xwl_window) { WindowPtr surface_window = xwl_window->toplevel; @@ -1512,14 +1512,15 @@ xwl_unrealize_window(WindowPtr window) xwl_screen = xwl_screen_get(screen); - compUnredirectWindow(serverClient, window, CompositeRedirectManual); + xwl_window = xwl_window_get(window); + if (xwl_window) + compUnredirectWindow(serverClient, window, CompositeRedirectManual); screen->UnrealizeWindow = xwl_screen->UnrealizeWindow; ret = (*screen->UnrealizeWindow) (window); xwl_screen->UnrealizeWindow = screen->UnrealizeWindow; screen->UnrealizeWindow = xwl_unrealize_window; - xwl_window = xwl_window_get(window); if (!xwl_window) return ret; diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h index 8823b03ea..836f654a3 100644 --- a/hw/xwayland/xwayland-window.h +++ b/hw/xwayland/xwayland-window.h @@ -82,6 +82,7 @@ struct xwl_window { * can also be used for the X dimensions of the Wayland surface though. */ WindowPtr surface_window; + RegionPtr surface_window_damage; struct xorg_list link_damage; struct xorg_list link_window; @@ -121,6 +122,7 @@ void xwl_window_rootful_update_title(struct xwl_window *xwl_window); void xwl_window_rootful_update_fullscreen(struct xwl_window *xwl_window, struct xwl_output *xwl_output); void xwl_window_set_window_pixmap(WindowPtr window, PixmapPtr pixmap); +void xwl_window_update_surface_window(struct xwl_window *xwl_window); void xwl_window_leave_output(struct xwl_window *xwl_window, struct xwl_output *xwl_output);