1
0
Fork 0

wayland: Preserve serial for all pressed keys

The current code checking keyboard serials for popup/grab
validation is a bit simple, tracking one key press exclusively.
This may break expectations if a client uses a serial
corresponding to a previous key that is still pressed.

Keep track of the serials corresponding to all pressed keys,
and ensure these are reset across focus changes, since the
validity of those serials is already outdated. The code does
still keep track of a single (last) key release serial, since
the validity lifetime is somewhat underdefined with those if
we keep track of multiple keys simultaneously.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3267
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3644>
This commit is contained in:
Carlos Garnacho 2024-03-05 19:28:01 +01:00 committed by Marge Bot
parent 73990f011f
commit 5dfed8a431

View file

@ -74,13 +74,9 @@ struct _MetaWaylandKeyboard
struct wl_listener focus_surface_listener;
uint32_t focus_serial;
uint32_t key_down_keycode;
uint32_t key_down_serial;
uint32_t key_up_keycode;
uint32_t key_up_serial;
struct wl_array pressed_keys;
GHashTable *key_down_serials;
uint32_t last_key_up_serial;
MetaWaylandXkbInfo xkb_info;
enum xkb_state_component mods_changed;
@ -285,13 +281,16 @@ meta_wayland_keyboard_broadcast_key (MetaWaylandKeyboard *keyboard,
if (state)
{
keyboard->key_down_serial = serial;
keyboard->key_down_keycode = key;
g_hash_table_insert (keyboard->key_down_serials,
GUINT_TO_POINTER (key),
GUINT_TO_POINTER (serial));
keyboard->last_key_up_serial = 0;
}
else
{
keyboard->key_up_serial = serial;
keyboard->key_up_keycode = key;
g_hash_table_remove (keyboard->key_down_serials,
GUINT_TO_POINTER (key));
keyboard->last_key_up_serial = serial;
}
wl_resource_for_each (resource, &keyboard->focus_resource_list)
@ -548,6 +547,8 @@ meta_wayland_keyboard_enable (MetaWaylandKeyboard *keyboard)
wl_array_init (&keyboard->pressed_keys);
keyboard->key_down_serials = g_hash_table_new (NULL, NULL);
g_signal_connect (keyboard->settings, "changed",
G_CALLBACK (settings_changed), keyboard);
@ -588,6 +589,9 @@ meta_wayland_keyboard_disable (MetaWaylandKeyboard *keyboard)
wl_list_remove (&keyboard->focus_resource_list);
wl_list_init (&keyboard->focus_resource_list);
g_clear_pointer (&keyboard->key_down_serials, g_hash_table_unref);
keyboard->last_key_up_serial = 0;
wl_array_release (&keyboard->pressed_keys);
g_clear_object (&keyboard->settings);
@ -791,6 +795,8 @@ meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
wl_list_remove (&keyboard->focus_surface_listener.link);
keyboard->focus_surface = NULL;
g_hash_table_remove_all (keyboard->key_down_serials);
keyboard->last_key_up_serial = 0;
}
if (surface != NULL)
@ -891,9 +897,20 @@ gboolean
meta_wayland_keyboard_can_popup (MetaWaylandKeyboard *keyboard,
uint32_t serial)
{
return (keyboard->key_down_serial == serial ||
((keyboard->key_down_keycode == keyboard->key_up_keycode) &&
keyboard->key_up_serial == serial));
GHashTableIter iter;
gpointer value;
if (keyboard->last_key_up_serial == serial)
return TRUE;
g_hash_table_iter_init (&iter, keyboard->key_down_serials);
while (g_hash_table_iter_next (&iter, NULL, &value))
{
if (GPOINTER_TO_UINT (value) == serial)
return TRUE;
}
return FALSE;
}
static void