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
This commit is contained in:
Robert Mader
2019-06-30 15:18:46 +02:00
parent a51437ee2b
commit 77229f99b8
11 changed files with 261 additions and 67 deletions

View File

@ -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);
clutter_actor_set_reactive (CLUTTER_ACTOR (meta_wayland_surface_get_actor (surface)), TRUE);
window_actor = meta_window_actor_wayland_from_surface (surface);
if (window_actor)
meta_window_actor_wayland_rebuild_surface_tree (window_actor);
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 = {