[mutter] wayland/subsurface: Move placement ops to the parents pending state



commit ba8499f9ec0ca017f11bcc8e50e66302b2f73aa7
Author: Robert Mader <robert mader posteo de>
Date:   Tue Mar 9 22:24:13 2021 +0100

    wayland/subsurface: Move placement ops to the parents pending state
    
    Unlike other subsurface state, placement operations need to get
    applied in order. As per spec:
    
    ```
    Requests are handled in order and applied immediately to a pending
    state. The final pending state is copied to the active state the
    next time the state of the parent surface is applied.
    ```
    
    Having placement operations being part of the subsurface state
    makes it difficult to support arbitrary orderings. Make them
    part of the parents surface pending state instead.
    
    Closes https://gitlab.gnome.org/GNOME/mutter/-/issues/1691
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1768>

 src/wayland/meta-wayland-subsurface.c | 94 +++++++++++------------------------
 src/wayland/meta-wayland-subsurface.h | 17 +++++++
 src/wayland/meta-wayland-surface.c    | 61 +++++++++++++++++++++++
 src/wayland/meta-wayland-surface.h    |  3 +-
 4 files changed, 108 insertions(+), 67 deletions(-)
---
diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c
index 78b23fe649..27bd91f0c6 100644
--- a/src/wayland/meta-wayland-subsurface.c
+++ b/src/wayland/meta-wayland-subsurface.c
@@ -30,19 +30,6 @@
 #include "wayland/meta-wayland-surface.h"
 #include "wayland/meta-window-wayland.h"
 
-typedef enum
-{
-  META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE,
-  META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW
-} MetaWaylandSubsurfacePlacement;
-
-typedef struct
-{
-  MetaWaylandSubsurfacePlacement placement;
-  MetaWaylandSurface *sibling;
-  struct wl_listener sibling_destroy_listener;
-} MetaWaylandSubsurfacePlacementOp;
-
 struct _MetaWaylandSubsurface
 {
   MetaWaylandActorSurface parent;
@@ -146,57 +133,6 @@ meta_wayland_subsurface_parent_state_applied (MetaWaylandSubsurface *subsurface)
       surface->sub.pending_pos = FALSE;
     }
 
-  if (surface->sub.pending_placement_ops)
-    {
-      GSList *it;
-      MetaWaylandSurface *parent;
-
-      parent = surface->sub.parent;
-
-      for (it = surface->sub.pending_placement_ops; it; it = it->next)
-        {
-          MetaWaylandSubsurfacePlacementOp *op = it->data;
-          MetaWaylandSurface *sibling;
-          GNode *sibling_node;
-
-          if (!op->sibling)
-            {
-              g_free (op);
-              continue;
-            }
-
-          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:
-              g_node_insert_after (parent->subsurface_branch_node,
-                                   sibling_node,
-                                   surface->subsurface_branch_node);
-              break;
-            case META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW:
-              g_node_insert_before (parent->subsurface_branch_node,
-                                    sibling_node,
-                                    surface->subsurface_branch_node);
-              break;
-            }
-
-          wl_list_remove (&op->sibling_destroy_listener.link);
-          g_free (op);
-        }
-
-      g_slist_free (surface->sub.pending_placement_ops);
-      surface->sub.pending_placement_ops = NULL;
-
-      meta_wayland_surface_notify_subsurface_state_changed (parent);
-    }
-
   if (is_surface_effectively_synchronized (surface))
     meta_wayland_surface_apply_cached_state (surface);
 
@@ -418,6 +354,16 @@ is_valid_sibling (MetaWaylandSurface *surface,
   return FALSE;
 }
 
+static void
+subsurface_handle_pending_surface_destroyed (struct wl_listener *listener,
+                                             void               *data)
+{
+  MetaWaylandSubsurfacePlacementOp *op =
+    wl_container_of (listener, op, surface_destroy_listener);
+
+  op->surface = NULL;
+}
+
 static void
 subsurface_handle_pending_sibling_destroyed (struct wl_listener *listener,
                                              void               *data)
@@ -428,23 +374,39 @@ subsurface_handle_pending_sibling_destroyed (struct wl_listener *listener,
   op->sibling = NULL;
 }
 
+void
+meta_wayland_subsurface_placement_op_free (MetaWaylandSubsurfacePlacementOp *op)
+{
+  if (op->surface)
+    wl_list_remove (&op->surface_destroy_listener.link);
+  if (op->sibling)
+    wl_list_remove (&op->sibling_destroy_listener.link);
+  g_free (op);
+}
+
 static void
 queue_subsurface_placement (MetaWaylandSurface             *surface,
                             MetaWaylandSurface             *sibling,
                             MetaWaylandSubsurfacePlacement  placement)
 {
+  MetaWaylandSurface *parent = surface->sub.parent;
   MetaWaylandSubsurfacePlacementOp *op =
     g_new0 (MetaWaylandSubsurfacePlacementOp, 1);
 
   op->placement = placement;
+  op->surface = surface;
   op->sibling = sibling;
+  op->surface_destroy_listener.notify =
+    subsurface_handle_pending_surface_destroyed;
   op->sibling_destroy_listener.notify =
     subsurface_handle_pending_sibling_destroyed;
+  wl_resource_add_destroy_listener (surface->resource,
+                                    &op->surface_destroy_listener);
   wl_resource_add_destroy_listener (sibling->resource,
                                     &op->sibling_destroy_listener);
 
-  surface->sub.pending_placement_ops =
-    g_slist_append (surface->sub.pending_placement_ops, op);
+  parent->pending_state->subsurface_placement_ops =
+    g_slist_append (parent->pending_state->subsurface_placement_ops, op);
 }
 
 static void
