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 <derek.foreman@collabora.com>
This commit is contained in:
Derek Foreman 2024-04-11 16:31:16 -05:00
parent bedd171d5d
commit 36c2c4a254
3 changed files with 49 additions and 3 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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,