[mutter] wayland: Implement subsurface.place_below() for parents



commit 77229f99b882ba4e9b09b31617175fdb653738f6
Author: Robert Mader <robert mader posteo de>
Date:   Sun Jun 30 15:18:46 2019 +0200

    wayland: Implement subsurface.place_below() for parents
    
    Flatten the subsurface actor tree, making all surface actors children
    of the window actor.
    Save the subsurface state in a GNode tree in MetaWaylandSurface, where
    each surface holds two nodes, one branch, which can be the tree root
    or be attached to a parent surfaces branch, and a leaf, which is
    used to save the position relative to child branch nodes.
    
    Each time a surface is added or reordered in the tree, unparent all
    surface actors from the window actor, traverse all leaves of the
    tree and readd the corresponding surface actors back to the window
    actor.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/664

 src/compositor/meta-window-actor-wayland.c |  86 ++++++++++++++++++++-
 src/compositor/meta-window-actor-wayland.h |   4 +
 src/compositor/meta-window-actor-x11.c     |   3 +
 src/compositor/meta-window-actor.c         |   1 -
 src/wayland/meta-wayland-actor-surface.c   |  25 +++---
 src/wayland/meta-wayland-pointer.c         |  11 ++-
 src/wayland/meta-wayland-shell-surface.c   |  15 ++--
 src/wayland/meta-wayland-subsurface.c      | 119 +++++++++++++++++++++--------
 src/wayland/meta-wayland-surface.c         |  50 ++++++++++--
 src/wayland/meta-wayland-surface.h         |   3 +-
 src/wayland/meta-wayland-tablet-tool.c     |  11 ++-
 11 files changed, 261 insertions(+), 67 deletions(-)
---
diff --git a/src/compositor/meta-window-actor-wayland.c b/src/compositor/meta-window-actor-wayland.c
index f50978e8f..e251e3a27 100644
--- a/src/compositor/meta-window-actor-wayland.c
+++ b/src/compositor/meta-window-actor-wayland.c
@@ -20,9 +20,10 @@
  *     Georges Basile Stavracas Neto <gbsneto gnome org>
  */
 
-#include "compositor/meta-surface-actor.h"
+#include "compositor/meta-surface-actor-wayland.h"
 #include "compositor/meta-window-actor-wayland.h"
 #include "meta/meta-window-actor.h"
