From 36c2c4a25422c1acb2476b2ac964da980ccbbb66 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Thu, 11 Apr 2024 16:31:16 -0500 Subject: [PATCH] libweston-desktop: Break grabs when a parent surface is destroyed When a client is killed we don't get a clean dismissal of pop-ups in construction order. This can lead to a weston_desktop_surface being destroyed before its child popup is destroyed. The weston_surface is still alive, so the surface destroy listener can't save us. Track grabbed seats in parent surfaces and explicitly break any grabs that depend on them when the surfaces are destroyed. Fixes #870 Signed-off-by: Derek Foreman --- libweston/desktop/internal.h | 6 ++++++ libweston/desktop/seat.c | 36 +++++++++++++++++++++++++++++++++--- libweston/desktop/surface.c | 10 ++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/libweston/desktop/internal.h b/libweston/desktop/internal.h index afbe31adc..1170021c5 100644 --- a/libweston/desktop/internal.h +++ b/libweston/desktop/internal.h @@ -227,6 +227,12 @@ weston_desktop_surface_popup_ungrab(struct weston_desktop_surface *popup, void weston_desktop_surface_popup_dismiss(struct weston_desktop_surface *surface); +struct wl_list * +weston_desktop_surface_get_grab_seat_list(struct weston_desktop_surface *surface); + +void +weston_desktop_seat_end_grabs_on_seats(struct wl_list *list); + struct weston_desktop_surface * weston_desktop_seat_popup_grab_get_topmost_surface(struct weston_desktop_seat *seat); bool diff --git a/libweston/desktop/seat.c b/libweston/desktop/seat.c index b398e79fd..d45719de0 100644 --- a/libweston/desktop/seat.c +++ b/libweston/desktop/seat.c @@ -47,6 +47,7 @@ struct weston_desktop_seat { bool initial_up; struct wl_client *client; struct wl_list surfaces; + struct wl_list grab_surface_link; struct weston_desktop_surface *grab_surface; struct wl_listener grab_surface_destroy_listener; } popup_grab; @@ -387,6 +388,25 @@ weston_desktop_seat_popup_grab_get_topmost_surface(struct weston_desktop_seat *s return weston_desktop_surface_from_grab_link(grab_link); } +static void +weston_desktop_seat_set_grab_surface(struct weston_desktop_seat *seat, + struct weston_desktop_surface *surface) +{ + struct wl_list *list; + + list = weston_desktop_surface_get_grab_seat_list(surface); + wl_list_insert(list->prev, &seat->popup_grab.grab_surface_link); + seat->popup_grab.grab_surface = surface; +} + +static void +weston_desktop_seat_clear_grab_surface(struct weston_desktop_seat *seat) +{ + wl_list_remove(&seat->popup_grab.grab_surface_link); + wl_list_init(&seat->popup_grab.grab_surface_link); + seat->popup_grab.grab_surface = NULL; +} + static void popup_grab_grab_surface_destroy(struct wl_listener *listener, void *data) { @@ -394,7 +414,7 @@ popup_grab_grab_surface_destroy(struct wl_listener *listener, void *data) wl_container_of(listener, seat, popup_grab.grab_surface_destroy_listener); - seat->popup_grab.grab_surface = NULL; + weston_desktop_seat_clear_grab_surface(seat); } bool @@ -447,7 +467,7 @@ weston_desktop_seat_popup_grab_start(struct weston_desktop_seat *seat, struct weston_surface *parent_surface; weston_keyboard_start_grab(keyboard, &seat->popup_grab.keyboard); - seat->popup_grab.grab_surface = parent; + weston_desktop_seat_set_grab_surface(seat, parent); parent_surface = weston_desktop_surface_get_surface(parent); seat->popup_grab.grab_surface_destroy_listener.notify = @@ -516,7 +536,7 @@ weston_desktop_seat_popup_grab_end(struct weston_desktop_seat *seat) seat->popup_grab.client = NULL; if (seat->popup_grab.grab_surface) { - seat->popup_grab.grab_surface = NULL; + weston_desktop_seat_clear_grab_surface(seat); wl_list_remove(&seat->popup_grab.grab_surface_destroy_listener.link); } } @@ -573,3 +593,13 @@ weston_seat_break_desktop_grabs(struct weston_seat *wseat) weston_desktop_seat_popup_grab_end(seat); } + +void +weston_desktop_seat_end_grabs_on_seats(struct wl_list *list) +{ + struct weston_desktop_seat *seat, *next; + + wl_list_for_each_safe(seat, next, list, popup_grab.grab_surface_link) + weston_desktop_seat_popup_grab_end(seat); + +} diff --git a/libweston/desktop/surface.c b/libweston/desktop/surface.c index 44a33c306..28ef55cbe 100644 --- a/libweston/desktop/surface.c +++ b/libweston/desktop/surface.c @@ -75,6 +75,7 @@ struct weston_desktop_surface { struct { struct wl_list grab_link; }; + struct wl_list grabbing_seats; }; static void @@ -175,6 +176,8 @@ weston_desktop_surface_destroy(struct weston_desktop_surface *surface) wl_list_for_each_safe(view, next_view, &surface->view_list, link) weston_desktop_view_destroy(view); + weston_desktop_seat_end_grabs_on_seats(&surface->grabbing_seats); + free(surface->title); free(surface->app_id); @@ -304,6 +307,7 @@ weston_desktop_surface_create(struct weston_desktop *desktop, wl_list_init(&surface->children_link); wl_list_init(&surface->view_list); wl_list_init(&surface->grab_link); + wl_list_init(&surface->grabbing_seats); wl_signal_init(&surface->metadata_signal); @@ -884,6 +888,12 @@ weston_desktop_surface_popup_dismiss(struct weston_desktop_surface *surface) weston_desktop_surface_close(surface); } +struct wl_list * +weston_desktop_surface_get_grab_seat_list(struct weston_desktop_surface *surface) +{ + return &surface->grabbing_seats; +} + WL_EXPORT void weston_desktop_surface_foreach_child(struct weston_desktop_surface *surface, void (* callback)(struct weston_desktop_surface *child,