[gtk+] wayland: synchronize key repeat with server



commit b5281837d676783987c24b4e429e0242a856bcbb
Author: Ray Strode <rstrode redhat com>
Date:   Thu Feb 25 13:58:42 2016 -0500

    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 files changed, 36 insertions(+), 1 deletions(-)
---
diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c
index a5735d0..dae132b 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;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]