[RFC Weston 02/10] compositor: introduce sub-surfaces

Pekka Paalanen ppaalanen at gmail.com
Fri Feb 22 07:07:46 PST 2013


This commit depends on the Wayland commit "protocol: add sub-surfaces".

Implement the basic protocol for sub-surfaces:
- expose wl_subcompositor global interface
- error checking on protocol calls
- associate a parent wl_surface to a sub-surface
- introduce the sub-surface role, which is exclusive
- a rudimentary implementation of the wl_subsurface interface
- proper surface transformation inheritance from parent to sub-surfaces
- two different modes of wl_surface.commit for sub-surfaces

Struct weston_subsurface is dynamically allocated. For sub-surfaces, it
is completely populated.

For parent surfaces, weston_subsurface acts only as a link for stacking
order purposes. The wl_resource is unused, parent_destroy_listener is
not registered, the transform is not linked, etc.

Sub-surfaces are not added directly into layers for display or input.
Instead, a following patch will hook them up via the sub-surface list
present in parent weston_surfaces. This way sub-surfaces are inherently
linked to the parent surface, and cannot be displayed unless the parent
is mapped, too. This also eases restacking, as only the parent will be
in a layer list.

Features still lacking are:
- double-buffering sub-surface z-order changes

Changes in v2:
- fix a bug in surface mapping: commit a sub-surface would cause the
  main surface to never be mapped.
- remove debug printfs
- detect attempt of making a surface its own parent
- always zero-alloc weston_subsurface
- apply wl_subsurface.set_position in commit, not immediately
- add weston_surface_to_subsurface()
- implement sub-surface commit modes parent-cached and independent
- implement wl_subcompositor.destroy and wl_subsurface.destroy

Signed-off-by: Pekka Paalanen <ppaalanen at gmail.com>
---
 src/compositor.c | 619 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/compositor.h |  55 +++++
 2 files changed, 672 insertions(+), 2 deletions(-)

diff --git a/src/compositor.c b/src/compositor.c
index ccabb95..9c14423 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -262,6 +262,9 @@ region_init_infinite(pixman_region32_t *region)
 				  UINT32_MAX, UINT32_MAX);
 }
 
+static struct weston_subsurface *
+weston_surface_to_subsurface(struct weston_surface *surface);
+
 WL_EXPORT struct weston_surface *
 weston_surface_create(struct weston_compositor *compositor)
 {
@@ -316,6 +319,8 @@ weston_surface_create(struct weston_compositor *compositor)
 	region_init_infinite(&surface->pending.input);
 	wl_list_init(&surface->pending.frame_callback_list);
 
+	wl_list_init(&surface->subsurface_list);
+
 	return surface;
 }
 
@@ -951,6 +956,8 @@ destroy_surface(struct wl_resource *resource)
 	struct weston_compositor *compositor = surface->compositor;
 	struct weston_frame_callback *cb, *next;
 
+	assert(wl_list_empty(&surface->subsurface_list));
+
 	if (weston_surface_is_mapped(surface))
 		weston_surface_unmap(surface);
 
@@ -1421,9 +1428,8 @@ weston_surface_has_different_size(struct weston_surface *surface,
 }
 
 static void
