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:
parent
73990f011f
commit
5dfed8a431
1 changed files with 30 additions and 13 deletions
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue