From 57881ba612f1571f2bf3f1642f416741fc4d3610 Mon Sep 17 00:00:00 2001 From: Robert Mader Date: Fri, 8 Jul 2022 21:03:52 +0200 Subject: [PATCH] wayland/subsurface: Move actor unparenting back to rebuild_surface_tree() Unparenting the surface actor when the subsurface object is destroyed has several issues: - subsurface actors can be unparented while a close animation is still ongoing, breaking the animation for e.g. Firefox. - adding and removing the actor to/from the parent is not handled in one place, making the code harder to follow. - if the destroyed subsurface had children of its own, they potentially stick around until a surface-tree rebuild. This makes the Firefox hamburger menu not close with the "compositor" backend. Move the unparenting back to `meta_window_actor_wayland_rebuild_surface_tree()` and instead just notify the parent of a state change, if it still exist. This will ensure a correct mapping between the subsurface node tree and the flat surface actor list. In case of the closing animation the parent will already be removed and the call is skipped. Part-of: --- src/compositor/meta-window-actor-wayland.c | 32 ++++++++++++++++++++++ src/wayland/meta-wayland-subsurface.c | 17 +----------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/compositor/meta-window-actor-wayland.c b/src/compositor/meta-window-actor-wayland.c index e1f341048..09205de5e 100644 --- a/src/compositor/meta-window-actor-wayland.c +++ b/src/compositor/meta-window-actor-wayland.c @@ -38,6 +38,18 @@ typedef struct _SurfaceTreeTraverseData int index; } SurfaceTreeTraverseData; +static gboolean +get_surface_actor_list (GNode *node, + gpointer data) +{ + MetaWaylandSurface *surface = node->data; + MetaSurfaceActor *surface_actor = meta_wayland_surface_get_actor (surface); + GList **surface_actors = data; + + *surface_actors = g_list_prepend (*surface_actors, surface_actor); + return FALSE; +} + static gboolean set_surface_actor_index (GNode *node, gpointer data) @@ -74,8 +86,28 @@ meta_window_actor_wayland_rebuild_surface_tree (MetaWindowActor *actor) MetaWaylandSurface *surface = meta_surface_actor_wayland_get_surface ( META_SURFACE_ACTOR_WAYLAND (surface_actor)); GNode *root_node = surface->subsurface_branch_node; + g_autoptr (GList) surface_actors = NULL; + g_autoptr (GList) children = NULL; + GList *l; SurfaceTreeTraverseData traverse_data; + g_node_traverse (root_node, + G_IN_ORDER, + G_TRAVERSE_LEAVES, + -1, + get_surface_actor_list, + &surface_actors); + + children = clutter_actor_get_children (CLUTTER_ACTOR (actor)); + for (l = children; l; l = l->next) + { + ClutterActor *child_actor = l->data; + + if (META_IS_SURFACE_ACTOR_WAYLAND (child_actor) && + !g_list_find (surface_actors, child_actor)) + clutter_actor_remove_child (CLUTTER_ACTOR (actor), child_actor); + } + traverse_data = (SurfaceTreeTraverseData) { .window_actor = actor, .index = 0, diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c index bc30bc779..ef6f6657b 100644 --- a/src/wayland/meta-wayland-subsurface.c +++ b/src/wayland/meta-wayland-subsurface.c @@ -292,31 +292,16 @@ meta_wayland_subsurface_class_init (MetaWaylandSubsurfaceClass *klass) meta_wayland_subsurface_sync_actor_state; } -static void -unparent_actor (MetaWaylandSurface *surface) -{ - ClutterActor *actor; - ClutterActor *parent_actor; - - actor = CLUTTER_ACTOR (meta_wayland_surface_get_actor (surface)); - if (!actor) - return; - - parent_actor = clutter_actor_get_parent (actor); - if (parent_actor) - clutter_actor_remove_child (parent_actor, actor); -} - static void wl_subsurface_destructor (struct wl_resource *resource) { MetaWaylandSurface *surface = wl_resource_get_user_data (resource); g_node_unlink (surface->subsurface_branch_node); - unparent_actor (surface); if (surface->sub.parent) { + meta_wayland_surface_notify_subsurface_state_changed (surface->sub.parent); wl_list_remove (&surface->sub.parent_destroy_listener.link); surface->sub.parent = NULL; }