-surface_commit(struct wl_client *client, struct wl_resource *resource)
+weston_surface_commit(struct weston_surface *surface)
 {
-	struct weston_surface *surface = resource->data;
 	pixman_region32_t opaque;
 
 	if (surface->pending.sx || surface->pending.sy ||
@@ -1484,6 +1490,31 @@ surface_commit(struct wl_client *client, struct wl_resource *resource)
 }
 
 static void
+weston_subsurface_commit(struct weston_subsurface *sub);
+
+static void
+weston_subsurface_parent_commit(struct weston_subsurface *sub);
+
+static void
+surface_commit(struct wl_client *client, struct wl_resource *resource)
+{
+	struct weston_surface *surface = resource->data;
+	struct weston_subsurface *sub = weston_surface_to_subsurface(surface);
+
+	if (sub) {
+		weston_subsurface_commit(sub);
+		return;
+	}
+
+	weston_surface_commit(surface);
+
+	wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
+		if (sub->surface != surface)
+			weston_subsurface_parent_commit(sub);
+	}
+}
+
+static void
 surface_set_buffer_transform(struct wl_client *client,
 			     struct wl_resource *resource, int transform)
 {
@@ -1602,6 +1633,586 @@ static const struct wl_compositor_interface compositor_interface = {
 };
 
 static void
+weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
+{
+	struct weston_surface *surface = sub->surface;
+	pixman_region32_t opaque;
+
+	if (sub->cached.sx || sub->cached.sy ||
+	    weston_surface_has_different_size(surface,
+	    				      sub->cached.buffer_ref.buffer,
+					      sub->cached.buffer_transform))
+		weston_surface_geometry_dirty(surface);
+
+	/* wl_surface.set_buffer_rotation */
+	surface->buffer_transform = sub->cached.buffer_transform;
+
+	/* wl_surface.attach */
+	if (sub->cached.buffer_ref.buffer || sub->cached.remove_contents)
+		weston_surface_attach(surface, sub->cached.buffer_ref.buffer);
+
+	if (surface->buffer_ref.buffer && surface->configure)
+		surface->configure(surface, sub->cached.sx, sub->cached.sy);
+	sub->cached.sx = 0;
+	sub->cached.sy = 0;
+
+	/* wl_surface.damage */
+	pixman_region32_union(&surface->damage, &surface->damage,
+			      &sub->cached.damage);
+	pixman_region32_intersect_rect(&surface->damage, &surface->damage,
+				       0, 0,
+				       surface->geometry.width,
+				       surface->geometry.height);
+	empty_region(&sub->cached.damage);
+
+	/* wl_surface.set_opaque_region */
+	pixman_region32_init_rect(&opaque, 0, 0,
+				  surface->geometry.width,
+				  surface->geometry.height);
+	pixman_region32_intersect(&opaque,
+				  &opaque, &sub->cached.opaque);
+
+	if (!pixman_region32_equal(&opaque, &surface->opaque)) {
+		pixman_region32_copy(&surface->opaque, &opaque);
+		weston_surface_geometry_dirty(surface);
+	}
+
+	pixman_region32_fini(&opaque);
+
+	/* wl_surface.set_input_region */
+	pixman_region32_fini(&surface->input);
+	pixman_region32_init_rect(&surface->input, 0, 0,
+				  surface->geometry.width,
+				  surface->geometry.height);
+	pixman_region32_intersect(&surface->input,
+				  &surface->input, &sub->cached.input);
+
+	/* wl_surface.frame */
+	wl_list_insert_list(&surface->frame_callback_list,
+			    &sub->cached.frame_callback_list);
+	wl_list_init(&sub->cached.frame_callback_list);
+
+	weston_surface_schedule_repaint(surface);
+
+	sub->cached.has_data = 0;
+}
+
+static void
+weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
+{
+	struct weston_surface *surface = sub->surface;
+
+	/*
+	 * If this commit would cause the surface to move by the
+	 * attach(dx, dy) parameters, the old damage region must be
+	 * translated to correspond to the new surface coordinate system
+	 * origin.
+	 */
+	pixman_region32_translate(&sub->cached.damage,
+				  -surface->pending.sx, -surface->pending.sy);
+	pixman_region32_union(&sub->cached.damage, &sub->cached.damage,
+			      &surface->pending.damage);
+	empty_region(&surface->pending.damage);
+
+	if (surface->pending.buffer || surface->pending.remove_contents) {
+		sub->cached.remove_contents = surface->pending.remove_contents;
+		weston_buffer_reference(&sub->cached.buffer_ref,
+					surface->pending.buffer);
+	}
+	sub->cached.sx += surface->pending.sx;
+	sub->cached.sy += surface->pending.sy;
+	surface->pending.sx = 0;
+	surface->pending.sy = 0;
+
+	sub->cached.buffer_transform = surface->pending.buffer_transform;
+
+	pixman_region32_copy(&sub->cached.opaque, &surface->pending.opaque);
+
+	pixman_region32_copy(&sub->cached.input, &surface->pending.input);
+
+	wl_list_insert_list(&sub->cached.frame_callback_list,
+			    &surface->pending.frame_callback_list);
+	wl_list_init(&surface->pending.frame_callback_list);
+
+	sub->cached.has_data = 1;
+}
+
+static void
+weston_subsurface_commit(struct weston_subsurface *sub)
+{
+	switch (sub->commit_mode) {
+	case WL_SUBSURFACE_COMMIT_MODE_PARENT_CACHED:
+		weston_subsurface_commit_to_cache(sub);
+		break;
+	case WL_SUBSURFACE_COMMIT_MODE_INDEPENDENT:
+		if (sub->cached.has_data) {
+			/* flush accumulated state from cache */
+			weston_subsurface_commit_to_cache(sub);
+			weston_subsurface_commit_from_cache(sub);
+		} else {
+			weston_surface_commit(sub->surface);
+		}
+		break;
+	default:
+		assert(!"bad weston_subsurface::commit_mode");
+	}
+}
+
+static void
+weston_subsurface_parent_commit(struct weston_subsurface *sub)
+{
+	switch (sub->commit_mode) {
+	case WL_SUBSURFACE_COMMIT_MODE_PARENT_CACHED:
+		weston_subsurface_commit_from_cache(sub);
+		break;
+	case WL_SUBSURFACE_COMMIT_MODE_INDEPENDENT:
+		/* no-op */
+		break;
+	default:
+		assert(!"bad weston_subsurface::commit_mode");
+	}
+
+	if (sub->position.set) {
+		weston_surface_set_position(sub->surface,
+					    sub->position.x, sub->position.y);
+		sub->position.set = 0;
+	}
+}
+
+static void
+subsurface_configure(struct weston_surface *surface, int32_t dx, int32_t dy)
+{
+	struct weston_compositor *compositor = surface->compositor;
+
+	weston_surface_configure(surface,
+				 surface->geometry.x + dx,
+				 surface->geometry.y + dy,
+				 weston_surface_buffer_width(surface),
+				 weston_surface_buffer_height(surface));
+
+	/* No need to check parent mappedness, because if parent is not
+	 * mapped, parent is not in a visible layer, so this sub-surface
+	 * will not be drawn either.
+	 */
+	if (!weston_surface_is_mapped(surface)) {
+		wl_list_init(&surface->layer_link);
+
+		/* Cannot call weston_surface_update_transform(),
+		 * because that would call it also for the parent surface,
+		 * which might not be mapped yet. That would lead to
+		 * inconsistent state, where the window could never be
+		 * mapped.
+		 *
+		 * Instead just assing any output, to make
+		 * weston_surface_is_mapped() return true, so that when the
+		 * parent surface does get mapped, this one will get
+		 * included, too. See surface_list_add().
+		 */
+		assert(!wl_list_empty(&compositor->output_list));
+		surface->output = container_of(compositor->output_list.next,
+					       struct weston_output, link);
+	}
+}
+
+static struct weston_subsurface *
+weston_surface_to_subsurface(struct weston_surface *surface)
+{
+	if (surface->configure == subsurface_configure)
+		return surface->private;
+
+	return NULL;
+}
+
+static void
+subsurface_set_position(struct wl_client *client,
+			struct wl_resource *resource, int32_t x, int32_t y)
+{
+	struct weston_subsurface *sub = resource->data;
+
+	sub->position.x = x;
+	sub->position.y = y;
+	sub->position.set = 1;
+}
+
+static struct weston_subsurface *
+subsurface_from_surface(struct weston_surface *surface)
+{
+	struct weston_subsurface *sub;
+
+	sub = weston_surface_to_subsurface(surface);
+	if (sub)
+		return sub;
+
+	wl_list_for_each(sub, &surface->subsurface_list, parent_link)
+		if (sub->surface == surface)
+			return sub;
+
+	return NULL;
+}
+
+static struct weston_subsurface *
+subsurface_sibling_check(struct weston_subsurface *sub,
+			 struct weston_surface *surface,
+			 const char *request)
+{
+	struct weston_subsurface *sibling;
+
+	sibling = subsurface_from_surface(surface);
+
+	if (!sibling) {
+		wl_resource_post_error(&sub->resource,
+			WL_SUBSURFACE_ERROR_BAD_SURFACE,
+			"%s: wl_surface@%d is not a parent or sibling",
+			request, surface->surface.resource.object.id);
+		return NULL;
+	}
+
+	if (sibling->parent != sub->parent) {
+		wl_resource_post_error(&sub->resource,
+			WL_SUBSURFACE_ERROR_BAD_SURFACE,
+			"%s: wl_surface@%d has a different parent",
+			request, surface->surface.resource.object.id);
+		return NULL;
+	}
+
+	return sibling;
+}
+
+static void
+subsurface_place_above(struct wl_client *client,
+		       struct wl_resource *resource,
+		       struct wl_resource *sibling_resource)
+{
+	struct weston_subsurface *sub = resource->data;
+	struct weston_surface *surface = sibling_resource->data;
+	struct weston_subsurface *sibling;
+
+	sibling = subsurface_sibling_check(sub, surface, "place_above");
+	if (!sibling)
+		return;
+
+	/* TODO: make the list double-buffered, and apply it on parent commit */
+
+	wl_list_remove(&sub->parent_link);
+	wl_list_insert(sibling->parent_link.prev, &sub->parent_link);
+}
+
+static void
+subsurface_place_below(struct wl_client *client,
+		       struct wl_resource *resource,
+		       struct wl_resource *sibling_resource)
+{
+	struct weston_subsurface *sub = resource->data;
+	struct weston_surface *surface = sibling_resource->data;
+	struct weston_subsurface *sibling;
+
+	sibling = subsurface_sibling_check(sub, surface, "place_below");
+	if (!sibling)
+		return;
+
+	/* TODO: make the list double-buffered, and apply it on parent commit */
+
+	wl_list_remove(&sub->parent_link);
+	wl_list_insert(&sibling->parent_link, &sub->parent_link);
+}
+
+static void
+subsurface_set_commit_mode(struct wl_client *client,
+			   struct wl_resource *resource,
+			   uint32_t mode)
+{
+	struct weston_subsurface *sub = resource->data;
+
+	switch (mode) {
+	case WL_SUBSURFACE_COMMIT_MODE_PARENT_CACHED:
+		sub->commit_mode = WL_SUBSURFACE_COMMIT_MODE_PARENT_CACHED;
+		break;
+	case WL_SUBSURFACE_COMMIT_MODE_INDEPENDENT:
+		sub->commit_mode = WL_SUBSURFACE_COMMIT_MODE_INDEPENDENT;
+		break;
+	default:
+		wl_resource_post_error(resource,
+			WL_SUBSURFACE_ERROR_BAD_VALUE,
+			"wl_subsurface@%d.set_commit_mode: bad mode %u",
+			resource->object.id, mode);
+		return;
+	}
+}
+
+static void
+subsurface_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+	struct weston_subsurface *sub =
+		container_of(listener, struct weston_subsurface,
+			     surface_destroy_listener);
+	assert(data == &sub->surface->surface.resource);
+
+	if (sub->surface != sub->parent)
+		wl_resource_destroy(&sub->resource);
+	else {
+		/* parent does not have a wl_subsurface resource */
+		assert(sub->resource.destroy == NULL);
+		assert(sub->parent_destroy_listener.notify == NULL);
+		wl_list_remove(&sub->parent_link);
+		free(sub);
+	}
+}
+
+static void
+subsurface_handle_parent_destroy(struct wl_listener *listener, void *data)
+{
+	struct weston_subsurface *sub =
+		container_of(listener, struct weston_subsurface,
+			     parent_destroy_listener);
+	assert(data == &sub->parent->surface.resource);
+	assert(sub->surface != sub->parent);
+
+	if (weston_surface_is_mapped(sub->surface))
+		weston_surface_unmap(sub->surface);
+
+	sub->parent = NULL;
+	wl_list_remove(&sub->parent_link);
+	wl_list_remove(&sub->parent_transform.link);
+	wl_list_remove(&sub->parent_dirty_listener.link);
+}
+
+static void
+subsurface_resource_destroy(struct wl_resource *resource)
+{
+	struct weston_subsurface *sub = resource->data;
+	struct weston_frame_callback *cb, *tmp;
+
+	assert(sub);
+	assert(sub->surface);
+	assert(weston_surface_to_subsurface(sub->surface) == sub);
+	assert(sub->parent_destroy_listener.notify ==
+	       subsurface_handle_parent_destroy);
+
+	sub->surface->configure = NULL;
+	sub->surface->private = NULL;
+	wl_list_remove(&sub->surface_destroy_listener.link);
+
+	if (sub->parent) {
+		wl_list_remove(&sub->parent_transform.link);
+		wl_list_remove(&sub->parent_dirty_listener.link);
+		wl_list_remove(&sub->parent_link);
+		wl_list_remove(&sub->parent_destroy_listener.link);
+	}
+
+	wl_list_for_each_safe(cb, tmp, &sub->cached.frame_callback_list, link)
+		wl_resource_destroy(&cb->resource);
+
+	weston_buffer_reference(&sub->cached.buffer_ref, NULL);
+	pixman_region32_fini(&sub->cached.damage);
+	pixman_region32_fini(&sub->cached.opaque);
+	pixman_region32_fini(&sub->cached.input);
+
+	free(sub);
+}
+
+static void
+subsurface_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+}
+
+static void
+subsurface_notify_parent_geometry_dirty(struct wl_listener *listener,
+					void *data)
+{
+	struct weston_subsurface *sub =
+		container_of(listener, struct weston_subsurface,
+			     parent_dirty_listener);
+
+	weston_surface_geometry_dirty(sub->surface);
+}
+
+static void
+weston_subsurface_link(struct weston_subsurface *sub,
+		       struct weston_surface *surface,
+		       struct weston_surface *parent)
+{
+	sub->surface = surface;
+	sub->surface_destroy_listener.notify =
+		subsurface_handle_surface_destroy;
+	wl_signal_add(&surface->surface.resource.destroy_signal,
+		      &sub->surface_destroy_listener);
+
+	sub->parent = parent;
+
+	if (sub->surface != sub->parent) {
+		sub->parent_destroy_listener.notify =
+			subsurface_handle_parent_destroy;
+		wl_signal_add(&parent->surface.resource.destroy_signal,
+			      &sub->parent_destroy_listener);
+
+		pixman_region32_init(&sub->cached.damage);
+		pixman_region32_init(&sub->cached.opaque);
+		pixman_region32_init(&sub->cached.input);
+		wl_list_init(&sub->cached.frame_callback_list);
+
+		sub->parent_transform.matrix = &parent->transform.matrix;
+		sub->parent_transform.parent = parent;
+		sub->parent_dirty_listener.notify =
+			subsurface_notify_parent_geometry_dirty;
+		wl_signal_add(&parent->transform.dirty_signal,
+			      &sub->parent_dirty_listener);
+		wl_list_insert(surface->geometry.transformation_list.prev,
+			       &sub->parent_transform.link);
+
+		sub->commit_mode = WL_SUBSURFACE_COMMIT_MODE_PARENT_CACHED;
+	}
+
+	wl_list_insert(&parent->subsurface_list, &sub->parent_link);
+}
+
+static const struct wl_subsurface_interface subsurface_interface = {
+	subsurface_destroy,
+	subsurface_set_position,
+	subsurface_place_above,
+	subsurface_place_below,
+	subsurface_set_commit_mode
+};
+
+static struct weston_subsurface *
+weston_subsurface_create(uint32_t id, struct weston_surface *surface,
+			 struct weston_surface *parent)
+{
+	struct weston_subsurface *sub;
+	uint32_t ret;
+
+	sub = calloc(1, sizeof *sub);
+	if (!sub)
+		return NULL;
+
+	sub->resource.destroy = subsurface_resource_destroy;
+	sub->resource.data = sub;
+	sub->resource.object.id = id;
+	sub->resource.object.interface = &wl_subsurface_interface;
+	sub->resource.object.implementation =
+		(void (**)(void))&subsurface_interface;
+
+	ret = wl_client_add_resource(surface->surface.resource.client,
+				     &sub->resource);
+	if (ret == 0) {
+		free(sub);
+		return NULL;
+	}
+
+	weston_subsurface_link(sub, surface, parent);
+
+	return sub;
+}
+
+/* Create a dummy subsurface for having the parent itself in its
+ * sub-surface list. Makes stacking order manipulation easy.
+ */
+static struct weston_subsurface *
+weston_subsurface_create_for_parent(struct weston_surface *parent)
+{
+	struct weston_subsurface *sub;
+
+	sub = calloc(1, sizeof *sub);
+	if (!sub)
+		return NULL;
+
+	weston_subsurface_link(sub, parent, parent);
+
+	return sub;
+}
+
+static void
+subcompositor_get_subsurface(struct wl_client *client,
+			     struct wl_resource *resource,
+			     uint32_t id,
+			     struct wl_resource *surface_resource,
+			     struct wl_resource *parent_resource)
+{
+	struct weston_surface *surface = surface_resource->data;
+	struct weston_surface *parent = parent_resource->data;
+	struct weston_subsurface *sub;
+	static const char where[] = "get_subsurface: wl_subsurface@";
+
+	if (surface == parent) {
+		wl_resource_post_error(resource,
+			WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
+			"%s%d: wl_surface@%d cannot be its own parent",
+			where, id, surface_resource->object.id);
+		return;
+	}
+
+	if (!wl_list_empty(&surface->subsurface_list)) {
+		wl_resource_post_error(resource,
+			WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
+			"%s%d: wl_surface@%d is already a parent",
+			where, id, surface_resource->object.id);
+		return;
+	}
+
+	if (weston_surface_to_subsurface(parent)) {
+		wl_resource_post_error(resource,
+			WL_SUBCOMPOSITOR_ERROR_BAD_PARENT,
+			"%s%d: parent wl_surface@%d is already a sub-surface",
+			where, id, parent_resource->object.id);
+		return;
+	}
+
+	if (weston_surface_to_subsurface(surface)) {
+		wl_resource_post_error(resource,
+			WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
+			"%s%d: wl_surface@%d is already a sub-surface",
+			where, id, surface_resource->object.id);
+		return;
+	}
+
+	if (surface->configure) {
+		wl_resource_post_error(resource,
+			WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
+			"%s%d: wl_surface@%d already has a role",
+			where, id, surface_resource->object.id);
+		return;
+	}
+
+	/* make sure the parent is in its own list */
+	if (wl_list_empty(&parent->subsurface_list)) {
+		if (!weston_subsurface_create_for_parent(parent)) {
+			wl_resource_post_no_memory(resource);
+			return;
+		}
+	}
+
+	sub = weston_subsurface_create(id, surface, parent);
+	if (!sub) {
+		wl_resource_post_no_memory(resource);
+		return;
+	}
+
+	surface->configure = subsurface_configure;
+	surface->private = sub;
+}
+
+static void
+subcompositor_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+}
+
+static const struct wl_subcompositor_interface subcompositor_interface = {
+	subcompositor_destroy,
+	subcompositor_get_subsurface
+};
+
+static void
+bind_subcompositor(struct wl_client *client,
+		   void *data, uint32_t version, uint32_t id)
+{
+	struct weston_compositor *compositor = data;
+
+	wl_client_add_object(client, &wl_subcompositor_interface,
+			     &subcompositor_interface, id, compositor);
+}
+
+static void
 weston_compositor_dpms(struct weston_compositor *compositor,
 		       enum dpms_enum state)
 {
@@ -3053,6 +3664,10 @@ weston_compositor_init(struct weston_compositor *ec,
 				   ec, compositor_bind))
 		return -1;
 
