From e67858b9cfe07efd58ea2abafc8e0642f4f46753 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 25 Apr 2013 13:57:42 +0300 Subject: [PATCH] compositor: introduce 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 - an implementation of the wl_subsurface interface - allow nesting of sub-surfaces - proper surface transformation inheritance from parent to sub-surfaces - two different modes of wl_surface.commit for sub-surfaces - hook sub-surfaces up to repaint by modifying the repaint list code 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, they are hooked up via the sub-surface list present in parent weston_surface. 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. Also, only the main surface should be subject to shell actions. The surface list rebuilding in weston_output_repaint() is modified to process sub-surface lists, if they are non-empty. The sub-surface list always contains the parent, too, unless empty. The collection of frame_callback_list is moved to a later loop, to streamline the surface list rebuild functions. Features still lacking are: - full-surface alpha support for compound windows 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 Changes in v3: - rebased, and use the new transform inheritance code - squashed the commit "add sub-surfaces to repaint list" - fixed a buffer reference leak in commit_from_cache() - Rewrite the sub-surface destructor code, and make it leave the wl_subsurface protocol object inert, if one destroys the corresponding wl_surface. - replaced set_commit_mode with set_sync and set_desync - allowed sub-surface nesting, and fixed repaint accordingly - implemented nested sub-surface commit modes - Made the sub-surface order changes from wl_subsurface.place_above and .place_below to be applied when the parent surface state is applied, instead of immediately. This conforms with the protocol specification now. Signed-off-by: Pekka Paalanen --- src/compositor.c | 736 +++++++++++++++++++++++++++++++++++++++++++++-- src/compositor.h | 54 ++++ 2 files changed, 774 insertions(+), 16 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index 93bd7369..856e359f 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) { @@ -314,6 +317,9 @@ 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); + wl_list_init(&surface->subsurface_list_pending); + return surface; } @@ -972,6 +978,8 @@ destroy_surface(struct wl_resource *resource) struct weston_frame_callback *cb, *next; assert(wl_list_empty(&surface->geometry.child_list)); + assert(wl_list_empty(&surface->subsurface_list_pending)); + assert(wl_list_empty(&surface->subsurface_list)); if (weston_surface_is_mapped(surface)) weston_surface_unmap(surface); @@ -1167,31 +1175,58 @@ compositor_accumulate_damage(struct weston_compositor *ec) } } +static void +surface_list_add(struct weston_compositor *compositor, + struct weston_surface *surface) +{ + struct weston_subsurface *sub; + + if (wl_list_empty(&surface->subsurface_list)) { + weston_surface_update_transform(surface); + wl_list_insert(compositor->surface_list.prev, &surface->link); + return; + } + + wl_list_for_each(sub, &surface->subsurface_list, parent_link) { + if (!weston_surface_is_mapped(sub->surface)) + continue; + + if (sub->surface == surface) { + weston_surface_update_transform(sub->surface); + wl_list_insert(compositor->surface_list.prev, + &sub->surface->link); + } else { + surface_list_add(compositor, sub->surface); + } + } +} + +static void +weston_compositor_build_surface_list(struct weston_compositor *compositor) +{ + struct weston_surface *surface; + struct weston_layer *layer; + + wl_list_init(&compositor->surface_list); + wl_list_for_each(layer, &compositor->layer_list, link) { + wl_list_for_each(surface, &layer->surface_list, layer_link) { + surface_list_add(compositor, surface); + } + } +} + static void weston_output_repaint(struct weston_output *output, uint32_t msecs) { struct weston_compositor *ec = output->compositor; struct weston_surface *es; - struct weston_layer *layer; struct weston_animation *animation, *next; struct weston_frame_callback *cb, *cnext; struct wl_list frame_callback_list; pixman_region32_t output_damage; /* Rebuild the surface list and update surface transforms up front. */ - wl_list_init(&ec->surface_list); - wl_list_init(&frame_callback_list); - wl_list_for_each(layer, &ec->layer_list, link) { - wl_list_for_each(es, &layer->surface_list, layer_link) { - weston_surface_update_transform(es); - wl_list_insert(ec->surface_list.prev, &es->link); - if (es->output == output) { - wl_list_insert_list(&frame_callback_list, - &es->frame_callback_list); - wl_list_init(&es->frame_callback_list); - } - } - } + weston_compositor_build_surface_list(ec); if (output->assign_planes && !output->disable_planes) output->assign_planes(output); @@ -1199,6 +1234,15 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs) wl_list_for_each(es, &ec->surface_list, link) weston_surface_move_to_plane(es, &ec->primary_plane); + wl_list_init(&frame_callback_list); + wl_list_for_each(es, &ec->surface_list, link) { + if (es->output == output) { + wl_list_insert_list(&frame_callback_list, + &es->frame_callback_list); + wl_list_init(&es->frame_callback_list); + } + } + compositor_accumulate_damage(ec); pixman_region32_init(&output_damage); @@ -1425,9 +1469,20 @@ surface_set_input_region(struct wl_client *client, } static void -surface_commit(struct wl_client *client, struct wl_resource *resource) +weston_surface_commit_subsurface_order(struct weston_surface *surface) +{ + struct weston_subsurface *sub; + + wl_list_for_each_reverse(sub, &surface->subsurface_list_pending, + parent_link_pending) { + wl_list_remove(&sub->parent_link); + wl_list_insert(&surface->subsurface_list, &sub->parent_link); + } +} + +static void +weston_surface_commit(struct weston_surface *surface) { - struct weston_surface *surface = resource->data; pixman_region32_t opaque; int buffer_width = 0; int buffer_height = 0; @@ -1492,9 +1547,37 @@ surface_commit(struct wl_client *client, struct wl_resource *resource) &surface->pending.frame_callback_list); wl_list_init(&surface->pending.frame_callback_list); + weston_surface_commit_subsurface_order(surface); + weston_surface_schedule_repaint(surface); } +static void +weston_subsurface_commit(struct weston_subsurface *sub); + +static void +weston_subsurface_parent_commit(struct weston_subsurface *sub, + int parent_is_synchronized); + +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, 0); + } +} + static void surface_set_buffer_transform(struct wl_client *client, struct wl_resource *resource, int transform) @@ -1613,6 +1696,623 @@ static const struct wl_compositor_interface compositor_interface = { compositor_create_region }; +static void +weston_subsurface_commit_from_cache(struct weston_subsurface *sub) +{ + struct weston_surface *surface = sub->surface; + pixman_region32_t opaque; + int buffer_width = 0; + int buffer_height = 0; + + /* wl_surface.set_buffer_rotation */ + surface->buffer_transform = sub->cached.buffer_transform; + + /* wl_surface.attach */ + if (sub->cached.buffer_ref.buffer || sub->cached.newly_attached) + weston_surface_attach(surface, sub->cached.buffer_ref.buffer); + weston_buffer_reference(&sub->cached.buffer_ref, NULL); + + if (surface->buffer_ref.buffer) { + buffer_width = weston_surface_buffer_width(surface); + buffer_height = weston_surface_buffer_height(surface); + } + + if (surface->configure && sub->cached.newly_attached) + surface->configure(surface, sub->cached.sx, sub->cached.sy, + buffer_width, buffer_height); + sub->cached.sx = 0; + sub->cached.sy = 0; + sub->cached.newly_attached = 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_commit_subsurface_order(surface); + + 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.newly_attached) { + sub->cached.newly_attached = 1; + 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; + surface->pending.newly_attached = 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 int +weston_subsurface_is_synchronized(struct weston_subsurface *sub) +{ + while (sub) { + if (sub->synchronized) + return 1; + + if (!sub->parent) + return 0; + + sub = weston_surface_to_subsurface(sub->parent); + } + + return 0; +} + +static void +weston_subsurface_commit(struct weston_subsurface *sub) +{ + struct weston_surface *surface = sub->surface; + struct weston_subsurface *tmp; + + /* Recursive check for effectively synchronized. */ + if (weston_subsurface_is_synchronized(sub)) { + weston_subsurface_commit_to_cache(sub); + } else { + 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(surface); + } + + wl_list_for_each(tmp, &surface->subsurface_list, parent_link) { + if (tmp->surface != surface) + weston_subsurface_parent_commit(tmp, 0); + } + } +} + +static void +weston_subsurface_parent_commit(struct weston_subsurface *sub, + int parent_is_synchronized) +{ + struct weston_surface *surface = sub->surface; + struct weston_subsurface *tmp; + + if (sub->position.set) { + weston_surface_set_position(sub->surface, + sub->position.x, sub->position.y); + sub->position.set = 0; + } + + if (!parent_is_synchronized && !sub->synchronized) + return; + + /* From now on, commit_from_cache the whole sub-tree, regardless of + * the synchronized mode of each child. This sub-surface or some + * of its ancestors were synchronized, so we are synchronized + * all the way down. + */ + + if (sub->cached.has_data) + weston_subsurface_commit_from_cache(sub); + + wl_list_for_each(tmp, &surface->subsurface_list, parent_link) { + if (tmp->surface != surface) + weston_subsurface_parent_commit(tmp, 1); + } +} + +static void +subsurface_configure(struct weston_surface *surface, int32_t dx, int32_t dy, + int32_t width, int32_t height) +{ + struct weston_compositor *compositor = surface->compositor; + + weston_surface_configure(surface, + surface->geometry.x + dx, + surface->geometry.y + dy, + width, height); + + /* 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->configure_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; + + if (!sub) + return; + + 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->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->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; + + if (!sub) + return; + + sibling = subsurface_sibling_check(sub, surface, "place_above"); + if (!sibling) + return; + + wl_list_remove(&sub->parent_link_pending); + wl_list_insert(sibling->parent_link_pending.prev, + &sub->parent_link_pending); +} + +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; + + if (!sub) + return; + + sibling = subsurface_sibling_check(sub, surface, "place_below"); + if (!sibling) + return; + + wl_list_remove(&sub->parent_link_pending); + wl_list_insert(&sibling->parent_link_pending, + &sub->parent_link_pending); +} + +static void +subsurface_set_sync(struct wl_client *client, struct wl_resource *resource) +{ + struct weston_subsurface *sub = resource->data; + + if (sub) + sub->synchronized = 1; +} + +static void +subsurface_set_desync(struct wl_client *client, struct wl_resource *resource) +{ + struct weston_subsurface *sub = resource->data; + + if (sub) + sub->synchronized = 0; +} + +static void +weston_subsurface_cache_init(struct weston_subsurface *sub) +{ + 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->cached.buffer_ref.buffer = NULL; +} + +static void +weston_subsurface_cache_fini(struct weston_subsurface *sub) +{ + struct weston_frame_callback *cb, *tmp; + + 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); +} + +static void +weston_subsurface_unlink_parent(struct weston_subsurface *sub) +{ + wl_list_remove(&sub->parent_link); + wl_list_remove(&sub->parent_link_pending); + wl_list_remove(&sub->parent_destroy_listener.link); + sub->parent = NULL; +} + +static void +weston_subsurface_destroy(struct weston_subsurface *sub); + +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->resource); + + /* The protocol object (wl_resource) is left inert. */ + if (sub->resource) + sub->resource->data = NULL; + + weston_subsurface_destroy(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->resource); + assert(sub->surface != sub->parent); + + if (weston_surface_is_mapped(sub->surface)) + weston_surface_unmap(sub->surface); + + weston_subsurface_unlink_parent(sub); +} + +static void +subsurface_resource_destroy(struct wl_resource *resource) +{ + struct weston_subsurface *sub = resource->data; + + if (sub) + weston_subsurface_destroy(sub); + + free(resource); +} + +static void +subsurface_destroy(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +weston_subsurface_link_parent(struct weston_subsurface *sub, + struct weston_surface *parent) +{ + sub->parent = parent; + sub->parent_destroy_listener.notify = subsurface_handle_parent_destroy; + wl_signal_add(&parent->resource.destroy_signal, + &sub->parent_destroy_listener); + + wl_list_insert(&parent->subsurface_list, &sub->parent_link); + wl_list_insert(&parent->subsurface_list_pending, + &sub->parent_link_pending); +} + +static void +weston_subsurface_link_surface(struct weston_subsurface *sub, + struct weston_surface *surface) +{ + sub->surface = surface; + sub->surface_destroy_listener.notify = + subsurface_handle_surface_destroy; + wl_signal_add(&surface->resource.destroy_signal, + &sub->surface_destroy_listener); +} + +static void +weston_subsurface_destroy(struct weston_subsurface *sub) +{ + assert(sub->surface); + + if (sub->resource) { + assert(weston_surface_to_subsurface(sub->surface) == sub); + assert(sub->parent_destroy_listener.notify == + subsurface_handle_parent_destroy); + + weston_surface_set_transform_parent(sub->surface, NULL); + if (sub->parent) + weston_subsurface_unlink_parent(sub); + + weston_subsurface_cache_fini(sub); + + sub->surface->configure = NULL; + sub->surface->configure_private = NULL; + } else { + /* the dummy weston_subsurface for the parent itself */ + assert(sub->parent_destroy_listener.notify == NULL); + wl_list_remove(&sub->parent_link); + wl_list_remove(&sub->parent_link_pending); + } + + wl_list_remove(&sub->surface_destroy_listener.link); + free(sub); +} + +static const struct wl_subsurface_interface subsurface_implementation = { + subsurface_destroy, + subsurface_set_position, + subsurface_place_above, + subsurface_place_below, + subsurface_set_sync, + subsurface_set_desync +}; + +static struct weston_subsurface * +weston_subsurface_create(uint32_t id, struct weston_surface *surface, + struct weston_surface *parent) +{ + struct weston_subsurface *sub; + + sub = calloc(1, sizeof *sub); + if (!sub) + return NULL; + + sub->resource = wl_client_add_object(surface->resource.client, + &wl_subsurface_interface, + &subsurface_implementation, + id, sub); + if (!sub->resource) { + free(sub); + return NULL; + } + + sub->resource->destroy = subsurface_resource_destroy; + weston_subsurface_link_surface(sub, surface); + weston_subsurface_link_parent(sub, parent); + weston_subsurface_cache_init(sub); + sub->synchronized = 1; + weston_surface_set_transform_parent(surface, parent); + + return sub; +} + +/* Create a dummy subsurface for having the parent itself in its + * sub-surface lists. 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_surface(sub, parent); + sub->parent = parent; + wl_list_insert(&parent->subsurface_list, &sub->parent_link); + wl_list_insert(&parent->subsurface_list_pending, + &sub->parent_link_pending); + + 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 (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->configure_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) @@ -2012,6 +2712,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->plane_list); wl_list_init(&ec->layer_list); diff --git a/src/compositor.h b/src/compositor.h index e3584743..3532b0aa 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -558,6 +558,53 @@ 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 wl_list parent_link_pending; + + struct { + int32_t x; + int32_t y; + int set; + } position; + + struct { + int has_data; + + /* wl_surface.attach */ + int newly_attached; + 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; + + int synchronized; +}; + /* Using weston_surface transformations * * To add a transformation to a surface, create a struct weston_transform, and @@ -690,6 +737,13 @@ struct weston_surface { */ void (*configure)(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height); void *configure_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; /* weston_subsurface::parent_link */ + struct wl_list subsurface_list_pending; /* ...::parent_link_pending */ }; enum weston_key_state_update {