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

@ -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;

View File

@ -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 */

View File

@ -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),

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);

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 = {

View File

@ -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),

View File

@ -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;

View File

@ -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;