static void subsurface_unlink_parent(struct ds_subsurface *subsurface);
static struct ds_subsurface *subsurface_find_sibling(struct ds_subsurface *subsurface,
struct ds_surface *surface);
+static bool subsurface_is_synchronized(struct ds_subsurface *subsurface);
+static void subsurface_synchronized_commit(struct ds_subsurface *subsurface);
struct ds_subsurface *
create_subsurface(struct wl_resource *subcomp_resource,
return ds_surface_get_role(surface) == &subsurface_role;
}
+void
+subsurface_commit(struct ds_subsurface *subsurface)
+{
+ struct ds_surface *surface = subsurface->surface;
+ struct ds_subsurface *child;
+
+ if (subsurface_is_synchronized(subsurface)) {
+ surface_state_move(&subsurface->cached, &surface->pending);
+ subsurface->has_cache = true;
+ }
+ else {
+ if (subsurface->has_cache) {
+ surface_state_move(&subsurface->cached, &surface->pending);
+ surface_commit_state(surface, &subsurface->cached);
+ subsurface->has_cache = false;
+ }
+ else {
+ surface_commit_state(surface, &surface->pending);
+ }
+
+ wl_list_for_each(child, &surface->current.subsurfaces_below, current.link)
+ subsurface_parent_commit(child, false);
+ wl_list_for_each(child, &surface->current.subsurfaces_above, current.link)
+ subsurface_parent_commit(child, false);
+ }
+}
+
+void
+subsurface_parent_commit(struct ds_subsurface *subsurface, bool synchronized)
+{
+ if (subsurface->current.x != subsurface->pending.x ||
+ subsurface->current.y != subsurface->pending.y) {
+ subsurface->current.x = subsurface->pending.x;
+ subsurface->current.y = subsurface->pending.y;
+ }
+
+ if (synchronized || subsurface->synchronized) {
+ subsurface_synchronized_commit(subsurface);
+ }
+}
+
WL_EXPORT struct ds_subsurface *
ds_subsurface_from_resource(struct wl_resource *resource)
{
if (subsurface->synchronized) {
subsurface->synchronized = false;
- // TODO: flush
+ if (!subsurface_is_synchronized(subsurface))
+ subsurface_synchronized_commit(subsurface);
}
}
if (subsurface->surface)
subsurface_unlink_surface(subsurface);
+ surface_state_finish(&subsurface->cached);
wl_resource_set_user_data(subsurface->resource, NULL);
free(subsurface);
return NULL;
}
+
+static bool
+subsurface_is_synchronized(struct ds_subsurface *subsurface)
+{
+ struct ds_subsurface *iter = subsurface;
+
+ do {
+ if (iter->synchronized)
+ return true;
+
+ if (!iter->parent)
+ break;
+ } while ((iter = subsurface_from_ds_surface(iter->parent)));
+
+ return false;
+}
+
+static void
+subsurface_synchronized_commit(struct ds_subsurface *subsurface)
+{
+ struct ds_surface *surface = subsurface->surface;
+ struct ds_subsurface *child;
+
+ if (subsurface->has_cache) {
+ surface_state_move(&subsurface->cached, &surface->pending);
+ surface_commit_state(surface, &subsurface->cached);
+ subsurface->has_cache = false;
+ }
+
+ wl_list_for_each(child, &surface->current.subsurfaces_below, current.link)
+ subsurface_parent_commit(child, true);
+ wl_list_for_each(child, &surface->current.subsurfaces_above, current.link)
+ subsurface_parent_commit(child, true);
+}
static const struct wl_surface_interface surface_impl;
static void surface_handle_resource_destroy(struct wl_resource *resource);
-static void surface_state_init(struct ds_surface_state *state);
-static void surface_state_finish(struct ds_surface_state *state);
-static void surface_state_move(struct ds_surface_state *state,
- struct ds_surface_state *next);
static void surface_finalize_pending(struct ds_surface *surface);
-static void surface_commit_state(struct ds_surface *surface,
- struct ds_surface_state *next);
static bool surface_for_each(struct ds_surface *surface, int x, int y,
ds_surface_for_each_func_t iterator, void *data);
+static void surface_update_damage(pixman_region32_t *buffer_damage,
+ struct ds_surface_state *current, struct ds_surface_state *pending);
+static void surface_update_buffer(struct ds_surface *surface);
WL_EXPORT void
ds_surface_add_destroy_listener(struct ds_surface *surface,
return surface->resource;
}
+void
+surface_state_move(struct ds_surface_state *state, struct ds_surface_state *next)
+{
+ state->width = next->width;
+ state->height = next->height;
+ state->buffer_width = next->buffer_width;
+ state->buffer_height = next->buffer_height;
+
+ if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_SCALE))
+ state->scale = next->scale;
+
+ if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_TRANSFORM))
+ state->transform = next->transform;
+
+ if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_BUFFER)) {
+ state->dx = next->dx;
+ state->dy = next->dy;
+ next->dx = next->dy = 0;
+
+ if (state->buffer) {
+ ds_buffer_unlock(state->buffer);
+ state->buffer = NULL;
+ }
+
+ if (next->buffer) {
+ state->buffer = ds_buffer_lock(next->buffer);
+ ds_buffer_unlock(next->buffer);
+ next->buffer = NULL;
+ }
+ }
+ else {
+ state->dx = state->dy = 0;
+ }
+
+ if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_SURFACE_DAMAGE)) {
+ pixman_region32_copy(&state->surface_damage, &next->surface_damage);
+ pixman_region32_clear(&next->surface_damage);
+ }
+ else
+ pixman_region32_clear(&state->surface_damage);
+
+ if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_BUFFER_DAMAGE)) {
+ pixman_region32_copy(&state->buffer_damage, &next->buffer_damage);
+ pixman_region32_clear(&next->buffer_damage);
+ }
+ else
+ pixman_region32_clear(&state->buffer_damage);
+
+ if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_OPAQUE_REGION))
+ pixman_region32_copy(&state->opaque, &next->opaque);
+
+ if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_INPUT_REGION))
+ pixman_region32_copy(&state->input, &next->input);
+
+ if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_VIEWPORT))
+ memcpy(&state->viewport, &next->viewport, sizeof(state->viewport));
+
+ if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_FRAME_CALLBACK_LIST)) {
+ wl_list_insert_list(&state->frame_callback_list,
+ &next->frame_callback_list);
+ wl_list_init(&next->frame_callback_list);
+ }
+
+ // FIXME
+ // state->committed |= next->committed; ??
+ state->committed = next->committed;
+ next->committed = 0;
+}
+
+void
+surface_commit_state(struct ds_surface *surface, struct ds_surface_state *next)
+{
+ struct ds_subsurface *subsurface;
+
+ surface_finalize_pending(surface);
+
+ surface->sx += next->dx;
+ surface->sy += next->dy;
+ surface_update_damage(&surface->buffer_damage, &surface->current, next);
+
+ surface_state_move(&surface->current, next);
+
+ // FIXME no need?
+ if (DS_FLAG_IS_SET(surface->current.committed, DS_SURFACE_STATE_BUFFER))
+ surface_update_buffer(surface);
+
+
+ wl_list_for_each_reverse(subsurface, &surface->pending.subsurfaces_above,
+ pending.link) {
+ wl_list_remove(&subsurface->current.link);
+ wl_list_insert(&surface->current.subsurfaces_above,
+ &subsurface->current.link);
+ }
+ wl_list_for_each_reverse(subsurface, &surface->pending.subsurfaces_below,
+ pending.link) {
+ wl_list_remove(&subsurface->current.link);
+ wl_list_insert(&surface->current.subsurfaces_below,
+ &subsurface->current.link);
+ }
+
+ if (surface->role && surface->role->commit)
+ surface->role->commit(surface);
+
+ wl_signal_emit(&surface->events.commit, surface);
+}
+
+void
+surface_state_init(struct ds_surface_state *state)
+{
+ state->scale = 1;
+ state->transform = WL_OUTPUT_TRANSFORM_NORMAL;
+
+ wl_list_init(&state->subsurfaces_above);
+ wl_list_init(&state->subsurfaces_below);
+
+ wl_list_init(&state->frame_callback_list);
+
+ pixman_region32_init(&state->surface_damage);
+ pixman_region32_init(&state->buffer_damage);
+ pixman_region32_init(&state->opaque);
+ pixman_region32_init_rect(&state->input,
+ INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX);
+}
+
+void
+surface_state_finish(struct ds_surface_state *state)
+{
+ struct wl_resource *resource, *tmp;
+
+ if (state->buffer)
+ ds_buffer_unlock(state->buffer);
+
+ wl_resource_for_each_safe(resource, tmp, &state->frame_callback_list)
+ wl_resource_destroy(resource);
+
+ pixman_region32_fini(&state->surface_damage);
+ pixman_region32_fini(&state->buffer_damage);
+ pixman_region32_fini(&state->opaque);
+ pixman_region32_fini(&state->input);
+}
+
static void
surface_handle_destroy(struct wl_client *client, struct wl_resource *resource)
{
surface_handle_commit(struct wl_client *client, struct wl_resource *resource)
{
struct ds_surface *surface;
+ struct ds_subsurface *subsurface, *child;
surface = wl_resource_get_user_data(resource);
ds_dbg("ds_surface(%p) commit", surface);
- // TODO handle subsurface
-
- surface_finalize_pending(surface);
+ if (ds_surface_is_subsurface(surface)) {
+ subsurface = subsurface_from_ds_surface(surface);
+ subsurface_commit(subsurface);
+ return;
+ }
surface_commit_state(surface, &surface->pending);
- // TODO handle subsurfaces of a given surface
+ wl_list_for_each(child, &surface->current.subsurfaces_below, current.link)
+ subsurface_parent_commit(child, false);
+ wl_list_for_each(child, &surface->current.subsurfaces_above, current.link)
+ subsurface_parent_commit(child, false);
}
static void
}
static void
-surface_state_init(struct ds_surface_state *state)
-{
- state->scale = 1;
- state->transform = WL_OUTPUT_TRANSFORM_NORMAL;
-
- wl_list_init(&state->subsurfaces_above);
- wl_list_init(&state->subsurfaces_below);
-
- wl_list_init(&state->frame_callback_list);
-
- pixman_region32_init(&state->surface_damage);
- pixman_region32_init(&state->buffer_damage);
- pixman_region32_init(&state->opaque);
- pixman_region32_init_rect(&state->input,
- INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX);
-}
-
-static void
-surface_state_finish(struct ds_surface_state *state)
-{
- struct wl_resource *resource, *tmp;
-
- if (state->buffer)
- ds_buffer_unlock(state->buffer);
-
- wl_resource_for_each_safe(resource, tmp, &state->frame_callback_list)
- wl_resource_destroy(resource);
-
- pixman_region32_fini(&state->surface_damage);
- pixman_region32_fini(&state->buffer_damage);
- pixman_region32_fini(&state->opaque);
- pixman_region32_fini(&state->input);
-}
-
-static void
-surface_state_move(struct ds_surface_state *state, struct ds_surface_state *next)
-{
- state->width = next->width;
- state->height = next->height;
- state->buffer_width = next->buffer_width;
- state->buffer_height = next->buffer_height;
-
- if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_SCALE))
- state->scale = next->scale;
-
- if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_TRANSFORM))
- state->transform = next->transform;
-
- if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_BUFFER)) {
- state->dx = next->dx;
- state->dy = next->dy;
- next->dx = next->dy = 0;
-
- if (state->buffer) {
- ds_buffer_unlock(state->buffer);
- state->buffer = NULL;
- }
-
- if (next->buffer) {
- state->buffer = ds_buffer_lock(next->buffer);
- ds_buffer_unlock(next->buffer);
- next->buffer = NULL;
- }
- }
- else {
- state->dx = state->dy = 0;
- }
-
- if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_SURFACE_DAMAGE)) {
- pixman_region32_copy(&state->surface_damage, &next->surface_damage);
- pixman_region32_clear(&next->surface_damage);
- }
- else
- pixman_region32_clear(&state->surface_damage);
-
- if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_BUFFER_DAMAGE)) {
- pixman_region32_copy(&state->buffer_damage, &next->buffer_damage);
- pixman_region32_clear(&next->buffer_damage);
- }
- else
- pixman_region32_clear(&state->buffer_damage);
-
- if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_OPAQUE_REGION))
- pixman_region32_copy(&state->opaque, &next->opaque);
-
- if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_INPUT_REGION))
- pixman_region32_copy(&state->input, &next->input);
-
- if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_VIEWPORT))
- memcpy(&state->viewport, &next->viewport, sizeof(state->viewport));
-
- if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_FRAME_CALLBACK_LIST)) {
- wl_list_insert_list(&state->frame_callback_list,
- &next->frame_callback_list);
- wl_list_init(&next->frame_callback_list);
- }
-
- // FIXME
- // state->committed |= next->committed; ??
- state->committed = next->committed;
- next->committed = 0;
-}
-
-static void
surface_state_viewport_src_size(struct ds_surface_state *state,
int *out_width, int *out_height)
{
}
}
-static void
-surface_commit_state(struct ds_surface *surface, struct ds_surface_state *next)
-{
- surface->sx += next->dx;
- surface->sy += next->dy;
- surface_update_damage(&surface->buffer_damage, &surface->current, next);
-
- surface_state_move(&surface->current, next);
-
- // FIXME no need?
- if (DS_FLAG_IS_SET(surface->current.committed, DS_SURFACE_STATE_BUFFER))
- surface_update_buffer(surface);
-
- if (surface->role && surface->role->commit)
- surface->role->commit(surface);
-
- wl_signal_emit(&surface->events.commit, surface);
-}
-
static bool
surface_for_each(struct ds_surface *surface, int x, int y,
ds_surface_for_each_func_t iterator, void *data)