wayland: Make wl_subsurface.place_(above|below) properly synchronized

The placement set by either wl_subsurface.place_above or
wl_subsurface.place_below should be applied when the parent surface
invokes wl_surface.commit.

Signed-off-by: Jonas Ådahl <jadahl@gmail.com>

https://bugzilla.gnome.org/show_bug.cgi?id=705502
This commit is contained in:
Jonas Ådahl 2014-01-12 23:24:00 +01:00 committed by Jasper St. Pierre
parent 16de7f66fb
commit 9348c9bd4b
2 changed files with 86 additions and 12 deletions

View File

@ -58,6 +58,19 @@
#include "meta-idle-monitor-private.h" #include "meta-idle-monitor-private.h"
#include "monitor-private.h" #include "monitor-private.h"
typedef enum
{
META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE,
META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW
} MetaWaylandSubsurfacePlacement;
typedef struct
{
MetaWaylandSubsurfacePlacement placement;
MetaWaylandSurface *sibling;
struct wl_listener sibling_destroy_listener;
} MetaWaylandSubsurfacePlacementOp;
static void static void
surface_process_damage (MetaWaylandSurface *surface, surface_process_damage (MetaWaylandSurface *surface,
cairo_region_t *region) cairo_region_t *region)
@ -1012,6 +1025,44 @@ wl_subsurface_parent_surface_committed (gpointer data, gpointer user_data)
surface->sub.pending_y); surface->sub.pending_y);
surface->sub.pending_pos = FALSE; 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;
}
} }
static void static void
@ -1062,12 +1113,39 @@ is_valid_sibling (MetaWaylandSurface *surface, MetaWaylandSurface *sibling)
return FALSE; return FALSE;
} }
static void
subsurface_handle_pending_sibling_destroyed (struct wl_listener *listener, void *data)
{
MetaWaylandSubsurfacePlacementOp *op =
wl_container_of (listener, op, sibling_destroy_listener);
op->sibling = NULL;
}
static void
queue_subsurface_placement (MetaWaylandSurface *surface,
MetaWaylandSurface *sibling,
MetaWaylandSubsurfacePlacement placement)
{
MetaWaylandSubsurfacePlacementOp *op =
g_slice_new (MetaWaylandSubsurfacePlacementOp);
op->placement = placement;
op->sibling = sibling;
op->sibling_destroy_listener.notify =
subsurface_handle_pending_sibling_destroyed;
wl_resource_add_destroy_listener (sibling->resource,
&op->sibling_destroy_listener);
surface->sub.pending_placement_ops =
g_slist_append (surface->sub.pending_placement_ops, op);
}
static void static void
wl_subsurface_place_above (struct wl_client *client, wl_subsurface_place_above (struct wl_client *client,
struct wl_resource *resource, struct wl_resource *resource,
struct wl_resource *sibling_resource) struct wl_resource *sibling_resource)
{ {
ClutterActor *parent_actor;
MetaWaylandSurfaceExtension *subsurface = wl_resource_get_user_data (resource); MetaWaylandSurfaceExtension *subsurface = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface = wl_container_of (subsurface, surface, subsurface); MetaWaylandSurface *surface = wl_container_of (subsurface, surface, subsurface);
MetaWaylandSurface *sibling = wl_resource_get_user_data (sibling_resource); MetaWaylandSurface *sibling = wl_resource_get_user_data (sibling_resource);
@ -1081,11 +1159,9 @@ wl_subsurface_place_above (struct wl_client *client,
return; return;
} }
parent_actor = clutter_actor_get_parent (CLUTTER_ACTOR (surface->surface_actor)); queue_subsurface_placement (surface,
sibling,
clutter_actor_set_child_above_sibling (parent_actor, META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE);
CLUTTER_ACTOR (surface->surface_actor),
CLUTTER_ACTOR (sibling->surface_actor));
} }
static void static void
@ -1093,7 +1169,6 @@ wl_subsurface_place_below (struct wl_client *client,
struct wl_resource *resource, struct wl_resource *resource,
struct wl_resource *sibling_resource) struct wl_resource *sibling_resource)
{ {
ClutterActor *parent_actor;
MetaWaylandSurfaceExtension *subsurface = wl_resource_get_user_data (resource); MetaWaylandSurfaceExtension *subsurface = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface = wl_container_of (subsurface, surface, subsurface); MetaWaylandSurface *surface = wl_container_of (subsurface, surface, subsurface);
MetaWaylandSurface *sibling = wl_resource_get_user_data (sibling_resource); MetaWaylandSurface *sibling = wl_resource_get_user_data (sibling_resource);
@ -1107,11 +1182,9 @@ wl_subsurface_place_below (struct wl_client *client,
return; return;
} }
parent_actor = clutter_actor_get_parent (CLUTTER_ACTOR (surface->surface_actor)); queue_subsurface_placement (surface,
sibling,
clutter_actor_set_child_below_sibling (parent_actor, META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW);
CLUTTER_ACTOR (surface->surface_actor),
CLUTTER_ACTOR (sibling->surface_actor));
} }
static void static void

View File

@ -94,6 +94,7 @@ struct _MetaWaylandSurface
int32_t pending_x; int32_t pending_x;
int32_t pending_y; int32_t pending_y;
gboolean pending_pos; gboolean pending_pos;
GSList *pending_placement_ops;
} sub; } sub;
/* All the pending state, that wl_surface.commit will apply. */ /* All the pending state, that wl_surface.commit will apply. */