subcompositor: use wlr_surface_synced

This commit is contained in:
Simon Ser 2023-12-07 12:27:40 +01:00
parent 1c3c24825f
commit 96aec06b0a
3 changed files with 84 additions and 20 deletions

View file

@ -12,8 +12,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include <wlr/types/wlr_compositor.h>
struct wlr_surface;
/** /**
* The sub-surface state describing the sub-surface's relationship with its * The sub-surface state describing the sub-surface's relationship with its
@ -23,6 +22,10 @@ struct wlr_surface;
struct wlr_subsurface_parent_state { struct wlr_subsurface_parent_state {
int32_t x, y; int32_t x, y;
struct wl_list link; struct wl_list link;
// private state
struct wlr_surface_synced *synced;
}; };
struct wlr_subsurface { struct wlr_subsurface {
@ -47,6 +50,14 @@ struct wlr_subsurface {
} events; } events;
void *data; void *data;
// private state
struct wlr_surface_synced parent_synced;
struct {
int32_t x, y;
} previous;
}; };
struct wlr_subcompositor { struct wlr_subcompositor {

View file

@ -371,6 +371,19 @@ static void surface_state_move(struct wlr_surface_state *state,
state_synced[synced->index], next_synced[synced->index]); state_synced[synced->index], next_synced[synced->index]);
} }
// commit subsurface order
struct wlr_subsurface_parent_state *sub_state_next, *sub_state;
wl_list_for_each(sub_state_next, &next->subsurfaces_below, link) {
sub_state = wlr_surface_synced_get_state(sub_state_next->synced, state);
wl_list_remove(&sub_state->link);
wl_list_insert(state->subsurfaces_below.prev, &sub_state->link);
}
wl_list_for_each(sub_state_next, &next->subsurfaces_above, link) {
sub_state = wlr_surface_synced_get_state(sub_state_next->synced, state);
wl_list_remove(&sub_state->link);
wl_list_insert(state->subsurfaces_above.prev, &sub_state->link);
}
state->committed = next->committed; state->committed = next->committed;
next->committed = 0; next->committed = 0;
@ -523,20 +536,11 @@ static void surface_commit_state(struct wlr_surface *surface,
surface_update_opaque_region(surface); surface_update_opaque_region(surface);
surface_update_input_region(surface); surface_update_input_region(surface);
// commit subsurface order
struct wlr_subsurface *subsurface; struct wlr_subsurface *subsurface;
wl_list_for_each(subsurface, &surface->pending.subsurfaces_below, pending.link) { wl_list_for_each(subsurface, &surface->current.subsurfaces_below, current.link) {
wl_list_remove(&subsurface->current.link);
wl_list_insert(surface->current.subsurfaces_below.prev,
&subsurface->current.link);
subsurface_handle_parent_commit(subsurface); subsurface_handle_parent_commit(subsurface);
} }
wl_list_for_each(subsurface, &surface->pending.subsurfaces_above, pending.link) { wl_list_for_each(subsurface, &surface->current.subsurfaces_above, current.link) {
wl_list_remove(&subsurface->current.link);
wl_list_insert(surface->current.subsurfaces_above.prev,
&subsurface->current.link);
subsurface_handle_parent_commit(subsurface); subsurface_handle_parent_commit(subsurface);
} }

View file

@ -33,9 +33,9 @@ static void subsurface_destroy(struct wlr_subsurface *subsurface) {
wl_signal_emit_mutable(&subsurface->events.destroy, subsurface); wl_signal_emit_mutable(&subsurface->events.destroy, subsurface);
wlr_surface_synced_finish(&subsurface->parent_synced);
wl_list_remove(&subsurface->surface_client_commit.link); wl_list_remove(&subsurface->surface_client_commit.link);
wl_list_remove(&subsurface->current.link);
wl_list_remove(&subsurface->pending.link);
wl_list_remove(&subsurface->parent_destroy.link); wl_list_remove(&subsurface->parent_destroy.link);
wl_resource_set_user_data(subsurface->resource, NULL); wl_resource_set_user_data(subsurface->resource, NULL);
@ -225,6 +225,33 @@ const struct wlr_surface_role subsurface_role = {
.destroy = subsurface_role_destroy, .destroy = subsurface_role_destroy,
}; };
static void surface_synced_init_state(void *_state) {
struct wlr_subsurface_parent_state *state = _state;
wl_list_init(&state->link);
}
static void surface_synced_finish_state(void *_state) {
struct wlr_subsurface_parent_state *state = _state;
wl_list_remove(&state->link);
}
static void surface_synced_move_state(void *_dst, void *_src) {
struct wlr_subsurface_parent_state *dst = _dst, *src = _src;
dst->x = src->x;
dst->y = src->y;
dst->synced = src->synced;
// For the sake of simplicity, copying the position in list is done by the
// parent itself
}
static struct wlr_surface_synced_impl surface_synced_impl = {
.state_size = sizeof(struct wlr_subsurface_parent_state),
.init_state = surface_synced_init_state,
.finish_state = surface_synced_finish_state,
.move_state = surface_synced_move_state,
};
static void subsurface_handle_parent_destroy(struct wl_listener *listener, static void subsurface_handle_parent_destroy(struct wl_listener *listener,
void *data) { void *data) {
struct wlr_subsurface *subsurface = struct wlr_subsurface *subsurface =
@ -267,8 +294,8 @@ static void collect_damage_iter(struct wlr_surface *surface,
void subsurface_handle_parent_commit(struct wlr_subsurface *subsurface) { void subsurface_handle_parent_commit(struct wlr_subsurface *subsurface) {
struct wlr_surface *surface = subsurface->surface; struct wlr_surface *surface = subsurface->surface;
bool moved = subsurface->current.x != subsurface->pending.x || bool moved = subsurface->current.x != subsurface->previous.x ||
subsurface->current.y != subsurface->pending.y; subsurface->current.y != subsurface->previous.y;
if (subsurface->surface->mapped && moved) { if (subsurface->surface->mapped && moved) {
wlr_surface_for_each_surface(surface, wlr_surface_for_each_surface(surface,
collect_damage_iter, subsurface); collect_damage_iter, subsurface);
@ -279,8 +306,6 @@ void subsurface_handle_parent_commit(struct wlr_subsurface *subsurface) {
subsurface->has_cache = false; subsurface->has_cache = false;
} }
subsurface->current.x = subsurface->pending.x;
subsurface->current.y = subsurface->pending.y;
if (subsurface->surface->mapped && (moved || subsurface->reordered)) { if (subsurface->surface->mapped && (moved || subsurface->reordered)) {
subsurface->reordered = false; subsurface->reordered = false;
wlr_surface_for_each_surface(surface, wlr_surface_for_each_surface(surface,
@ -293,6 +318,9 @@ void subsurface_handle_parent_commit(struct wlr_subsurface *subsurface) {
subsurface); subsurface);
subsurface_consider_map(subsurface); subsurface_consider_map(subsurface);
} }
subsurface->previous.x = subsurface->current.x;
subsurface->previous.y = subsurface->current.y;
} }
struct wlr_subsurface *wlr_subsurface_try_from_wlr_surface(struct wlr_surface *surface) { struct wlr_subsurface *wlr_subsurface_try_from_wlr_surface(struct wlr_surface *surface) {
@ -335,11 +363,19 @@ static void subcompositor_handle_get_subsurface(struct wl_client *client,
return; return;
} }
if (!wlr_surface_synced_init(&subsurface->parent_synced, parent, &surface_synced_impl,
&subsurface->pending, &subsurface->current)) {
free(subsurface);
wl_client_post_no_memory(client);
return;
}
subsurface->synchronized = true; subsurface->synchronized = true;
subsurface->surface = surface; subsurface->surface = surface;
subsurface->resource = wl_resource_create(client, &wl_subsurface_interface, subsurface->resource = wl_resource_create(client, &wl_subsurface_interface,
wl_resource_get_version(resource), id); wl_resource_get_version(resource), id);
if (subsurface->resource == NULL) { if (subsurface->resource == NULL) {
wlr_surface_synced_finish(&subsurface->parent_synced);
free(subsurface); free(subsurface);
wl_client_post_no_memory(client); wl_client_post_no_memory(client);
return; return;
@ -347,6 +383,19 @@ static void subcompositor_handle_get_subsurface(struct wl_client *client,
wl_resource_set_implementation(subsurface->resource, wl_resource_set_implementation(subsurface->resource,
&subsurface_implementation, subsurface, NULL); &subsurface_implementation, subsurface, NULL);
// In surface_state_move() we commit sub-surface order. To do so we need to
// iterate over the list of sub-surfaces from a struct wlr_surface_state.
// Store a pointer to struct wlr_surface_synced to facilitate this.
subsurface->pending.synced = &subsurface->parent_synced;
subsurface->current.synced = &subsurface->parent_synced;
struct wlr_surface_state *cached;
wl_list_for_each(cached, &parent->cached, cached_state_link) {
struct wlr_subsurface_parent_state *sub_state =
wlr_surface_synced_get_state(&subsurface->parent_synced, cached);
sub_state->synced = &subsurface->parent_synced;
}
wlr_surface_set_role_object(surface, subsurface->resource); wlr_surface_set_role_object(surface, subsurface->resource);
wl_signal_init(&subsurface->events.destroy); wl_signal_init(&subsurface->events.destroy);
@ -361,7 +410,7 @@ static void subcompositor_handle_get_subsurface(struct wl_client *client,
wl_signal_add(&parent->events.destroy, &subsurface->parent_destroy); wl_signal_add(&parent->events.destroy, &subsurface->parent_destroy);
subsurface->parent_destroy.notify = subsurface_handle_parent_destroy; subsurface->parent_destroy.notify = subsurface_handle_parent_destroy;
wl_list_init(&subsurface->current.link); wl_list_remove(&subsurface->pending.link);
wl_list_insert(parent->pending.subsurfaces_above.prev, wl_list_insert(parent->pending.subsurfaces_above.prev,
&subsurface->pending.link); &subsurface->pending.link);
} }