diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c index 6a50b3299..ba86d6206 100644 --- a/src/wayland/meta-wayland-subsurface.c +++ b/src/wayland/meta-wayland-subsurface.c @@ -28,6 +28,7 @@ #include "wayland/meta-wayland-actor-surface.h" #include "wayland/meta-wayland-buffer.h" #include "wayland/meta-wayland-surface.h" +#include "wayland/meta-wayland-transaction.h" #include "wayland/meta-window-wayland.h" struct _MetaWaylandSubsurface @@ -105,28 +106,6 @@ is_sibling (MetaWaylandSurface *surface, return surface != sibling && surface->sub.parent == sibling->sub.parent; } -void -meta_wayland_subsurface_parent_state_applied (MetaWaylandSubsurface *subsurface) -{ - MetaWaylandSurfaceRole *surface_role = META_WAYLAND_SURFACE_ROLE (subsurface); - MetaWaylandActorSurface *actor_surface = - META_WAYLAND_ACTOR_SURFACE (subsurface); - MetaWaylandSurface *surface = - meta_wayland_surface_role_get_surface (surface_role); - - if (surface->sub.pending_pos) - { - surface->sub.x = surface->sub.pending_x; - surface->sub.y = surface->sub.pending_y; - surface->sub.pending_pos = FALSE; - } - - if (meta_wayland_surface_is_synchronized (surface)) - meta_wayland_surface_apply_cached_state (surface); - - meta_wayland_actor_surface_sync_actor_state (actor_surface); -} - void meta_wayland_subsurface_union_geometry (MetaWaylandSubsurface *subsurface, int parent_x, @@ -452,7 +431,13 @@ wl_subsurface_set_desync (struct wl_client *client, meta_wayland_surface_is_synchronized (surface->sub.parent); if (!is_parent_effectively_synchronized) - meta_wayland_surface_apply_cached_state (surface); + { + MetaWaylandTransaction *transaction; + + transaction = meta_wayland_transaction_new (surface->compositor); + meta_wayland_transaction_add_cached_states (transaction, surface); + meta_wayland_transaction_commit (transaction); + } surface->sub.synchronous = FALSE; } diff --git a/src/wayland/meta-wayland-subsurface.h b/src/wayland/meta-wayland-subsurface.h index 45dbf8626..5fa2999db 100644 --- a/src/wayland/meta-wayland-subsurface.h +++ b/src/wayland/meta-wayland-subsurface.h @@ -44,8 +44,6 @@ typedef struct struct wl_listener sibling_destroy_listener; } MetaWaylandSubsurfacePlacementOp; -void meta_wayland_subsurface_parent_state_applied (MetaWaylandSubsurface *subsurface); - void meta_wayland_subsurface_union_geometry (MetaWaylandSubsurface *subsurface, int parent_x, int parent_y, diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index adc8ba836..852bbed99 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -48,6 +48,7 @@ #include "wayland/meta-wayland-region.h" #include "wayland/meta-wayland-seat.h" #include "wayland/meta-wayland-subsurface.h" +#include "wayland/meta-wayland-transaction.h" #include "wayland/meta-wayland-viewporter.h" #include "wayland/meta-wayland-xdg-shell.h" #include "wayland/meta-window-wayland.h" @@ -717,7 +718,6 @@ void meta_wayland_surface_apply_state (MetaWaylandSurface *surface, MetaWaylandSurfaceState *state) { - MetaWaylandSurface *subsurface_surface; gboolean had_damage = FALSE; int old_width, old_height; @@ -956,14 +956,6 @@ cleanup: surface_state_signals[SURFACE_STATE_SIGNAL_APPLIED], 0); - META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface) - { - MetaWaylandSubsurface *subsurface; - - subsurface = META_WAYLAND_SUBSURFACE (subsurface_surface->role); - meta_wayland_subsurface_parent_state_applied (subsurface); - } - if (had_damage) { MetaWindow *toplevel_window; @@ -984,22 +976,6 @@ cleanup: meta_wayland_surface_role_post_apply_state (surface->role, state); } -static void -ensure_cached_state (MetaWaylandSurface *surface) -{ - if (!surface->cached_state) - surface->cached_state = g_object_new (META_TYPE_WAYLAND_SURFACE_STATE, - NULL); -} - -void -meta_wayland_surface_apply_cached_state (MetaWaylandSurface *surface) -{ - ensure_cached_state (surface); - meta_wayland_surface_apply_state (surface, surface->cached_state); - meta_wayland_surface_state_reset (surface->cached_state); -} - MetaWaylandSurfaceState * meta_wayland_surface_get_pending_state (MetaWaylandSurface *surface) { @@ -1028,16 +1004,30 @@ meta_wayland_surface_commit (MetaWaylandSurface *surface) */ if (meta_wayland_surface_is_synchronized (surface)) { - ensure_cached_state (surface); - - meta_wayland_surface_state_merge_into (pending, surface->cached_state); + if (surface->cached_state) + { + meta_wayland_surface_state_merge_into (pending, surface->cached_state); + meta_wayland_surface_state_reset (pending); + } + else + { + surface->cached_state = pending; + surface->pending_state = meta_wayland_surface_state_new (); + } } else { - meta_wayland_surface_apply_state (surface, surface->pending_state); - } + MetaWaylandTransaction *transaction; - meta_wayland_surface_state_reset (pending); + transaction = meta_wayland_transaction_new (surface->compositor); + meta_wayland_transaction_add_state (transaction, surface, pending); + if (surface->sub.pending_pos) + meta_wayland_transaction_add_subsurface_position (transaction, surface); + meta_wayland_transaction_add_cached_child_states (transaction, surface); + meta_wayland_transaction_commit (transaction); + + surface->pending_state = meta_wayland_surface_state_new (); + } } static void @@ -1745,7 +1735,7 @@ meta_wayland_surface_get_absolute_coordinates (MetaWaylandSurface *surface, static void meta_wayland_surface_init (MetaWaylandSurface *surface) { - surface->pending_state = g_object_new (META_TYPE_WAYLAND_SURFACE_STATE, NULL); + surface->pending_state = meta_wayland_surface_state_new (); surface->buffer_ref = meta_wayland_buffer_ref_new (); diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index 56bcbb189..ddd86ec1a 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -276,7 +276,8 @@ void meta_wayland_surface_apply_state (MetaWaylandSurface *s MetaWaylandSurfaceState * meta_wayland_surface_get_pending_state (MetaWaylandSurface *surface); -void meta_wayland_surface_apply_cached_state (MetaWaylandSurface *surface); +MetaWaylandSurfaceState * + meta_wayland_surface_ensure_cached_state (MetaWaylandSurface *surface); gboolean meta_wayland_surface_assign_role (MetaWaylandSurface *surface, GType role_type, @@ -386,6 +387,12 @@ meta_wayland_surface_can_scanout_untransformed (MetaWaylandSurface *surface, int meta_wayland_surface_get_geometry_scale (MetaWaylandSurface *surface); +static inline MetaWaylandSurfaceState * +meta_wayland_surface_state_new (void) +{ + return g_object_new (META_TYPE_WAYLAND_SURFACE_STATE, NULL); +} + static inline GNode * meta_get_next_subsurface_sibling (GNode *n) { diff --git a/src/wayland/meta-wayland-transaction.c b/src/wayland/meta-wayland-transaction.c index 96a0b18bc..bfcf42580 100644 --- a/src/wayland/meta-wayland-transaction.c +++ b/src/wayland/meta-wayland-transaction.c @@ -41,6 +41,11 @@ struct _MetaWaylandTransaction typedef struct _MetaWaylandTransactionEntry { MetaWaylandSurfaceState *state; + + /* Sub-surface position */ + gboolean has_sub_pos; + int x; + int y; } MetaWaylandTransactionEntry; static MetaWaylandTransactionEntry * @@ -66,6 +71,17 @@ meta_wayland_transaction_sync_child_states (MetaWaylandSurface *surface) } } +static void +meta_wayland_transaction_apply_subsurface_position (MetaWaylandSurface *surface, + MetaWaylandTransactionEntry *entry) +{ + if (!entry->has_sub_pos) + return; + + surface->sub.x = entry->x; + surface->sub.y = entry->y; +} + static gboolean is_ancestor (MetaWaylandSurface *candidate, MetaWaylandSurface *reference) @@ -149,11 +165,13 @@ meta_wayland_transaction_apply (MetaWaylandTransaction *transaction, MetaWaylandTransaction **first_candidate) { g_autofree MetaWaylandSurface **surfaces = NULL; + g_autofree MetaWaylandSurfaceState **states = NULL; unsigned int num_surfaces; int i; surfaces = (MetaWaylandSurface **) g_hash_table_get_keys_as_array (transaction->entries, &num_surfaces); + states = g_new (MetaWaylandSurfaceState *, num_surfaces); /* Sort surfaces from ancestors to descendants */ qsort (surfaces, num_surfaces, sizeof (MetaWaylandSurface *), @@ -166,7 +184,10 @@ meta_wayland_transaction_apply (MetaWaylandTransaction *transaction, MetaWaylandTransactionEntry *entry; entry = meta_wayland_transaction_get_entry (transaction, surface); - meta_wayland_surface_apply_state (surface, entry->state); + states[i] = entry->state; + meta_wayland_transaction_apply_subsurface_position (surface, entry); + if (entry->state) + meta_wayland_surface_apply_state (surface, entry->state); if (surface->transaction.last_committed == transaction) { @@ -188,7 +209,10 @@ meta_wayland_transaction_apply (MetaWaylandTransaction *transaction, /* Synchronize child states from descendants to ancestors */ for (i = num_surfaces - 1; i >= 0; i--) - meta_wayland_transaction_sync_child_states (surfaces[i]); + { + if (states[i]) + meta_wayland_transaction_sync_child_states (surfaces[i]); + } meta_wayland_transaction_free (transaction); } @@ -296,6 +320,58 @@ meta_wayland_transaction_add_state (MetaWaylandTransaction *transaction, entry->state = state; } +void +meta_wayland_transaction_add_subsurface_position (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface) +{ + MetaWaylandTransactionEntry *entry; + + entry = meta_wayland_transaction_ensure_entry (transaction, surface); + entry->x = surface->sub.pending_x; + entry->y = surface->sub.pending_y; + entry->has_sub_pos = TRUE; + surface->sub.pending_pos = FALSE; +} + +static gboolean +meta_wayland_transaction_add_cached_state (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface) +{ + MetaWaylandSurfaceState *cached = surface->cached_state; + gboolean is_synchronized; + + is_synchronized = meta_wayland_surface_is_synchronized (surface); + + if (is_synchronized && cached) + { + meta_wayland_transaction_add_state (transaction, surface, cached); + surface->cached_state = NULL; + } + + if (surface->sub.pending_pos) + meta_wayland_transaction_add_subsurface_position (transaction, surface); + + return is_synchronized; +} + +void +meta_wayland_transaction_add_cached_child_states (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface) +{ + MetaWaylandSurface *subsurface_surface; + + META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface) + meta_wayland_transaction_add_cached_states (transaction, subsurface_surface); +} + +void +meta_wayland_transaction_add_cached_states (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface) +{ + if (meta_wayland_transaction_add_cached_state (transaction, surface)) + meta_wayland_transaction_add_cached_child_states (transaction, surface); +} + static void meta_wayland_transaction_entry_free (MetaWaylandTransactionEntry *entry) { diff --git a/src/wayland/meta-wayland-transaction.h b/src/wayland/meta-wayland-transaction.h index 230548c19..d79f8d94c 100644 --- a/src/wayland/meta-wayland-transaction.h +++ b/src/wayland/meta-wayland-transaction.h @@ -28,6 +28,15 @@ void meta_wayland_transaction_add_state (MetaWaylandTransaction *transaction, MetaWaylandSurface *surface, MetaWaylandSurfaceState *state); +void meta_wayland_transaction_add_subsurface_position (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface); + +void meta_wayland_transaction_add_cached_states (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface); + +void meta_wayland_transaction_add_cached_child_states (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface); + MetaWaylandTransaction *meta_wayland_transaction_new (MetaWaylandCompositor *compositor); void meta_wayland_transaction_free (MetaWaylandTransaction *transaction);