libweston: Add view unmap listener to pointer constraints

Since the logic of pointer constraints assumes a valid view throughout, add a
signal to disable constraints when its current view is unmapped by Weston.

The assumption that a previously unmapped view is valid already leads to the
constraints code crashing. This can happen when attaching a NULL buffer to the
surface and commiting, which effectively unmaps the view with the side effect of
clearing the surface's input region, which is then assumed valid inside
maybe_warp_confined_pointer().

Fixes: #721

Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
(cherry picked from commit e3079393c4)
This commit is contained in:
Sergio Gómez 2023-03-08 17:39:49 -05:00 committed by Marius Vlad
parent d3a636dfb8
commit 08979a1d79
3 changed files with 33 additions and 14 deletions

View File

@ -1289,6 +1289,7 @@ struct weston_view {
struct weston_surface *surface;
struct wl_list surface_link;
struct wl_signal destroy_signal;
struct wl_signal unmap_signal;
/* struct weston_paint_node::view_link */
struct wl_list paint_node_list;
@ -1441,6 +1442,7 @@ struct weston_pointer_constraint {
bool hint_is_pending;
struct wl_listener pointer_destroy_listener;
struct wl_listener view_unmap_listener;
struct wl_listener surface_commit_listener;
struct wl_listener surface_activate_listener;
};

View File

@ -393,6 +393,7 @@ weston_view_create(struct weston_surface *surface)
wl_list_insert(&surface->views, &view->surface_link);
wl_signal_init(&view->destroy_signal);
wl_signal_init(&view->unmap_signal);
wl_list_init(&view->link);
wl_list_init(&view->layer_link.link);
wl_list_init(&view->paint_node_list);
@ -2225,9 +2226,7 @@ weston_view_unmap(struct weston_view *view)
view->output_mask = 0;
weston_surface_assign_output(view->surface);
if (weston_surface_is_mapped(view->surface))
return;
if (!weston_surface_is_mapped(view->surface)) {
wl_list_for_each(seat, &view->surface->compositor->seat_list, link) {
struct weston_touch *touch = weston_seat_get_touch(seat);
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
@ -2241,6 +2240,8 @@ weston_view_unmap(struct weston_view *view)
if (touch && touch->focus == view)
weston_touch_set_focus(touch, NULL);
}
}
weston_signal_emit_mutable(&view->unmap_signal, view);
}
WL_EXPORT void

View File

@ -3655,6 +3655,8 @@ enable_pointer_constraint(struct weston_pointer_constraint *constraint,
constraint->view = view;
pointer_constraint_notify_activated(constraint);
weston_pointer_start_grab(constraint->pointer, &constraint->grab);
wl_signal_add(&constraint->view->unmap_signal,
&constraint->view_unmap_listener);
}
static bool
@ -3669,6 +3671,8 @@ weston_pointer_constraint_disable(struct weston_pointer_constraint *constraint)
constraint->view = NULL;
pointer_constraint_notify_deactivated(constraint);
weston_pointer_end_grab(constraint->grab.pointer);
wl_list_remove(&constraint->view_unmap_listener.link);
wl_list_init(&constraint->view_unmap_listener.link);
}
void
@ -3873,6 +3877,16 @@ pointer_constraint_pointer_destroyed(struct wl_listener *listener, void *data)
weston_pointer_constraint_destroy(constraint);
}
static void
pointer_constraint_view_unmapped(struct wl_listener *listener, void *data)
{
struct weston_pointer_constraint *constraint =
container_of(listener, struct weston_pointer_constraint,
view_unmap_listener);
disable_pointer_constraint(constraint);
}
static void
pointer_constraint_surface_committed(struct wl_listener *listener, void *data)
{
@ -3934,6 +3948,8 @@ weston_pointer_constraint_create(struct weston_surface *surface,
constraint->surface_activate_listener.notify =
pointer_constraint_surface_activate;
constraint->view_unmap_listener.notify =
pointer_constraint_view_unmapped;
constraint->surface_commit_listener.notify =
pointer_constraint_surface_committed;
constraint->pointer_destroy_listener.notify =