+#include "wayland/meta-wayland-surface.h"
 
 struct _MetaWindowActorWayland
 {
@@ -31,6 +32,88 @@ struct _MetaWindowActorWayland
 
 G_DEFINE_TYPE (MetaWindowActorWayland, meta_window_actor_wayland, META_TYPE_WINDOW_ACTOR)
 
+static gboolean
+remove_surface_actor_from_children (GNode    *node,
+                                    gpointer  data)
+{
+  MetaWaylandSurface *surface = node->data;
+  MetaSurfaceActor *surface_actor = meta_wayland_surface_get_actor (surface);
+  MetaWindowActor *window_actor = data;
+  ClutterActor *parent;
+
+  parent = clutter_actor_get_parent (CLUTTER_ACTOR (surface_actor));
+  if (!parent)
+    return FALSE;
+
+  g_return_val_if_fail (parent == CLUTTER_ACTOR (window_actor), FALSE);
+
+  clutter_actor_remove_child (CLUTTER_ACTOR (window_actor),
+                              CLUTTER_ACTOR (surface_actor));
+
+  return FALSE;
+}
+
+static gboolean
+add_surface_actor_to_children (GNode    *node,
+                               gpointer  data)
+{
+  MetaWaylandSurface *surface = node->data;
+  MetaSurfaceActor *surface_actor = meta_wayland_surface_get_actor (surface);
+  MetaWindowActor *window_actor = data;
+
+  clutter_actor_add_child (CLUTTER_ACTOR (window_actor),
+                           CLUTTER_ACTOR (surface_actor));
+
+  return FALSE;
+}
+
+void
+meta_window_actor_wayland_rebuild_surface_tree (MetaWindowActor *actor)
+{
+  MetaSurfaceActor *surface_actor =
+    meta_window_actor_get_surface (actor);
+  MetaWaylandSurface *surface = meta_surface_actor_wayland_get_surface (
+    META_SURFACE_ACTOR_WAYLAND (surface_actor));
+  GNode *root_node = surface->subsurface_branch_node;
+
+  g_node_traverse (root_node,
+                   G_IN_ORDER,
+                   G_TRAVERSE_LEAVES,
+                   -1,
+                   remove_surface_actor_from_children,
+                   actor);
+
+  g_node_traverse (root_node,
+                   G_IN_ORDER,
+                   G_TRAVERSE_LEAVES,
+                   -1,
+                   add_surface_actor_to_children,
+                   actor);
+}
+
+MetaWindowActor *
+meta_window_actor_wayland_from_surface (MetaWaylandSurface *surface)
+{
+  if (surface->window)
+    return meta_window_actor_from_window (surface->window);
+  else if (surface->sub.parent)
+    return meta_window_actor_wayland_from_surface (surface->sub.parent);
+  else
+    return NULL;
+}
+
+static void
+meta_window_actor_wayland_assign_surface_actor (MetaWindowActor  *actor,
+                                                MetaSurfaceActor *surface_actor)
+{
+  MetaWindowActorClass *parent_class =
+    META_WINDOW_ACTOR_CLASS (meta_window_actor_wayland_parent_class);
+
+  parent_class->assign_surface_actor (actor, surface_actor);
+
+  meta_window_actor_wayland_rebuild_surface_tree (actor);
+}
+
 static void
 meta_window_actor_wayland_frame_complete (MetaWindowActor  *actor,
                                           ClutterFrameInfo *frame_info,
@@ -64,6 +147,7 @@ meta_window_actor_wayland_class_init (MetaWindowActorWaylandClass *klass)
 {
   MetaWindowActorClass *window_actor_class = META_WINDOW_ACTOR_CLASS (klass);
 
+  window_actor_class->assign_surface_actor = meta_window_actor_wayland_assign_surface_actor;
   window_actor_class->frame_complete = meta_window_actor_wayland_frame_complete;
   window_actor_class->queue_frame_drawn = meta_window_actor_wayland_queue_frame_drawn;
   window_actor_class->pre_paint = meta_window_actor_wayland_pre_paint;
diff --git a/src/compositor/meta-window-actor-wayland.h b/src/compositor/meta-window-actor-wayland.h
index 560800693..d7e1b7808 100644
--- a/src/compositor/meta-window-actor-wayland.h
+++ b/src/compositor/meta-window-actor-wayland.h
@@ -24,6 +24,7 @@
 #define META_WINDOW_ACTOR_WAYLAND_H
 
 #include "compositor/meta-window-actor-private.h"
+#include "wayland/meta-wayland-surface.h"
 
 #define META_TYPE_WINDOW_ACTOR_WAYLAND (meta_window_actor_wayland_get_type())
 G_DECLARE_FINAL_TYPE (MetaWindowActorWayland,
@@ -31,4 +32,7 @@ G_DECLARE_FINAL_TYPE (MetaWindowActorWayland,
                       META, WINDOW_ACTOR_WAYLAND,
                       MetaWindowActor)
 
+void meta_window_actor_wayland_rebuild_surface_tree (MetaWindowActor *actor);
+MetaWindowActor * meta_window_actor_wayland_from_surface (MetaWaylandSurface *surface);
+
 #endif /*META_WINDOW_ACTOR_WAYLAND_H */
diff --git a/src/compositor/meta-window-actor-x11.c b/src/compositor/meta-window-actor-x11.c
index 03035d6bf..a82b923f3 100644
--- a/src/compositor/meta-window-actor-x11.c
+++ b/src/compositor/meta-window-actor-x11.c
@@ -338,6 +338,9 @@ meta_window_actor_x11_assign_surface_actor (MetaWindowActor  *actor,
 
   parent_class->assign_surface_actor (actor, surface_actor);
 
+  clutter_actor_add_child (CLUTTER_ACTOR (actor),
+                           CLUTTER_ACTOR (surface_actor));
+
   actor_x11->repaint_scheduled_id =
     g_signal_connect (surface_actor, "repaint-scheduled",
                       G_CALLBACK (surface_repaint_scheduled),
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index 312eb9811..d2d46e6b0 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -377,7 +377,6 @@ meta_window_actor_real_assign_surface_actor (MetaWindowActor  *self,
   priv->size_changed_id = g_signal_connect (priv->surface, "size-changed",
                                             G_CALLBACK (surface_size_changed),
                                             self);
-  clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface));
 
   meta_window_actor_update_shape (self);
 
diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c
index eb909c3b5..aea67a589 100644
--- a/src/wayland/meta-wayland-actor-surface.c
+++ b/src/wayland/meta-wayland-actor-surface.c
@@ -26,6 +26,7 @@
 #include "backends/meta-backend-private.h"
 #include "backends/meta-logical-monitor.h"
 #include "compositor/meta-surface-actor-wayland.h"
+#include "compositor/meta-window-actor-wayland.h"
 #include "compositor/region-utils.h"
 #include "wayland/meta-wayland-surface.h"
 #include "wayland/meta-window-wayland.h"
@@ -76,18 +77,10 @@ meta_wayland_actor_surface_assigned (MetaWaylandSurfaceRole *surface_role)
     meta_wayland_actor_surface_get_instance_private (META_WAYLAND_ACTOR_SURFACE (surface_role));
   MetaWaylandSurface *surface =
     meta_wayland_surface_role_get_surface (surface_role);
-  GList *l;
 
   meta_surface_actor_wayland_add_frame_callbacks (META_SURFACE_ACTOR_WAYLAND (priv->actor),
                                                   &surface->pending_frame_callback_list);
   wl_list_init (&surface->pending_frame_callback_list);
-
-  for (l = surface->subsurfaces; l; l = l->next)
-    {
-      ClutterActor *subsurface_actor =
-        CLUTTER_ACTOR (meta_wayland_surface_get_actor (l->data));
-      clutter_actor_add_child (CLUTTER_ACTOR (priv->actor), subsurface_actor);
-    }
 }
 
 void
@@ -139,7 +132,7 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor
     meta_wayland_surface_role_get_surface (surface_role);
   MetaSurfaceActor *surface_actor;
   MetaShapedTexture *stex;
-  GList *l;
+  GNode *n;
   cairo_rectangle_int_t surface_rect;
   int geometry_scale;
 
@@ -205,12 +198,18 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor
       meta_surface_actor_reset_viewport_dst_size (surface_actor);
     }
 
-  for (l = surface->subsurfaces; l; l = l->next)
+  for (n = g_node_first_child (surface->subsurface_branch_node);
+       n;
+       n = g_node_next_sibling (n))
     {
-      MetaWaylandSurface *subsurface_surface = l->data;
-      MetaWaylandActorSurface *subsurface_actor_surface =
-        META_WAYLAND_ACTOR_SURFACE (subsurface_surface->role);
+      MetaWaylandSurface *subsurface_surface = n->data;
+      MetaWaylandActorSurface *subsurface_actor_surface;
+
+      if (G_NODE_IS_LEAF (n))
+        continue;
 
+      subsurface_actor_surface =
+        META_WAYLAND_ACTOR_SURFACE (subsurface_surface->role);
       meta_wayland_actor_surface_sync_actor_state (subsurface_actor_surface);
     }
 }
diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c
index e41aab8e0..334349e30 100644
--- a/src/wayland/meta-wayland-pointer.c
+++ b/src/wayland/meta-wayland-pointer.c
@@ -1194,14 +1194,19 @@ static gboolean
 pointer_can_grab_surface (MetaWaylandPointer *pointer,
                           MetaWaylandSurface *surface)
 {
-  GList *l;
+  GNode *n;
 
   if (pointer->focus_surface == surface)
     return TRUE;
 
-  for (l = surface->subsurfaces; l; l = l->next)
+  for (n = g_node_first_child (surface->subsurface_branch_node);
+       n;
+       n = g_node_next_sibling (n))
     {
-      MetaWaylandSurface *subsurface = l->data;
+      MetaWaylandSurface *subsurface = n->data;
+
+      if (G_NODE_IS_LEAF (n))
+        continue;
 
       if (pointer_can_grab_surface (pointer, subsurface))
         return TRUE;
diff --git a/src/wayland/meta-wayland-shell-surface.c b/src/wayland/meta-wayland-shell-surface.c
index 3ebfdd284..32b4d981c 100644
--- a/src/wayland/meta-wayland-shell-surface.c
+++ b/src/wayland/meta-wayland-shell-surface.c
@@ -43,19 +43,24 @@ meta_wayland_shell_surface_calculate_geometry (MetaWaylandShellSurface *shell_su
   MetaWaylandSurface *surface =
     meta_wayland_surface_role_get_surface (surface_role);
   MetaRectangle geometry;
-  GList *l;
+  GNode *n;
 
   geometry = (MetaRectangle) {
     .width = meta_wayland_surface_get_width (surface),
     .height = meta_wayland_surface_get_height (surface),
   };
 
-  for (l = surface->subsurfaces; l; l = l->next)
+  for (n = g_node_first_child (surface->subsurface_branch_node);
+       n;
+       n = g_node_next_sibling (n))
     {
-      MetaWaylandSurface *subsurface_surface = l->data;
-      MetaWaylandSubsurface *subsurface =
-        META_WAYLAND_SUBSURFACE (subsurface_surface->role);
+      MetaWaylandSurface *subsurface_surface = n->data;
+      MetaWaylandSubsurface *subsurface;
 
+      if (G_NODE_IS_LEAF (n))
+        continue;
+
+      subsurface = META_WAYLAND_SUBSURFACE (subsurface_surface->role);
       meta_wayland_subsurface_union_geometry (subsurface,
                                               0, 0,
                                               &geometry);
diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c
index 3b813a191..8724da39f 100644
--- a/src/wayland/meta-wayland-subsurface.c
+++ b/src/wayland/meta-wayland-subsurface.c
@@ -23,6 +23,7 @@
 #include "wayland/meta-wayland-subsurface.h"
 
 #include "compositor/meta-surface-actor-wayland.h"
+#include "compositor/meta-window-actor-wayland.h"
 #include "wayland/meta-wayland.h"
 #include "wayland/meta-wayland-actor-surface.h"
 #include "wayland/meta-wayland-buffer.h"
@@ -51,6 +52,21 @@ G_DEFINE_TYPE (MetaWaylandSubsurface,
                meta_wayland_subsurface,
                META_TYPE_WAYLAND_ACTOR_SURFACE)
 
+static void
+transform_subsurface_position (MetaWaylandSurface *surface,
+                               int                *x,
+                               int                *y)
+{
+  do
+    {
+      *x += surface->sub.x;
+      *y += surface->sub.y;
+
+      surface = surface->sub.parent;
+    }
+  while (surface);
+}
+
 static void
 sync_actor_subsurface_state (MetaWaylandSurface *surface)
 {
@@ -65,8 +81,8 @@ sync_actor_subsurface_state (MetaWaylandSurface *surface)
   if (toplevel_window->client_type == META_WINDOW_CLIENT_TYPE_X11)
     return;
 
-  x = surface->offset_x + surface->sub.x;
-  y = surface->offset_y + surface->sub.y;
+  x = y = 0;
+  transform_subsurface_position (surface, &x, &y);
 
   clutter_actor_set_position (actor, x, y);
 
@@ -76,6 +92,26 @@ sync_actor_subsurface_state (MetaWaylandSurface *surface)
     clutter_actor_hide (actor);
 }
 
+static gboolean
+is_child (MetaWaylandSurface *surface,
+          MetaWaylandSurface *sibling)
+{
+  if (surface->sub.parent == sibling)
+    return TRUE;
+  else
+    return FALSE;
+}
+
+static gboolean
+is_sibling (MetaWaylandSurface *surface,
+            MetaWaylandSurface *sibling)
+{
+  if (surface->sub.parent == sibling->sub.parent)
+    return TRUE;
+  else
+    return FALSE;
+}
+
 void
 meta_wayland_subsurface_parent_state_applied (MetaWaylandSubsurface *subsurface)
 {
@@ -95,15 +131,16 @@ meta_wayland_subsurface_parent_state_applied (MetaWaylandSubsurface *subsurface)
   if (surface->sub.pending_placement_ops)
     {
       GSList *it;
-      MetaWaylandSurface *parent = surface->sub.parent;
-      ClutterActor *parent_actor =
-        clutter_actor_get_parent (CLUTTER_ACTOR (meta_wayland_surface_get_actor (parent)));
-      ClutterActor *surface_actor = CLUTTER_ACTOR (meta_wayland_surface_get_actor (surface));
+      MetaWaylandSurface *parent;
+      MetaWindowActor *window_actor;
+
+      parent = surface->sub.parent;
 
       for (it = surface->sub.pending_placement_ops; it; it = it->next)
         {
           MetaWaylandSubsurfacePlacementOp *op = it->data;
-          ClutterActor *sibling_actor;
+          MetaWaylandSurface *sibling;
+          GNode *sibling_node;
 
           if (!op->sibling)
             {
@@ -111,19 +148,25 @@ meta_wayland_subsurface_parent_state_applied (MetaWaylandSubsurface *subsurface)
               continue;
             }
 
-          sibling_actor = CLUTTER_ACTOR (meta_wayland_surface_get_actor (op->sibling));
+          sibling = op->sibling;
+          if (is_child (surface, sibling))
+            sibling_node = sibling->subsurface_leaf_node;
+          else
+            sibling_node = sibling->subsurface_branch_node;
+
+          g_node_unlink (surface->subsurface_branch_node);
 
           switch (op->placement)
             {
             case META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE:
-              clutter_actor_set_child_above_sibling (parent_actor,
-                                                     surface_actor,
-                                                     sibling_actor);
+              g_node_insert_after (parent->subsurface_branch_node,
+                                   sibling_node,
+                                   surface->subsurface_branch_node);
               break;
             case META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW:
-              clutter_actor_set_child_below_sibling (parent_actor,
-                                                     surface_actor,
-                                                     sibling_actor);
+              g_node_insert_before (parent->subsurface_branch_node,
+                                    sibling_node,
+                                    surface->subsurface_branch_node);
               break;
             }
 
@@ -133,6 +176,10 @@ meta_wayland_subsurface_parent_state_applied (MetaWaylandSubsurface *subsurface)
 
       g_slist_free (surface->sub.pending_placement_ops);
       surface->sub.pending_placement_ops = NULL;
+
+      window_actor = meta_window_actor_wayland_from_surface (surface);
+      if (window_actor)
+        meta_window_actor_wayland_rebuild_surface_tree (window_actor);
     }
 
   if (meta_wayland_surface_is_effectively_synchronized (surface))
@@ -151,7 +198,7 @@ meta_wayland_subsurface_union_geometry (MetaWaylandSubsurface *subsurface,
   MetaWaylandSurface *surface =
     meta_wayland_surface_role_get_surface (surface_role);
   MetaRectangle geometry;
-  GList *l;
+  GNode *n;
 
   geometry = (MetaRectangle) {
     .x = surface->offset_x + surface->sub.x,
@@ -162,12 +209,17 @@ meta_wayland_subsurface_union_geometry (MetaWaylandSubsurface *subsurface,
 
   meta_rectangle_union (out_geometry, &geometry, out_geometry);
 
-  for (l = surface->subsurfaces; l; l = l->next)
+  for (n = g_node_first_child (surface->subsurface_branch_node);
+       n;
+       n = g_node_next_sibling (n))
     {
-      MetaWaylandSurface *subsurface_surface = l->data;
-      MetaWaylandSubsurface *subsurface =
-        META_WAYLAND_SUBSURFACE (subsurface_surface->role);
+      MetaWaylandSurface *subsurface_surface = n->data;
+      MetaWaylandSubsurface *subsurface;
 
+      if (G_NODE_IS_LEAF (n))
+        continue;
+
+      subsurface = META_WAYLAND_SUBSURFACE (subsurface_surface->role);
       meta_wayland_subsurface_union_geometry (subsurface,
                                               parent_x + geometry.x,
                                               parent_y + geometry.y,
@@ -242,12 +294,13 @@ wl_subsurface_destructor (struct wl_resource *resource)
 
   meta_wayland_compositor_destroy_frame_callbacks (surface->compositor,
                                                    surface);
+
+  g_node_unlink (surface->subsurface_branch_node);
+  unparent_actor (surface);
+
   if (surface->sub.parent)
     {
       wl_list_remove (&surface->sub.parent_destroy_listener.link);
-      surface->sub.parent->subsurfaces =
-        g_list_remove (surface->sub.parent->subsurfaces, surface);
-      unparent_actor (surface);
       surface->sub.parent = NULL;
     }
 
@@ -279,9 +332,9 @@ static gboolean
 is_valid_sibling (MetaWaylandSurface *surface,
                   MetaWaylandSurface *sibling)
 {
-  if (surface->sub.parent == sibling)
+  if (is_child (surface, sibling))
     return TRUE;
-  if (surface->sub.parent == sibling->sub.parent)
+  if (is_sibling (surface, sibling))
     return TRUE;
   return FALSE;
 }
@@ -409,7 +462,6 @@ surface_handle_parent_surface_destroyed (struct wl_listener *listener,
                                                  sub.parent_destroy_listener);
 
   surface->sub.parent = NULL;
-  unparent_actor (surface);
 }
 
 static void
@@ -422,6 +474,8 @@ wl_subcompositor_get_subsurface (struct wl_client   *client,
   MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
   MetaWaylandSurface *parent = wl_resource_get_user_data (parent_resource);
   MetaWindow *toplevel_window;
+  MetaWindowActor *window_actor;
+  MetaSurfaceActor *surface_actor;
 
   if (surface->wl_subsurface)
     {
@@ -463,15 +517,16 @@ wl_subcompositor_get_subsurface (struct wl_client   *client,
     surface_handle_parent_surface_destroyed;
   wl_resource_add_destroy_listener (parent->resource,
                                     &surface->sub.parent_destroy_listener);
-  parent->subsurfaces = g_list_append (parent->subsurfaces, surface);
 
-  if (meta_wayland_surface_get_actor (parent))
-    {
-      clutter_actor_add_child (CLUTTER_ACTOR (meta_wayland_surface_get_actor (parent)),
-                               CLUTTER_ACTOR (meta_wayland_surface_get_actor (surface)));
-    }
+  g_node_append (parent->subsurface_branch_node,
+                 surface->subsurface_branch_node);
+
+  window_actor = meta_window_actor_wayland_from_surface (surface);
+  if (window_actor)
+    meta_window_actor_wayland_rebuild_surface_tree (window_actor);
 
-  clutter_actor_set_reactive (CLUTTER_ACTOR (meta_wayland_surface_get_actor (surface)), TRUE);
+  surface_actor = meta_wayland_surface_get_actor (surface);
+  clutter_actor_set_reactive (CLUTTER_ACTOR (surface_actor), TRUE);
 }
 
 static const struct wl_subcompositor_interface meta_wayland_subcompositor_interface = {
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 787265f33..9a1b45ece 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -646,12 +646,16 @@ meta_wayland_surface_is_effectively_synchronized (MetaWaylandSurface *surface)
 }
 
 static void
-parent_surface_state_applied (gpointer data,
-                              gpointer user_data)
+parent_surface_state_applied (GNode    *subsurface_node,
+                              gpointer  user_data)
 {
-  MetaWaylandSurface *surface = data;
-  MetaWaylandSubsurface *subsurface = META_WAYLAND_SUBSURFACE (surface->role);
+  MetaWaylandSurface *surface = subsurface_node->data;
+  MetaWaylandSubsurface *subsurface;
 
+  if (G_NODE_IS_LEAF (subsurface_node))
+    return;
+
+  subsurface = META_WAYLAND_SUBSURFACE (surface->role);
   meta_wayland_subsurface_parent_state_applied (subsurface);
 }
 
@@ -836,7 +840,10 @@ cleanup:
 
   pending_state_reset (pending);
 
-  g_list_foreach (surface->subsurfaces, parent_surface_state_applied, NULL);
+  g_node_children_foreach (surface->subsurface_branch_node,
+                           G_TRAVERSE_ALL,
+                           parent_surface_state_applied,
+                           NULL);
 }
 
 static void
@@ -1254,14 +1261,22 @@ meta_wayland_surface_update_outputs (MetaWaylandSurface *surface)
 static void
 meta_wayland_surface_update_outputs_recursively (MetaWaylandSurface *surface)
 {
-  GList *l;
+  GNode *n;
 
   meta_wayland_surface_update_outputs (surface);
 
-  for (l = surface->subsurfaces; l != NULL; l = l->next)
-    meta_wayland_surface_update_outputs_recursively (l->data);
+  for (n = g_node_first_child (surface->subsurface_branch_node);
+       n;
+       n = g_node_next_sibling (n))
+    {
+      if (G_NODE_IS_LEAF (n))
+        continue;
+
+      meta_wayland_surface_update_outputs_recursively (n->data);
+    }
 }
 
+
 void
 meta_wayland_surface_set_window (MetaWaylandSurface *surface,
                                  MetaWindow         *window)
@@ -1306,6 +1321,13 @@ meta_wayland_surface_set_window (MetaWaylandSurface *surface,
     }
 }
 
+static void
+unlink_note (GNode    *node,
+             gpointer  data)
+{
+  g_node_unlink (node);
+}
+
 static void
 wl_surface_destructor (struct wl_resource *resource)
 {
@@ -1355,6 +1377,15 @@ wl_surface_destructor (struct wl_resource *resource)
   if (surface->wl_subsurface)
     wl_resource_destroy (surface->wl_subsurface);
 
+  if (surface->subsurface_branch_node)
+    {
+      g_node_children_foreach (surface->subsurface_branch_node,
+                               G_TRAVERSE_NON_LEAVES,
+                               unlink_note,
+                               NULL);
+      g_clear_pointer (&surface->subsurface_branch_node, g_node_destroy);
+    }
+
   g_hash_table_destroy (surface->shortcut_inhibited_seats);
 
   g_object_unref (surface);
@@ -1612,6 +1643,9 @@ static void
 meta_wayland_surface_init (MetaWaylandSurface *surface)
 {
   surface->pending = g_object_new (META_TYPE_WAYLAND_PENDING_STATE, NULL);
+  surface->subsurface_branch_node = g_node_new (surface);
+  surface->subsurface_leaf_node =
+    g_node_prepend_data (surface->subsurface_branch_node, surface);
 
   g_signal_connect (surface, "geometry-changed",
                     G_CALLBACK (meta_wayland_surface_update_outputs_recursively),
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index e244a3fdf..9b225fc6f 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -145,7 +145,8 @@ struct _MetaWaylandSurface
   cairo_region_t *opaque_region;
   int scale;
   int32_t offset_x, offset_y;
-  GList *subsurfaces;
+  GNode *subsurface_branch_node;
+  GNode *subsurface_leaf_node;
   GHashTable *outputs_to_destroy_notify_id;
   MetaMonitorTransform buffer_transform;
 
diff --git a/src/wayland/meta-wayland-tablet-tool.c b/src/wayland/meta-wayland-tablet-tool.c
index cce93030b..fd491fa50 100644
--- a/src/wayland/meta-wayland-tablet-tool.c
+++ b/src/wayland/meta-wayland-tablet-tool.c
@@ -989,14 +989,19 @@ static gboolean
 tablet_tool_can_grab_surface (MetaWaylandTabletTool *tool,
                               MetaWaylandSurface    *surface)
 {
-  GList *l;
+  GNode *n;
 
   if (tool->focus_surface == surface)
     return TRUE;
 
-  for (l = surface->subsurfaces; l; l = l->next)
+  for (n = g_node_first_child (surface->subsurface_branch_node);
+       n;
+       n = g_node_next_sibling (n))
     {
-      MetaWaylandSurface *subsurface = l->data;
+      MetaWaylandSurface *subsurface = n->data;
+
+      if (G_NODE_IS_LEAF (n))
+        continue;
 
       if (tablet_tool_can_grab_surface (tool, subsurface))
         return TRUE;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]