x11: Query pointer devices' scroll valuators on toplevel enter events
authorCarlos Garnacho <carlosg@gnome.org>
Tue, 23 Jun 2015 16:11:07 +0000 (18:11 +0200)
committerCarlos Garnacho <carlosg@gnome.org>
Wed, 1 Jul 2015 17:40:09 +0000 (19:40 +0200)
We used to "invalidate" scroll valuators, so the next scroll event could
be used as the base for the next scroll deltas. This has the inconvenience
that it invariably consumes the first event received after enter and,
due to interactions with WM overeager passive button grabs, there's a
possibility we don't scroll at all if we receive interleaved "smooth
scroll" XI_Motion events and XI_Enter events (Normally triggered by regular
scroll wheels in mice).

In order to fix this, and at the expense of some sync-call overhead on
XI_Enter events (one XIQueryDevice call per slave device), query the
current scroll valuator state for all the slaves of the entered pointer,
so we do know beforehand the right base values. If new devices are plugged
while the pointer is on top of the client, the initialized scroll values
will match the valuators'.

https://bugzilla.gnome.org/show_bug.cgi?id=750994
https://bugzilla.gnome.org/show_bug.cgi?id=750870

gdk/x11/gdkdevice-xi2.c
gdk/x11/gdkdevicemanager-xi2.c
gdk/x11/gdkprivate-x11.h

index 515840b83a21cfd34245699a1a7d1e030934f280..280eb0d5d2d4fcd559c9776b57c3dcd1cc379ccd 100644 (file)
@@ -40,7 +40,6 @@ struct _ScrollValuator
 {
   guint n_valuator       : 4;
   guint direction        : 4;
-  guint last_value_valid : 1;
   gdouble last_value;
   gdouble increment;
 };
@@ -819,8 +818,8 @@ _gdk_x11_device_xi2_add_scroll_valuator (GdkX11DeviceXI2    *device,
 
   scroll.n_valuator = n_valuator;
   scroll.direction = direction;
-  scroll.last_value_valid = FALSE;
   scroll.increment = increment;
+  scroll.last_value = 0;
 
   g_array_append_val (device->scroll_valuators, scroll);
 }
@@ -851,18 +850,10 @@ _gdk_x11_device_xi2_get_scroll_delta (GdkX11DeviceXI2    *device,
           if (delta_ret)
             *delta_ret = 0;
 
-          if (scroll->last_value_valid)
-            {
-              if (delta_ret)
-                *delta_ret = (valuator_value - scroll->last_value) / scroll->increment;
+          if (delta_ret)
+            *delta_ret = (valuator_value - scroll->last_value) / scroll->increment;
 
-              scroll->last_value = valuator_value;
-            }
-          else
-            {
-              scroll->last_value = valuator_value;
-              scroll->last_value_valid = TRUE;
-            }
+          scroll->last_value = valuator_value;
 
           return TRUE;
         }
@@ -872,17 +863,33 @@ _gdk_x11_device_xi2_get_scroll_delta (GdkX11DeviceXI2    *device,
 }
 
 void
-_gdk_device_xi2_reset_scroll_valuators (GdkX11DeviceXI2 *device)
+_gdk_device_xi2_revalidate_scroll_valuators (GdkX11DeviceXI2 *device)
 {
-  guint i;
+  GdkDisplay *display;
+  XIDeviceInfo *info;
+  gint i, ndevices;
+
+  display = gdk_device_get_display (GDK_DEVICE (device));
+
+  gdk_x11_display_error_trap_push (display);
+  info = XIQueryDevice (GDK_DISPLAY_XDISPLAY (display),
+                        device->device_id, &ndevices);
+  gdk_x11_display_error_trap_pop_ignored (display);
+
+  if (!info)
+    return;
 
   for (i = 0; i < device->scroll_valuators->len; i++)
     {
+      XIValuatorClassInfo *valuator;
       ScrollValuator *scroll;
 
       scroll = &g_array_index (device->scroll_valuators, ScrollValuator, i);
-      scroll->last_value_valid = FALSE;
+      valuator = (XIValuatorClassInfo *) info->classes[scroll->n_valuator + 1];
+      scroll->last_value = valuator->value;
     }
+
+  XIFreeDeviceInfo (info);
 }
 
 void
index e63c35b82b1ff9a3e1256de0e1f1d42f031c3627..5d374a2f3e17db9b834a990e2453d8c8b8a5cd1c 100644 (file)
@@ -824,13 +824,11 @@ handle_device_changed (GdkX11DeviceManagerXI2 *device_manager,
                        XIDeviceChangedEvent   *ev)
 {
   GdkDisplay *display;
-  GdkDevice *device, *source_device;
+  GdkDevice *device;
 
   display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
   device = g_hash_table_lookup (device_manager->id_table,
                                 GUINT_TO_POINTER (ev->deviceid));
-  source_device = g_hash_table_lookup (device_manager->id_table,
-                                       GUINT_TO_POINTER (ev->sourceid));
 
   if (device)
     {
@@ -841,9 +839,6 @@ handle_device_changed (GdkX11DeviceManagerXI2 *device_manager,
 
       g_signal_emit_by_name (G_OBJECT (device), "changed");
     }
-
-  if (source_device)
-    _gdk_device_xi2_reset_scroll_valuators (GDK_X11_DEVICE_XI2 (source_device));
 }
 
 static GdkCrossingMode
@@ -1683,16 +1678,16 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
             xev->detail != XINotifyInferior && xev->mode != XINotifyPassiveUngrab &&
            gdk_window_get_window_type (window) == GDK_WINDOW_TOPLEVEL)
           {
-            if (gdk_device_get_device_type (source_device) != GDK_DEVICE_TYPE_MASTER)
-              _gdk_device_xi2_reset_scroll_valuators (GDK_X11_DEVICE_XI2 (source_device));
+            if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER)
+              _gdk_device_xi2_revalidate_scroll_valuators (GDK_X11_DEVICE_XI2 (source_device));
             else
               {
                 GList *slaves, *l;
 
-                slaves = gdk_device_list_slave_devices (source_device);
+                slaves = gdk_device_list_slave_devices (device);
 
                 for (l = slaves; l; l = l->next)
-                  _gdk_device_xi2_reset_scroll_valuators (GDK_X11_DEVICE_XI2 (l->data));
+                  _gdk_device_xi2_revalidate_scroll_valuators (l->data);
 
                 g_list_free (slaves);
               }
index c2afecf46d158421367fa4ccff3d82af724710f8..459b76e7d9f1cf08ac5850303434369f68dc729e 100644 (file)
@@ -246,6 +246,8 @@ gboolean  _gdk_x11_device_xi2_get_scroll_delta    (GdkX11DeviceXI2    *device,
                                                    GdkScrollDirection *direction_ret,
                                                    gdouble            *delta_ret);
 void     _gdk_device_xi2_reset_scroll_valuators   (GdkX11DeviceXI2    *device);
+void     _gdk_device_xi2_revalidate_scroll_valuators (GdkX11DeviceXI2 *device);
+
 
 gdouble  gdk_x11_device_xi2_get_last_axis_value (GdkX11DeviceXI2 *device,
                                                  gint             n_axis);