From cbb4f6c892c1c795aaabb5b39be91d4defc6ad65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 3 Oct 2019 21:44:34 +0200 Subject: [PATCH] wayland/actor-surface: Handle surface actor destruction A surface actor may be destroyed without the backing Wayland surface being destroyed yet, e.g. by the window being unmanaged. Handle this by listening on the "destroy" signal and making late requests (e.g. wl_surface_commit()) resilient against the lack of a surface actor. Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/838 https://gitlab.gnome.org/GNOME/mutter/merge_requests/825 --- src/wayland/meta-wayland-actor-surface.c | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c index 5e8cd09b9..21cbe7a7c 100644 --- a/src/wayland/meta-wayland-actor-surface.c +++ b/src/wayland/meta-wayland-actor-surface.c @@ -36,6 +36,8 @@ typedef struct _MetaWaylandActorSurfacePrivate MetaWaylandActorSurfacePrivate; struct _MetaWaylandActorSurfacePrivate { MetaSurfaceActor *actor; + + gulong actor_destroyed_handler_id; }; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaWaylandActorSurface, @@ -60,6 +62,10 @@ clear_surface_actor (MetaWaylandActorSurface *actor_surface) MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (surface_role); + if (!priv->actor) + return; + + g_clear_signal_handler (&priv->actor_destroyed_handler_id, priv->actor); g_signal_handlers_disconnect_by_func (priv->actor, meta_wayland_surface_notify_geometry_changed, surface); @@ -104,6 +110,9 @@ meta_wayland_actor_surface_queue_frame_callbacks (MetaWaylandActorSurface *actor MetaSurfaceActorWayland *surface_actor_wayland = META_SURFACE_ACTOR_WAYLAND (priv->actor); + if (!priv->actor) + return; + meta_surface_actor_wayland_add_frame_callbacks (surface_actor_wayland, &pending->frame_callback_list); wl_list_init (&pending->frame_callback_list); @@ -226,6 +235,11 @@ meta_wayland_actor_surface_commit (MetaWaylandSurfaceRole *surface_role, { MetaWaylandActorSurface *actor_surface = META_WAYLAND_ACTOR_SURFACE (surface_role); + MetaWaylandActorSurfacePrivate *priv = + meta_wayland_actor_surface_get_instance_private (actor_surface); + + if (!priv->actor) + return; meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending); @@ -304,6 +318,13 @@ meta_wayland_actor_surface_get_actor (MetaWaylandActorSurface *actor_surface) return priv->actor; } +static void +on_actor_destroyed (ClutterActor *actor, + MetaWaylandActorSurface *actor_surface) +{ + clear_surface_actor (actor_surface); +} + void meta_wayland_actor_surface_reset_actor (MetaWaylandActorSurface *actor_surface) { @@ -315,6 +336,10 @@ meta_wayland_actor_surface_reset_actor (MetaWaylandActorSurface *actor_surface) clear_surface_actor (actor_surface); priv->actor = g_object_ref_sink (meta_surface_actor_wayland_new (surface)); + priv->actor_destroyed_handler_id = + g_signal_connect (priv->actor, "destroy", + G_CALLBACK (on_actor_destroyed), + surface); g_signal_connect_swapped (priv->actor, "notify::allocation", G_CALLBACK (meta_wayland_surface_notify_geometry_changed),