libweston: Make weston_seat release safe

Ensure the server can safely handle client requests for wl_seat resource
that have become inert due to weston_seat object release and subsequent
destruction.

The clean-up involves, among other things, unsetting the destroyed
weston_seat object from the user data of wl_seat resources, and handling
this NULL user data case where required.

The list of sites extracting and using weston_seat object from wl_seat
resources which were audited for this patch are:

Legend:
N/A = Not Applicable (not implemented by weston)
FIXED = Fixed in the commit
OK = Already works correctly

== keyboard_shortcuts_inhibit_unstable_v1 ==
[N/A] zwp_keyboard_shortcuts_inhibit_manager_v1.inhibit_shortcuts
== tablet_input_unstable_v{1,2} ==
[N/A] zwp_tablet_manager_v{1,2}.get_tablet_seat
== text_input_unstable_v1 ==
[FIXED] zwp_text_input_v1.activate
[FIXED] zwp_text_input_v1.deactivate
== wl_data_device ==
[FIXED] wl_data_device_manager.get_data_device
[OK] wl_data_device.start_drag
[FIXED] wl_data_device.set_selection
[OK] wl_data_device.release
== wl_shell ==
[FIXED] wl_shell_surface.move
[FIXED] wl_shell_surface.resize
[FIXED] wl_shell_surface.set_popup
== xdg_shell and xdg_shell_unstable_v6 ==
[FIXED] xdg_toplevel.show_window_menu
[FIXED] xdg_toplevel.move
[FIXED] xdg_toplevel.resize
[FIXED] xdg_popup.grab
== xdg_shell_unstable_v5 ==
[FIXED] xdg_shell.get_xdg_popup
[FIXED] xdg_surface.show_window_menu
[FIXED] xdg_surface.move
[FIXED] xdg_surface.resize

