From b5281837d676783987c24b4e429e0242a856bcbb Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Thu, 25 Feb 2016 13:58:42 -0500 Subject: [PATCH] wayland: synchronize key repeat with server key repeat is handled client side, which means stalls in the compositor dispatching key release events can lead to fictious repeat events. This commit ties key repeat to a server roundtrip to ensure the client and server are in sync. https://bugzilla.gnome.org/show_bug.cgi?id=757942 --- gdk/wayland/gdkdevice-wayland.c | 37 ++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index a5735d0d3d..dae132b5f7 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -105,6 +105,8 @@ struct _GdkWaylandSeat gboolean have_server_repeat; uint32_t server_repeat_rate; uint32_t server_repeat_delay; + + struct wl_callback *repeat_callback; guint32 repeat_timer; guint32 repeat_key; guint32 repeat_count; @@ -175,6 +177,10 @@ struct _GdkWaylandDeviceManagerClass GdkDeviceManagerClass parent_class; }; +static void deliver_key_event (GdkWaylandDeviceData *device, + uint32_t time_, + uint32_t key, + uint32_t state); GType gdk_wayland_device_manager_get_type (void); G_DEFINE_TYPE (GdkWaylandDeviceManager, @@ -1692,6 +1698,8 @@ stop_key_repeat (GdkWaylandDeviceData *device) g_source_remove (device->repeat_timer); device->repeat_timer = 0; } + + g_clear_pointer (&device->repeat_callback, wl_callback_destroy); } static void @@ -1762,12 +1770,39 @@ deliver_key_event (GdkWaylandDeviceData *device, g_source_set_name_by_id (device->repeat_timer, "[gtk+] keyboard_repeat"); } +static void +sync_after_repeat_callback (void *data, + struct wl_callback *callback, + uint32_t time) +{ + GdkWaylandDeviceData *device = data; + + g_clear_pointer (&device->repeat_callback, wl_callback_destroy); + + deliver_key_event (device, device->time, device->repeat_key, 1); +} + +static const struct wl_callback_listener sync_after_repeat_callback_listener = { + sync_after_repeat_callback +}; + static gboolean keyboard_repeat (gpointer data) { GdkWaylandDeviceData *device = data; + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (device->display); - deliver_key_event (device, device->time, device->repeat_key, 1); + /* Ping the server and wait for the timeout. We won't process + * key repeat until it responds, since a hung server could lead + * to a delayed key release event. We don't want to generate + * repeat events long after the user released the key, just because + * the server is tardy in telling us the user released the key. + */ + device->repeat_callback = wl_display_sync (display->wl_display); + + wl_callback_add_listener (device->repeat_callback, + &sync_after_repeat_callback_listener, + device); return G_SOURCE_REMOVE; }