diff --git a/src/compositor/meta-window-actor-wayland.c b/src/compositor/meta-window-actor-wayland.c index f50978e8f..e251e3a27 100644 --- a/src/compositor/meta-window-actor-wayland.c +++ b/src/compositor/meta-window-actor-wayland.c @@ -20,9 +20,10 @@ * Georges Basile Stavracas Neto */ -#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; diff --git a/src/compositor/meta-window-actor-wayland.h b/src/compositor/meta-window-actor-wayland.h index 560800693..d7e1b7808 100644 --- a/src/compositor/meta-window-actor-wayland.h +++ b/src/compositor/meta-window-actor-wayland.h @@ -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 */ diff --git a/src/compositor/meta-window-actor-x11.c b/src/compositor/meta-window-actor-x11.c index 03035d6bf..a82b923f3 100644 --- a/src/compositor/meta-window-actor-x11.c +++ b/src/compositor/meta-window-actor-x11.c @@ -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), diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index 312eb9811..d2d46e6b0 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -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); diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c index eb909c3b5..aea67a589 100644 --- a/src/wayland/meta-wayland-actor-surface.c +++ b/src/wayland/meta-wayland-actor-surface.c @@ -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); } } diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c index e41aab8e0..334349e30 100644 --- a/src/wayland/meta-wayland-pointer.c +++ b/src/wayland/meta-wayland-pointer.c @@ -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; diff --git a/src/wayland/meta-wayland-shell-surface.c b/src/wayland/meta-wayland-shell-surface.c index 3ebfdd284..32b4d981c 100644 --- a/src/wayland/meta-wayland-shell-surface.c +++ b/src/wayland/meta-wayland-shell-surface.c @@ -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); diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c index 3b813a191..8724da39f 100644 --- a/src/wayland/meta-wayland-subsurface.c +++ b/src/wayland/meta-wayland-subsurface.c @@ -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 = { diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 787265f33..9a1b45ece 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -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), diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index e244a3fdf..9b225fc6f 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -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; diff --git a/src/wayland/meta-wayland-tablet-tool.c b/src/wayland/meta-wayland-tablet-tool.c index cce93030b..fd491fa50 100644 --- a/src/wayland/meta-wayland-tablet-tool.c +++ b/src/wayland/meta-wayland-tablet-tool.c @@ -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;