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:
parent
bedd171d5d
commit
36c2c4a254
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue