From ba8499f9ec0ca017f11bcc8e50e66302b2f73aa7 Mon Sep 17 00:00:00 2001 From: Robert Mader Date: Tue, 9 Mar 2021 22:24:13 +0100 Subject: [PATCH] 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: --- 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 78b23fe64..27bd91f0c 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 d92c02197..7ea6bc5ae 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 962ab05ff..465b67619 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 22afb0ae1..f0153b23b 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 */