diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c index 17280659e..752f9353a 100644 --- a/hw/xwayland/xwayland-screen.c +++ b/hw/xwayland/xwayland-screen.c @@ -173,6 +173,7 @@ xwl_close_screen(ScreenPtr screen) struct xwl_screen *xwl_screen = xwl_screen_get(screen); struct xwl_output *xwl_output, *next_xwl_output; struct xwl_seat *xwl_seat, *next_xwl_seat; + struct xwl_wl_surface *xwl_wl_surface, *xwl_wl_surface_next; DeleteCallback(&PropertyStateCallback, xwl_property_callback, screen); @@ -192,6 +193,10 @@ xwl_close_screen(ScreenPtr screen) xwl_screen_destroy_drm_lease_device(xwl_screen, device_data->drm_lease_device); + xorg_list_for_each_entry_safe(xwl_wl_surface, xwl_wl_surface_next, + &xwl_screen->pending_wl_surface_destroy, link) + xwl_window_surface_do_destroy(xwl_wl_surface); + RemoveNotifyFd(xwl_screen->wayland_fd); wl_display_disconnect(xwl_screen->display); @@ -711,6 +716,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) xorg_list_init(&xwl_screen->drm_lease_devices); xorg_list_init(&xwl_screen->queued_drm_lease_devices); xorg_list_init(&xwl_screen->drm_leases); + xorg_list_init(&xwl_screen->pending_wl_surface_destroy); xwl_screen->depth = 24; if (!monitorResolution) diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h index 32dfd0ddb..6d1e7d1bd 100644 --- a/hw/xwayland/xwayland-screen.h +++ b/hw/xwayland/xwayland-screen.h @@ -94,6 +94,7 @@ struct xwl_screen { struct xorg_list drm_lease_devices; struct xorg_list queued_drm_lease_devices; struct xorg_list drm_leases; + struct xorg_list pending_wl_surface_destroy; uint32_t serial; #define XWL_FORMAT_ARGB8888 (1 << 0) diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c index 41061e344..a5c1e2aef 100644 --- a/hw/xwayland/xwayland-window.c +++ b/hw/xwayland/xwayland-window.c @@ -46,6 +46,8 @@ #include "viewporter-client-protocol.h" #include "xdg-shell-client-protocol.h" +#define DELAYED_WL_SURFACE_DESTROY 1000 /* ms */ + static DevPrivateKeyRec xwl_window_private_key; static DevPrivateKeyRec xwl_damage_private_key; @@ -563,6 +565,58 @@ xwl_realize_window(WindowPtr window) return ensure_surface_for_window(window); } +static void +xwl_surface_destroy_free_timer(struct xwl_wl_surface *xwl_wl_surface) +{ + if (xwl_wl_surface->wl_surface_destroy_timer) { + TimerFree(xwl_wl_surface->wl_surface_destroy_timer); + xwl_wl_surface->wl_surface_destroy_timer = NULL; + } +} + +void +xwl_window_surface_do_destroy(struct xwl_wl_surface *xwl_wl_surface) +{ + wl_surface_destroy(xwl_wl_surface->wl_surface); + xorg_list_del(&xwl_wl_surface->link); + xwl_surface_destroy_free_timer(xwl_wl_surface); + free(xwl_wl_surface); +} + +static CARD32 +xwl_surface_destroy_callback(OsTimerPtr timer, CARD32 now, void *arg) +{ + struct xwl_wl_surface *xwl_wl_surface = arg; + + xwl_window_surface_do_destroy(xwl_wl_surface); + + return 0; +} + +static void +release_wl_surface_for_window(struct xwl_window *xwl_window) +{ + struct xwl_wl_surface *xwl_wl_surface; + + /* If the Xserver is terminating, destroy the surface immediately */ + if ((dispatchException & DE_TERMINATE) == DE_TERMINATE) { + wl_surface_destroy(xwl_window->surface); + return; + } + + /* Otherwise, schedule the destruction later, to mitigate the race + * between X11 and Wayland processing so that the compositor has the + * time to establish the association before the wl_surface is destroyed. + */ + xwl_wl_surface = xnfcalloc(1, sizeof *xwl_wl_surface); + xwl_wl_surface->wl_surface = xwl_window->surface; + xorg_list_add(&xwl_wl_surface->link, + &xwl_window->xwl_screen->pending_wl_surface_destroy); + xwl_wl_surface->wl_surface_destroy_timer = + TimerSet(NULL, 0, DELAYED_WL_SURFACE_DESTROY, + xwl_surface_destroy_callback, xwl_wl_surface); +} + Bool xwl_unrealize_window(WindowPtr window) { @@ -617,7 +671,7 @@ xwl_unrealize_window(WindowPtr window) } #endif - wl_surface_destroy(xwl_window->surface); + release_wl_surface_for_window(xwl_window); xorg_list_del(&xwl_window->link_damage); xorg_list_del(&xwl_window->link_window); unregister_damage(window); diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h index d94f07204..fbe76784d 100644 --- a/hw/xwayland/xwayland-window.h +++ b/hw/xwayland/xwayland-window.h @@ -37,6 +37,12 @@ #include "xwayland-types.h" +struct xwl_wl_surface { + OsTimerPtr wl_surface_destroy_timer; + struct wl_surface *wl_surface; + struct xorg_list link; +}; + struct xwl_window { struct xwl_screen *xwl_screen; struct wl_surface *surface; @@ -81,6 +87,8 @@ void xwl_move_window(WindowPtr window, Bool xwl_destroy_window(WindowPtr window); void xwl_window_post_damage(struct xwl_window *xwl_window); void xwl_window_create_frame_callback(struct xwl_window *xwl_window); +void xwl_window_surface_do_destroy(struct xwl_wl_surface *xwl_wl_surface); + Bool xwl_window_init(void); #endif /* XWAYLAND_WINDOW_H */