diff --git a/src/wayland/meta-wayland-subsurface.h b/src/wayland/meta-wayland-subsurface.h
index d92c021976..7ea6bc5ae1 100644
--- a/src/wayland/meta-wayland-subsurface.h
+++ b/src/wayland/meta-wayland-subsurface.h
@@ -29,6 +29,21 @@ G_DECLARE_FINAL_TYPE (MetaWaylandSubsurface,
                       META, WAYLAND_SUBSURFACE,
                       MetaWaylandActorSurface)
 
+typedef enum
+{
+  META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE,
+  META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW
+} MetaWaylandSubsurfacePlacement;
+
+typedef struct
+{
+  MetaWaylandSubsurfacePlacement placement;
+  MetaWaylandSurface *surface;
+  MetaWaylandSurface *sibling;
+  struct wl_listener surface_destroy_listener;
+  struct wl_listener sibling_destroy_listener;
+} MetaWaylandSubsurfacePlacementOp;
+
 void meta_wayland_subsurface_parent_state_applied (MetaWaylandSubsurface *subsurface);
 
 void meta_wayland_subsurface_union_geometry (MetaWaylandSubsurface *subsurface,
@@ -36,6 +51,8 @@ void meta_wayland_subsurface_union_geometry (MetaWaylandSubsurface *subsurface,
                                              int                    parent_y,
                                              MetaRectangle         *out_geometry);
 
+void meta_wayland_subsurface_placement_op_free (MetaWaylandSubsurfacePlacementOp *op);
+
 void meta_wayland_subsurfaces_init (MetaWaylandCompositor *compositor);
 
 #endif /* META_WAYLAND_SUBSURFACE_H */
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 962ab05ff3..465b67619d 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -468,6 +468,8 @@ meta_wayland_surface_state_set_default (MetaWaylandSurfaceState *state)
   state->has_new_viewport_src_rect = FALSE;
   state->has_new_viewport_dst_size = FALSE;
 
+  state->subsurface_placement_ops = NULL;
+
   wl_list_init (&state->presentation_feedback_list);
 }
 
@@ -499,6 +501,13 @@ meta_wayland_surface_state_clear (MetaWaylandSurfaceState *state)
   wl_list_for_each_safe (cb, next, &state->frame_callback_list, link)
     wl_resource_destroy (cb->resource);
 
+  if (state->subsurface_placement_ops)
+    {
+      g_slist_free_full (
+        state->subsurface_placement_ops,
+        (GDestroyNotify) meta_wayland_subsurface_placement_op_free);
+    }
+
   meta_wayland_surface_state_discard_presentation_feedback (state);
 }
 
@@ -609,6 +618,21 @@ meta_wayland_surface_state_merge_into (MetaWaylandSurfaceState *from,
                           to);
     }
 
+  if (from->subsurface_placement_ops != NULL)
+    {
+      if (to->subsurface_placement_ops != NULL)
+        {
+          to->subsurface_placement_ops =
+            g_slist_concat (to->subsurface_placement_ops,
+                            from->subsurface_placement_ops);
+          from->subsurface_placement_ops = NULL;
+        }
+      else
+        {
+          to->subsurface_placement_ops = from->subsurface_placement_ops;
+        }
+    }
+
   wl_list_insert_list (&to->presentation_feedback_list,
                        &from->presentation_feedback_list);
   wl_list_init (&from->presentation_feedback_list);
@@ -827,6 +851,43 @@ meta_wayland_surface_apply_state (MetaWaylandSurface      *surface,
         }
     }
 
+  if (state->subsurface_placement_ops)
+    {
+      GSList *l;
+
+      for (l = state->subsurface_placement_ops; l; l = l->next)
+        {
+          MetaWaylandSubsurfacePlacementOp *op = l->data;
+          GNode *sibling_node;
+
+          if (!op->surface || !op->sibling)
+            continue;
+
+          if (op->sibling == surface)
+            sibling_node = surface->subsurface_leaf_node;
+          else
+            sibling_node = op->sibling->subsurface_branch_node;
+
+          g_node_unlink (op->surface->subsurface_branch_node);
+
+          switch (op->placement)
+            {
+            case META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE:
+              g_node_insert_after (surface->subsurface_branch_node,
+                                   sibling_node,
+                                   op->surface->subsurface_branch_node);
+              break;
+            case META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW:
+              g_node_insert_before (surface->subsurface_branch_node,
+                                    sibling_node,
+                                    op->surface->subsurface_branch_node);
+              break;
+            }
+        }
+
+      meta_wayland_surface_notify_subsurface_state_changed (surface);
+    }
+
 cleanup:
   /* If we have a buffer that we are not using, decrease the use count so it may
    * be released if no-one else has a use-reference to it.
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index 22afb0ae17..f0153b23b9 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -121,6 +121,8 @@ struct _MetaWaylandSurfaceState
   int viewport_dst_width;
   int viewport_dst_height;
 
+  GSList *subsurface_placement_ops;
+
   /* presentation-time */
   struct wl_list presentation_feedback_list;
 };
@@ -212,7 +214,6 @@ struct _MetaWaylandSurface
     int32_t pending_x;
     int32_t pending_y;
     gboolean pending_pos;
-    GSList *pending_placement_ops;
   } sub;
 
   /* wp_viewport */


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