clutter/evdev: Dispatch libinput before generating key repeat events

Since both the libinput event source and the key repeat timer have the
same priority, the order in which both handlers are called is
arbitrary if both sources are ready on the same poll return. This
means that sometimes we generate key repeats when there's already a
real key event queued on libinput that would cancel the repeat timer
if only it was processed before.

One solution would be lowering the repeat timer source priority a
notch lower than the libinput source but that would mean that a steady
stream of events from libinput (e.g. pointer device motion) would
prevent any key repeats to happen.

Instead, we can fix this problem by trying to dispatch libinput from
the key repeat timer and checking if the timer source has been
destroyed before generating more key repeats.

https://bugzilla.gnome.org/show_bug.cgi?id=774989
This commit is contained in:
Rui Matos 2016-11-25 12:44:56 +01:00
parent 2166a496fe
commit 18a4b9fb2c
3 changed files with 14 additions and 0 deletions

View File

@ -2261,6 +2261,12 @@ _clutter_device_manager_evdev_acquire_device_id (ClutterDeviceManagerEvdev *mana
return next_id; return next_id;
} }
void
_clutter_device_manager_evdev_dispatch (ClutterDeviceManagerEvdev *manager_evdev)
{
dispatch_libinput (manager_evdev);
}
static int static int
compare_ids (gconstpointer a, compare_ids (gconstpointer a,
gconstpointer b) gconstpointer b)

View File

@ -76,6 +76,8 @@ void _clutter_device_manager_evdev_constrain_pointer (ClutterDeviceManagerEvdev
float *new_x, float *new_x,
float *new_y); float *new_y);
void _clutter_device_manager_evdev_dispatch (ClutterDeviceManagerEvdev *manager_evdev);
static inline guint64 static inline guint64
us (guint64 us) us (guint64 us)
{ {

View File

@ -186,6 +186,12 @@ keyboard_repeat (gpointer data)
ClutterSeatEvdev *seat = data; ClutterSeatEvdev *seat = data;
GSource *source; GSource *source;
/* There might be events queued in libinput that could cancel the
repeat timer. */
_clutter_device_manager_evdev_dispatch (seat->manager_evdev);
if (!seat->repeat_timer)
return G_SOURCE_REMOVE;
g_return_val_if_fail (seat->repeat_device != NULL, G_SOURCE_REMOVE); g_return_val_if_fail (seat->repeat_device != NULL, G_SOURCE_REMOVE);
source = g_main_context_find_source_by_id (NULL, seat->repeat_timer); source = g_main_context_find_source_by_id (NULL, seat->repeat_timer);