mirror of
https://github.com/brl/mutter.git
synced 2025-06-14 01:09:30 +00:00
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:
@ -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 = {
|
||||
|
Reference in New Issue
Block a user