+	if (!wl_display_add_global(display, &wl_subcompositor_interface,
+				   ec, bind_subcompositor))
+		return -1;
+
 	wl_list_init(&ec->surface_list);
 	wl_list_init(&ec->layer_list);
 	wl_list_init(&ec->seat_list);
diff --git a/src/compositor.h b/src/compositor.h
index 3d197ef..d3c4f2d 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -379,6 +379,55 @@ struct weston_region {
 	pixman_region32_t region;
 };
 
+struct weston_subsurface {
+	struct wl_resource resource;
+
+	/* guaranteed to be valid and non-NULL */
+	struct weston_surface *surface;
+	struct wl_listener surface_destroy_listener;
+
+	/* can be NULL */
+	struct weston_surface *parent;
+	struct wl_listener parent_destroy_listener;
+	struct wl_list parent_link;
+
+	struct {
+		int32_t x;
+		int32_t y;
+		int set;
+	} position;
+
+	struct {
+		int has_data;
+
+		/* wl_surface.attach */
+		int remove_contents;
+		struct weston_buffer_reference buffer_ref;
+		int32_t sx;
+		int32_t sy;
+
+		/* wl_surface.damage */
+		pixman_region32_t damage;
+
+		/* wl_surface.set_opaque_region */
+		pixman_region32_t opaque;
+
+		/* wl_surface.set_input_region */
+		pixman_region32_t input;
+
+		/* wl_surface.frame */
+		struct wl_list frame_callback_list;
+
+		/* wl_surface.set_buffer_transform */
+		uint32_t buffer_transform;
+	} cached;
+
+	enum wl_subsurface_commit_mode commit_mode;
+
+	struct weston_matrix_pointer parent_transform;
+	struct wl_listener parent_dirty_listener;
+};
+
 /* Using weston_surface transformations
  *
  * To add a transformation to a surface, create a struct weston_matrix_pointer,
@@ -503,6 +552,12 @@ struct weston_surface {
 	 */
 	void (*configure)(struct weston_surface *es, int32_t sx, int32_t sy);
 	void *private;
+
+	/* Parent's list of its sub-surfaces, weston_subsurface:parent_link.
+	 * Contains also the parent itself as a dummy weston_subsurface,
+	 * if the list is not empty.
+	 */
+	struct wl_list subsurface_list;
 };
 
 enum weston_key_state_update {
-- 
1.7.12.4



More information about the wayland-devel mailing list