Signed-off-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net>
This commit is contained in:
Alexandros Frantzis
2018-02-15 13:07:09 +02:00
committed by Pekka Paalanen
parent 1c3a40edcd
commit 8480d13f6d
6 changed files with 102 additions and 31 deletions
+10 -5
View File
@@ -1167,9 +1167,10 @@ data_device_set_selection(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *source_resource, uint32_t serial)
{
struct weston_seat *seat = wl_resource_get_user_data(resource);
struct weston_data_source *source;
if (!source_resource)
if (!seat || !source_resource)
return;
source = wl_resource_get_user_data(source_resource);
@@ -1182,8 +1183,7 @@ data_device_set_selection(struct wl_client *client,
}
/* FIXME: Store serial and check against incoming serial here. */
weston_seat_set_selection(wl_resource_get_user_data(resource),
source, serial);
weston_seat_set_selection(seat, source, serial);
}
static void
data_device_release(struct wl_client *client, struct wl_resource *resource)
@@ -1296,8 +1296,13 @@ get_data_device(struct wl_client *client,
return;
}
wl_list_insert(&seat->drag_resource_list,
wl_resource_get_link(resource));
if (seat) {
wl_list_insert(&seat->drag_resource_list,
wl_resource_get_link(resource));
} else {
wl_list_init(wl_resource_get_link(resource));
}
wl_resource_set_implementation(resource, &data_device_interface,
seat, unbind_data_device);
}
+43 -18
View File
@@ -2420,13 +2420,10 @@ seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
* This prevents a race between the compositor sending new
* capabilities and the client trying to use the old ones.
*/
struct weston_pointer *pointer = seat->pointer_state;
struct weston_pointer *pointer = seat ? seat->pointer_state : NULL;
struct wl_resource *cr;
struct weston_pointer_client *pointer_client;
if (!pointer)
return;
cr = wl_resource_create(client, &wl_pointer_interface,
wl_resource_get_version(resource), id);
if (cr == NULL) {
@@ -2434,6 +2431,15 @@ seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
return;
}
wl_list_init(wl_resource_get_link(cr));
wl_resource_set_implementation(cr, &pointer_interface, pointer,
unbind_pointer_client_resource);
/* If we don't have a pointer_state, the resource is inert, so there
* is nothing more to set up */
if (!pointer)
return;
pointer_client = weston_pointer_ensure_pointer_client(pointer, client);
if (!pointer_client) {
wl_client_post_no_memory(client);
@@ -2442,8 +2448,6 @@ seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
wl_list_insert(&pointer_client->pointer_resources,
wl_resource_get_link(cr));
wl_resource_set_implementation(cr, &pointer_interface, pointer,
unbind_pointer_client_resource);
if (pointer->focus && pointer->focus->surface->resource &&
wl_resource_get_client(pointer->focus->surface->resource) == client) {
@@ -2507,12 +2511,9 @@ seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
* This prevents a race between the compositor sending new
* capabilities and the client trying to use the old ones.
*/
struct weston_keyboard *keyboard = seat->keyboard_state;
struct weston_keyboard *keyboard = seat ? seat->keyboard_state : NULL;
struct wl_resource *cr;
if (!keyboard)
return;
cr = wl_resource_create(client, &wl_keyboard_interface,
wl_resource_get_version(resource), id);
if (cr == NULL) {
@@ -2520,12 +2521,19 @@ seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
return;
}
wl_list_init(wl_resource_get_link(cr));
wl_resource_set_implementation(cr, &keyboard_interface,
keyboard, unbind_resource);
/* If we don't have a keyboard_state, the resource is inert, so there
* is nothing more to set up */
if (!keyboard)
return;
/* May be moved to focused list later by either
* weston_keyboard_set_focus or directly if this client is already
* focused */
wl_list_insert(&keyboard->resource_list, wl_resource_get_link(cr));
wl_resource_set_implementation(cr, &keyboard_interface,
keyboard, unbind_resource);
if (wl_resource_get_version(cr) >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) {
wl_keyboard_send_repeat_info(cr,
@@ -2587,12 +2595,9 @@ seat_get_touch(struct wl_client *client, struct wl_resource *resource,
* This prevents a race between the compositor sending new
* capabilities and the client trying to use the old ones.
*/
struct weston_touch *touch = seat->touch_state;
struct weston_touch *touch = seat ? seat->touch_state : NULL;
struct wl_resource *cr;
if (!touch)
return;
cr = wl_resource_create(client, &wl_touch_interface,
wl_resource_get_version(resource), id);
if (cr == NULL) {
@@ -2600,6 +2605,15 @@ seat_get_touch(struct wl_client *client, struct wl_resource *resource,
return;
}
wl_list_init(wl_resource_get_link(cr));
wl_resource_set_implementation(cr, &touch_interface,
touch, unbind_resource);
/* If we don't have a touch_state, the resource is inert, so there
* is nothing more to set up */
if (!touch)
return;
if (touch->focus &&
wl_resource_get_client(touch->focus->surface->resource) == client) {
wl_list_insert(&touch->focus_resource_list,
@@ -2608,8 +2622,6 @@ seat_get_touch(struct wl_client *client, struct wl_resource *resource,
wl_list_insert(&touch->resource_list,
wl_resource_get_link(cr));
}
wl_resource_set_implementation(cr, &touch_interface,
touch, unbind_resource);
}
static void
@@ -3087,6 +3099,19 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec,
WL_EXPORT void
weston_seat_release(struct weston_seat *seat)
{
struct wl_resource *resource;
wl_resource_for_each(resource, &seat->base_resource_list) {
wl_resource_set_user_data(resource, NULL);
}
wl_resource_for_each(resource, &seat->drag_resource_list) {
wl_resource_set_user_data(resource, NULL);
}
wl_list_remove(&seat->base_resource_list);
wl_list_remove(&seat->drag_resource_list);
wl_list_remove(&seat->link);
if (seat->saved_kbd_focus)