mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 09:30:45 -05:00
wayland: Rework synchronized state application semantics
When a parent of a subsurface gets it state applied (either by a wl_surface.commit, wl_subsurface.set_desync or a recursive wl_surface.commit on a parent surface), the pending position state of the subsurface should be applied. If the subsurface is in effective synchronized mode (i.e. if its in explicit synchronized mode or any of its parent surfaces is a subsurface in explicit synchronized mode), the cached state should also be applied at this point, including its subsurface children, recursively. https://bugzilla.gnome.org/show_bug.cgi?id=743617
This commit is contained in:
parent
4aa74af694
commit
868e1427a8
@ -361,33 +361,95 @@ subsurface_surface_commit (MetaWaylandSurface *surface,
|
|||||||
clutter_actor_set_position (CLUTTER_ACTOR (surface_actor), x, y);
|
clutter_actor_set_position (CLUTTER_ACTOR (surface_actor), x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
/* A non-subsurface is always desynchronized.
|
||||||
subsurface_parent_surface_committed (MetaWaylandSurface *surface);
|
*
|
||||||
|
* A subsurface is effectively synchronized if either its parent is
|
||||||
static void
|
* synchronized or itself is in synchronized mode. */
|
||||||
parent_surface_committed (gpointer data, gpointer user_data)
|
static gboolean
|
||||||
|
is_surface_effectively_synchronized (MetaWaylandSurface *surface)
|
||||||
{
|
{
|
||||||
subsurface_parent_surface_committed (data);
|
if (surface->wl_subsurface == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (surface->sub.synchronous)
|
||||||
|
return TRUE;
|
||||||
|
else
|
||||||
|
return is_surface_effectively_synchronized (surface->sub.parent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
commit_pending_state (MetaWaylandSurface *surface,
|
apply_pending_state (MetaWaylandSurface *surface,
|
||||||
MetaWaylandPendingState *pending)
|
MetaWaylandPendingState *pending);
|
||||||
|
|
||||||
|
static void
|
||||||
|
parent_surface_state_applied (gpointer data, gpointer user_data)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *surface = data;
|
||||||
|
|
||||||
|
if (surface->sub.pending_pos)
|
||||||
|
{
|
||||||
|
clutter_actor_set_position (CLUTTER_ACTOR (surface->surface_actor),
|
||||||
|
surface->sub.pending_x,
|
||||||
|
surface->sub.pending_y);
|
||||||
|
surface->sub.pending_pos = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (surface->sub.pending_placement_ops)
|
||||||
|
{
|
||||||
|
GSList *it;
|
||||||
|
for (it = surface->sub.pending_placement_ops; it; it = it->next)
|
||||||
|
{
|
||||||
|
MetaWaylandSubsurfacePlacementOp *op = it->data;
|
||||||
|
ClutterActor *surface_actor;
|
||||||
|
ClutterActor *parent_actor;
|
||||||
|
ClutterActor *sibling_actor;
|
||||||
|
|
||||||
|
if (!op->sibling)
|
||||||
|
{
|
||||||
|
g_slice_free (MetaWaylandSubsurfacePlacementOp, op);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
surface_actor = CLUTTER_ACTOR (surface->surface_actor);
|
||||||
|
parent_actor = clutter_actor_get_parent (CLUTTER_ACTOR (surface->sub.parent));
|
||||||
|
sibling_actor = CLUTTER_ACTOR (op->sibling->surface_actor);
|
||||||
|
|
||||||
|
switch (op->placement)
|
||||||
|
{
|
||||||
|
case META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE:
|
||||||
|
clutter_actor_set_child_above_sibling (parent_actor,
|
||||||
|
surface_actor,
|
||||||
|
sibling_actor);
|
||||||
|
break;
|
||||||
|
case META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW:
|
||||||
|
clutter_actor_set_child_below_sibling (parent_actor,
|
||||||
|
surface_actor,
|
||||||
|
sibling_actor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_list_remove (&op->sibling_destroy_listener.link);
|
||||||
|
g_slice_free (MetaWaylandSubsurfacePlacementOp, op);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_slist_free (surface->sub.pending_placement_ops);
|
||||||
|
surface->sub.pending_placement_ops = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_surface_effectively_synchronized (surface))
|
||||||
|
apply_pending_state (surface, &surface->sub.pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
apply_pending_state (MetaWaylandSurface *surface,
|
||||||
|
MetaWaylandPendingState *pending)
|
||||||
{
|
{
|
||||||
MetaWaylandCompositor *compositor = surface->compositor;
|
MetaWaylandCompositor *compositor = surface->compositor;
|
||||||
|
|
||||||
/* If this surface is a subsurface in in synchronous mode, commit
|
|
||||||
* has a special-case and should not apply the pending state immediately.
|
|
||||||
*
|
|
||||||
* Instead, we move it to another pending state, which will be
|
|
||||||
* actually committed when the parent commits.
|
|
||||||
*/
|
|
||||||
if (surface->sub.synchronous)
|
|
||||||
{
|
|
||||||
move_pending_state (pending, &surface->sub.pending);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pending->newly_attached)
|
if (pending->newly_attached)
|
||||||
{
|
{
|
||||||
surface_set_buffer (surface, pending->buffer);
|
surface_set_buffer (surface, pending->buffer);
|
||||||
@ -438,15 +500,26 @@ commit_pending_state (MetaWaylandSurface *surface,
|
|||||||
else if (surface->wl_subsurface)
|
else if (surface->wl_subsurface)
|
||||||
subsurface_surface_commit (surface, pending);
|
subsurface_surface_commit (surface, pending);
|
||||||
|
|
||||||
g_list_foreach (surface->subsurfaces, parent_surface_committed, NULL);
|
|
||||||
|
|
||||||
pending_state_reset (pending);
|
pending_state_reset (pending);
|
||||||
|
|
||||||
|
g_list_foreach (surface->subsurfaces, parent_surface_state_applied, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
meta_wayland_surface_commit (MetaWaylandSurface *surface)
|
meta_wayland_surface_commit (MetaWaylandSurface *surface)
|
||||||
{
|
{
|
||||||
commit_pending_state (surface, &surface->pending);
|
/*
|
||||||
|
* If this is a sub-surface and it is in effective synchronous mode, only
|
||||||
|
* cache the pending surface state until either one of the following two
|
||||||
|
* scenarios happens:
|
||||||
|
* 1) Its parent surface gets its state applied.
|
||||||
|
* 2) Its mode changes from synchronized to desynchronized and its parent
|
||||||
|
* surface is in effective desynchronized mode.
|
||||||
|
*/
|
||||||
|
if (is_surface_effectively_synchronized (surface))
|
||||||
|
move_pending_state (&surface->pending, &surface->sub.pending);
|
||||||
|
else
|
||||||
|
apply_pending_state (surface, &surface->pending);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1554,59 +1627,6 @@ bind_gtk_shell (struct wl_client *client,
|
|||||||
gtk_shell_send_capabilities (resource, capabilities);
|
gtk_shell_send_capabilities (resource, capabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
subsurface_parent_surface_committed (MetaWaylandSurface *surface)
|
|
||||||
{
|
|
||||||
if (surface->sub.pending_pos)
|
|
||||||
{
|
|
||||||
clutter_actor_set_position (CLUTTER_ACTOR (surface->surface_actor),
|
|
||||||
surface->sub.pending_x,
|
|
||||||
surface->sub.pending_y);
|
|
||||||
surface->sub.pending_pos = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (surface->sub.pending_placement_ops)
|
|
||||||
{
|
|
||||||
GSList *it;
|
|
||||||
for (it = surface->sub.pending_placement_ops; it; it = it->next)
|
|
||||||
{
|
|
||||||
MetaWaylandSubsurfacePlacementOp *op = it->data;
|
|
||||||
ClutterActor *surface_actor;
|
|
||||||
ClutterActor *parent_actor;
|
|
||||||
ClutterActor *sibling_actor;
|
|
||||||
|
|
||||||
if (!op->sibling)
|
|
||||||
{
|
|
||||||
g_slice_free (MetaWaylandSubsurfacePlacementOp, op);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
surface_actor = CLUTTER_ACTOR (surface->surface_actor);
|
|
||||||
parent_actor = clutter_actor_get_parent (CLUTTER_ACTOR (surface->sub.parent));
|
|
||||||
sibling_actor = CLUTTER_ACTOR (op->sibling->surface_actor);
|
|
||||||
|
|
||||||
switch (op->placement)
|
|
||||||
{
|
|
||||||
case META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE:
|
|
||||||
clutter_actor_set_child_above_sibling (parent_actor, surface_actor, sibling_actor);
|
|
||||||
break;
|
|
||||||
case META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW:
|
|
||||||
clutter_actor_set_child_below_sibling (parent_actor, surface_actor, sibling_actor);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
wl_list_remove (&op->sibling_destroy_listener.link);
|
|
||||||
g_slice_free (MetaWaylandSubsurfacePlacementOp, op);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_slist_free (surface->sub.pending_placement_ops);
|
|
||||||
surface->sub.pending_placement_ops = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (surface->sub.synchronous)
|
|
||||||
commit_pending_state (surface, &surface->sub.pending);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
unparent_actor (MetaWaylandSurface *surface)
|
unparent_actor (MetaWaylandSurface *surface)
|
||||||
{
|
{
|
||||||
@ -1751,11 +1771,13 @@ wl_subsurface_set_desync (struct wl_client *client,
|
|||||||
struct wl_resource *resource)
|
struct wl_resource *resource)
|
||||||
{
|
{
|
||||||
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
||||||
|
gboolean was_effectively_synchronized;
|
||||||
|
|
||||||
if (surface->sub.synchronous)
|
was_effectively_synchronized = is_surface_effectively_synchronized (surface);
|
||||||
subsurface_parent_surface_committed (surface);
|
|
||||||
|
|
||||||
surface->sub.synchronous = FALSE;
|
surface->sub.synchronous = FALSE;
|
||||||
|
if (was_effectively_synchronized &&
|
||||||
|
!is_surface_effectively_synchronized (surface))
|
||||||
|
apply_pending_state (surface, &surface->sub.pending);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_subsurface_interface meta_wayland_wl_subsurface_interface = {
|
static const struct wl_subsurface_interface meta_wayland_wl_subsurface_interface = {
|
||||||
|
Loading…
Reference in New Issue
Block a user