wayland: Avoid a race in wl_seat capabilities
The way wl_seat capabilities work, by notifying clients of capabilities changes, and clients consequently requesting the relevant interface objects (pointer, keyboard, touch) is inherently racy. On quick VT changes for example, capabilities on the seat will be added and removed, and by the time the client receives the capability change notification and requests the relevant keyboard, pointer or touch, another VT switch might have occurred and the wl_pointer, wl_keyboard or wl_touch already destroyed, leading to a protocol error which kills the client. To avoid this, create the objects when requested regardless of the capabilities. Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1797 Related: https://bugzilla.gnome.org/show_bug.cgi?id=790932 Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/77>
This commit is contained in:
parent
73c6540028
commit
20bb8bf502
@ -109,7 +109,7 @@ meta_wayland_pointer_client_new (void)
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_pointer_client_free (MetaWaylandPointerClient *pointer_client)
|
||||
meta_wayland_pointer_make_resources_inert (MetaWaylandPointerClient *pointer_client)
|
||||
{
|
||||
struct wl_resource *resource, *next;
|
||||
|
||||
@ -141,10 +141,25 @@ meta_wayland_pointer_client_free (MetaWaylandPointerClient *pointer_client)
|
||||
wl_list_init (wl_resource_get_link (resource));
|
||||
wl_resource_set_user_data (resource, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_pointer_client_free (MetaWaylandPointerClient *pointer_client)
|
||||
{
|
||||
meta_wayland_pointer_make_resources_inert (pointer_client);
|
||||
g_free (pointer_client);
|
||||
}
|
||||
|
||||
static void
|
||||
make_resources_inert_foreach (gpointer key,
|
||||
gpointer value,
|
||||
gpointer data)
|
||||
{
|
||||
MetaWaylandPointerClient *pointer_client = value;
|
||||
|
||||
meta_wayland_pointer_make_resources_inert (pointer_client);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_wayland_pointer_client_is_empty (MetaWaylandPointerClient *pointer_client)
|
||||
{
|
||||
@ -158,8 +173,6 @@ MetaWaylandPointerClient *
|
||||
meta_wayland_pointer_get_pointer_client (MetaWaylandPointer *pointer,
|
||||
struct wl_client *client)
|
||||
{
|
||||
if (!pointer->pointer_clients)
|
||||
return NULL;
|
||||
return g_hash_table_lookup (pointer->pointer_clients, client);
|
||||
}
|
||||
|
||||
@ -475,10 +488,6 @@ meta_wayland_pointer_enable (MetaWaylandPointer *pointer)
|
||||
MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
|
||||
ClutterSeat *clutter_seat;
|
||||
|
||||
pointer->pointer_clients =
|
||||
g_hash_table_new_full (NULL, NULL, NULL,
|
||||
(GDestroyNotify) meta_wayland_pointer_client_free);
|
||||
|
||||
pointer->cursor_surface = NULL;
|
||||
|
||||
clutter_seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
|
||||
@ -508,6 +517,10 @@ meta_wayland_pointer_disable (MetaWaylandPointer *pointer)
|
||||
ClutterBackend *clutter_backend = clutter_get_default_backend ();
|
||||
ClutterSeat *clutter_seat = clutter_backend_get_default_seat (clutter_backend);
|
||||
|
||||
g_hash_table_foreach (pointer->pointer_clients,
|
||||
make_resources_inert_foreach,
|
||||
NULL);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (cursor_tracker,
|
||||
(gpointer) meta_wayland_pointer_on_cursor_changed,
|
||||
pointer);
|
||||
@ -531,7 +544,6 @@ meta_wayland_pointer_disable (MetaWaylandPointer *pointer)
|
||||
meta_wayland_pointer_set_focus (pointer, NULL);
|
||||
meta_wayland_pointer_set_current (pointer, NULL);
|
||||
|
||||
g_clear_pointer (&pointer->pointer_clients, g_hash_table_unref);
|
||||
pointer->cursor_surface = NULL;
|
||||
}
|
||||
|
||||
@ -1356,11 +1368,28 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer)
|
||||
pointer->default_grab.interface = &default_pointer_grab_interface;
|
||||
pointer->default_grab.pointer = pointer;
|
||||
pointer->grab = &pointer->default_grab;
|
||||
pointer->pointer_clients =
|
||||
g_hash_table_new_full (NULL, NULL, NULL,
|
||||
(GDestroyNotify) meta_wayland_pointer_client_free);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_pointer_finalize (GObject *object)
|
||||
{
|
||||
MetaWaylandPointer *pointer = META_WAYLAND_POINTER (object);
|
||||
|
||||
g_clear_pointer (&pointer->pointer_clients, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (meta_wayland_pointer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_pointer_class_init (MetaWaylandPointerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_wayland_pointer_finalize;
|
||||
|
||||
signals[FOCUS_SURFACE_CHANGED] = g_signal_new ("focus-surface-changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
|
@ -46,8 +46,7 @@ seat_get_pointer (struct wl_client *client,
|
||||
MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
|
||||
MetaWaylandPointer *pointer = seat->pointer;
|
||||
|
||||
if (meta_wayland_seat_has_pointer (seat))
|
||||
meta_wayland_pointer_create_new_resource (pointer, client, resource, id);
|
||||
meta_wayland_pointer_create_new_resource (pointer, client, resource, id);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -58,8 +57,7 @@ seat_get_keyboard (struct wl_client *client,
|
||||
MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
|
||||
MetaWaylandKeyboard *keyboard = seat->keyboard;
|
||||
|
||||
if (meta_wayland_seat_has_keyboard (seat))
|
||||
meta_wayland_keyboard_create_new_resource (keyboard, client, resource, id);
|
||||
meta_wayland_keyboard_create_new_resource (keyboard, client, resource, id);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -70,8 +68,7 @@ seat_get_touch (struct wl_client *client,
|
||||
MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
|
||||
MetaWaylandTouch *touch = seat->touch;
|
||||
|
||||
if (meta_wayland_seat_has_touch (seat))
|
||||
meta_wayland_touch_create_new_resource (touch, client, resource, id);
|
||||
meta_wayland_touch_create_new_resource (touch, client, resource, id);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -521,16 +521,8 @@ meta_wayland_touch_create_new_resource (MetaWaylandTouch *touch,
|
||||
struct wl_resource *seat_resource,
|
||||
uint32_t id)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
|
||||
struct wl_resource *cr;
|
||||
|
||||
if (!meta_wayland_seat_has_touch (seat))
|
||||
{
|
||||
wl_resource_post_error (seat_resource, WL_DISPLAY_ERROR_INVALID_METHOD,
|
||||
"Cannot retrieve touch interface without touch capability");
|
||||
return;
|
||||
}
|
||||
|
||||
cr = wl_resource_create (client, &wl_touch_interface, wl_resource_get_version (seat_resource), id);
|
||||
wl_resource_set_implementation (cr, &touch_interface, touch, unbind_resource);
|
||||
wl_list_insert (&touch->resource_list, wl_resource_get_link (cr));
|
||||
|
Loading…
Reference in New Issue
Block a user