pointer-constraints: use wlr_surface_synced.commit hook

This fixes a problem where an outdated surface input region was used to
compute the effective confinement region.

Additionally, this commit fixes a bug in pointer_constraint_create()
which caused the initial region to not be applied immediately.

This is a breaking change: set_region is now emitted before the role
commit hook is called, and it's not emitted if the region hasn't
actually changed.
This commit is contained in:
Kirill Primak 2025-01-08 12:16:24 +03:00 committed by Isaac Freund
parent f95270bb5e
commit b25f98d583
2 changed files with 34 additions and 34 deletions

View file

@ -64,7 +64,6 @@ struct wlr_pointer_constraint_v1 {
void *data; void *data;
struct { struct {
struct wl_listener surface_commit;
struct wl_listener surface_destroy; struct wl_listener surface_destroy;
struct wl_listener seat_destroy; struct wl_listener seat_destroy;

View file

@ -58,7 +58,6 @@ static void pointer_constraint_destroy(struct wlr_pointer_constraint_v1 *constra
wl_resource_set_user_data(constraint->resource, NULL); wl_resource_set_user_data(constraint->resource, NULL);
wlr_surface_synced_finish(&constraint->synced); wlr_surface_synced_finish(&constraint->synced);
wl_list_remove(&constraint->link); wl_list_remove(&constraint->link);
wl_list_remove(&constraint->surface_commit.link);
wl_list_remove(&constraint->surface_destroy.link); wl_list_remove(&constraint->surface_destroy.link);
wl_list_remove(&constraint->seat_destroy.link); wl_list_remove(&constraint->seat_destroy.link);
pixman_region32_fini(&constraint->region); pixman_region32_fini(&constraint->region);
@ -72,19 +71,6 @@ static void pointer_constraint_destroy_resource(struct wl_resource *resource) {
pointer_constraint_destroy(constraint); pointer_constraint_destroy(constraint);
} }
static void pointer_constraint_set_region(
struct wlr_pointer_constraint_v1 *constraint,
struct wl_resource *region_resource) {
pixman_region32_clear(&constraint->pending.region);
if (region_resource) {
const pixman_region32_t *region = wlr_region_from_resource(region_resource);
pixman_region32_copy(&constraint->pending.region, region);
}
constraint->pending.committed |= WLR_POINTER_CONSTRAINT_V1_STATE_REGION;
}
static void pointer_constraint_handle_set_region(struct wl_client *client, static void pointer_constraint_handle_set_region(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *region_resource) { struct wl_resource *resource, struct wl_resource *region_resource) {
struct wlr_pointer_constraint_v1 *constraint = struct wlr_pointer_constraint_v1 *constraint =
@ -93,7 +79,13 @@ static void pointer_constraint_handle_set_region(struct wl_client *client,
return; return;
} }
pointer_constraint_set_region(constraint, region_resource); pixman_region32_clear(&constraint->pending.region);
if (region_resource) {
const pixman_region32_t *region = wlr_region_from_resource(region_resource);
pixman_region32_copy(&constraint->pending.region, region);
}
constraint->pending.committed |= WLR_POINTER_CONSTRAINT_V1_STATE_REGION;
} }
static void pointer_constraint_set_cursor_position_hint(struct wl_client *client, static void pointer_constraint_set_cursor_position_hint(struct wl_client *client,
@ -110,27 +102,27 @@ static void pointer_constraint_set_cursor_position_hint(struct wl_client *client
constraint->pending.committed |= WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT; constraint->pending.committed |= WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT;
} }
static void pointer_constraint_commit( // Returns true if the region has changed
struct wlr_pointer_constraint_v1 *constraint) { static bool update_region(struct wlr_pointer_constraint_v1 *constraint) {
pixman_region32_clear(&constraint->region); pixman_region32_t region;
pixman_region32_init(&region);
if (pixman_region32_not_empty(&constraint->current.region)) { if (pixman_region32_not_empty(&constraint->current.region)) {
pixman_region32_intersect(&constraint->region, pixman_region32_intersect(&region,
&constraint->surface->input_region, &constraint->current.region); &constraint->surface->input_region, &constraint->current.region);
} else { } else {
pixman_region32_copy(&constraint->region, pixman_region32_copy(&region, &constraint->surface->input_region);
&constraint->surface->input_region);
} }
if (constraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_REGION) { if (pixman_region32_equal(&region, &constraint->region)) {
wl_signal_emit_mutable(&constraint->events.set_region, NULL); pixman_region32_fini(&region);
return false;
} }
}
static void handle_surface_commit(struct wl_listener *listener, void *data) { pixman_region32_fini(&constraint->region);
struct wlr_pointer_constraint_v1 *constraint = constraint->region = region;
wl_container_of(listener, constraint, surface_commit);
pointer_constraint_commit(constraint); return true;
} }
static void handle_surface_destroy(struct wl_listener *listener, void *data) { static void handle_surface_destroy(struct wl_listener *listener, void *data) {
@ -182,11 +174,20 @@ static void surface_synced_move_state(void *_dst, void *_src) {
src->committed = 0; src->committed = 0;
} }
static void surface_synced_commit(struct wlr_surface_synced *synced) {
struct wlr_pointer_constraint_v1 *constraint = wl_container_of(synced, constraint, synced);
if (update_region(constraint)) {
wl_signal_emit_mutable(&constraint->events.set_region, NULL);
}
}
static const struct wlr_surface_synced_impl surface_synced_impl = { static const struct wlr_surface_synced_impl surface_synced_impl = {
.state_size = sizeof(struct wlr_pointer_constraint_v1_state), .state_size = sizeof(struct wlr_pointer_constraint_v1_state),
.init_state = surface_synced_init_state, .init_state = surface_synced_init_state,
.finish_state = surface_synced_finish_state, .finish_state = surface_synced_finish_state,
.move_state = surface_synced_move_state, .move_state = surface_synced_move_state,
.commit = surface_synced_commit,
}; };
static void pointer_constraint_create(struct wl_client *client, static void pointer_constraint_create(struct wl_client *client,
@ -264,11 +265,11 @@ static void pointer_constraint_create(struct wl_client *client,
pixman_region32_init(&constraint->region); pixman_region32_init(&constraint->region);
pointer_constraint_set_region(constraint, region_resource); if (region_resource) {
pointer_constraint_commit(constraint); pixman_region32_copy(&constraint->current.region,
wlr_region_from_resource(region_resource));
constraint->surface_commit.notify = handle_surface_commit; update_region(constraint);
wl_signal_add(&surface->events.commit, &constraint->surface_commit); }
constraint->surface_destroy.notify = handle_surface_destroy; constraint->surface_destroy.notify = handle_surface_destroy;
wl_signal_add(&surface->events.destroy, &constraint->surface_destroy); wl_signal_add(&surface->events.destroy, &constraint->surface_destroy);