[gtk+] devicemanager,xi2: Implement smooth scrolling



commit 147cdd846502d261e2efa02a96ef39d238f8ec4f
Author: Carlos Garnacho <carlosg gnome org>
Date:   Tue Jan 24 00:49:52 2012 +0100

    devicemanager,xi2: Implement smooth scrolling
    
    XInput >= 2.1 allows for implementing smooth scrolling,
    reporting the different scrolling axes as valuators.
    Any change in those will be reported as GdkEventScroll
    events with delta_x/y information.
    
    the older kind of scroll events is still handled, and
    emulated in devices able to provide smooth scrolling,
    setting _gdk_event_set_pointer_emulated() in that case.

 gdk/x11/gdkdevice-xi2.c        |  101 ++++++++++++++++++++++++++++++++++++++++
 gdk/x11/gdkdevicemanager-xi2.c |   99 ++++++++++++++++++++++++++++++++++++++-
 gdk/x11/gdkprivate-x11.h       |    9 ++++
 3 files changed, 206 insertions(+), 3 deletions(-)
---
diff --git a/gdk/x11/gdkdevice-xi2.c b/gdk/x11/gdkdevice-xi2.c
index 4b37a7a..d1139da 100644
--- a/gdk/x11/gdkdevice-xi2.c
+++ b/gdk/x11/gdkdevice-xi2.c
@@ -33,11 +33,22 @@
 
 #endif
 
+typedef struct _ScrollValuator ScrollValuator;
+
+struct _ScrollValuator
+{
+  guint n_valuator       : 4;
+  guint direction        : 4;
+  guint last_value_valid : 1;
+  gdouble last_value;
+};
+
 struct _GdkX11DeviceXI2
 {
   GdkDevice parent_instance;
 
   gint device_id;
+  GArray *scroll_valuators;
 };
 
 struct _GdkX11DeviceXI2Class
@@ -49,6 +60,7 @@ G_DEFINE_TYPE (GdkX11DeviceXI2, gdk_x11_device_xi2, GDK_TYPE_DEVICE)
 
 #ifdef XINPUT_2
 
+static void gdk_x11_device_xi2_finalize     (GObject      *object);
 static void gdk_x11_device_xi2_get_property (GObject      *object,
                                              guint         prop_id,
                                              GValue       *value,
@@ -110,6 +122,7 @@ gdk_x11_device_xi2_class_init (GdkX11DeviceXI2Class *klass)
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
 
+  object_class->finalize = gdk_x11_device_xi2_finalize;
   object_class->get_property = gdk_x11_device_xi2_get_property;
   object_class->set_property = gdk_x11_device_xi2_set_property;
 
@@ -134,6 +147,17 @@ gdk_x11_device_xi2_class_init (GdkX11DeviceXI2Class *klass)
 static void
 gdk_x11_device_xi2_init (GdkX11DeviceXI2 *device)
 {
+  device->scroll_valuators = g_array_new (FALSE, FALSE, sizeof (ScrollValuator));
+}
+
+static void
+gdk_x11_device_xi2_finalize (GObject *object)
+{
+  GdkX11DeviceXI2 *device = GDK_X11_DEVICE_XI2 (object);
+
+  g_array_free (device->scroll_valuators, TRUE);
+
+  G_OBJECT_CLASS (gdk_x11_device_xi2_parent_class)->finalize (object);
 }
 
 static void
@@ -777,6 +801,83 @@ _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
   return state;
 }
 
+void
+_gdk_x11_device_xi2_add_scroll_valuator (GdkX11DeviceXI2    *device,
+                                         guint               n_valuator,
+                                         GdkScrollDirection  direction)
+{
+  ScrollValuator scroll;
+
+  g_return_if_fail (GDK_IS_X11_DEVICE_XI2 (device));
+  g_return_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)));
+
+  scroll.n_valuator = n_valuator;
+  scroll.direction = direction;
+  scroll.last_value_valid = FALSE;
+
+  g_array_append_val (device->scroll_valuators, scroll);
+}
+
+gboolean
+_gdk_x11_device_xi2_get_scroll_delta (GdkX11DeviceXI2    *device,
+                                      guint               n_valuator,
+                                      gdouble             valuator_value,
+                                      GdkScrollDirection *direction_ret,
+                                      gdouble            *delta_ret)
+{
+  guint i;
+
+  g_return_val_if_fail (GDK_IS_X11_DEVICE_XI2 (device), FALSE);
+  g_return_val_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)), FALSE);
+
+  for (i = 0; i < device->scroll_valuators->len; i++)
+    {
+      ScrollValuator *scroll;
+
+      scroll = &g_array_index (device->scroll_valuators, ScrollValuator, i);
+
+      if (scroll->n_valuator == n_valuator)
+        {
+          if (direction_ret)
+            *direction_ret = scroll->direction;
+
+          if (delta_ret)
+            *delta_ret = 0;
+
+          if (scroll->last_value_valid)
+            {
+              if (delta_ret)
+                *delta_ret = valuator_value - scroll->last_value;
+
+              scroll->last_value = valuator_value;
+            }
+          else
+            {
+              scroll->last_value = valuator_value;
+              scroll->last_value_valid = TRUE;
+            }
+
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+void
+_gdk_device_xi2_reset_scroll_valuators (GdkX11DeviceXI2 *device)
+{
+  guint i;
+
+  for (i = 0; i < device->scroll_valuators->len; i++)
+    {
+      ScrollValuator *scroll;
+
+      scroll = &g_array_index (device->scroll_valuators, ScrollValuator, i);
+      scroll->last_value_valid = FALSE;
+    }
+}
+
 gint
 _gdk_x11_device_xi2_get_id (GdkX11DeviceXI2 *device)
 {
diff --git a/gdk/x11/gdkdevicemanager-xi2.c b/gdk/x11/gdkdevicemanager-xi2.c
index cf6a174..2fb66e1 100644
--- a/gdk/x11/gdkdevicemanager-xi2.c
+++ b/gdk/x11/gdkdevicemanager-xi2.c
@@ -241,6 +241,22 @@ translate_device_classes (GdkDisplay      *display,
                                       valuator_info->resolution);
           }
           break;
+#ifdef XINPUT_2_2
+        case XIScrollClass:
+          {
+            XIScrollClassInfo *scroll_info = (XIScrollClassInfo *) class_info;
+            GdkScrollDirection direction;
+
+            if (scroll_info->scroll_type == XIScrollTypeVertical)
+              direction = GDK_SCROLL_DOWN;
+            else
+              direction = GDK_SCROLL_RIGHT;
+
+            _gdk_x11_device_xi2_add_scroll_valuator (GDK_X11_DEVICE_XI2 (device),
+                                                     scroll_info->number,
+                                                     direction);
+          }
+#endif /* XINPUT_2_2 */
         default:
           /* Ignore */
           break;
@@ -1037,6 +1053,47 @@ gdk_x11_device_manager_xi2_translate_core_event (GdkEventTranslator *translator,
 }
 
 static gboolean
+scroll_valuators_changed (GdkX11DeviceXI2 *device,
+                          XIValuatorState *valuators,
+                          gdouble         *dx,
+                          gdouble         *dy)
+{
+  gdouble has_scroll_valuators = FALSE;
+  GdkScrollDirection direction;
+  guint n_axes, i, n_val;
+  gdouble *vals;
+
+  n_axes = gdk_device_get_n_axes (GDK_DEVICE (device));
+  vals = valuators->values;
+  *dx = *dy = 0;
+  n_val = 0;
+
+  for (i = 0; i < MIN (valuators->mask_len * 8, n_axes); i++)
+    {
+      gdouble delta;
+
+      if (!XIMaskIsSet (valuators->mask, i))
+        continue;
+
+      if (_gdk_x11_device_xi2_get_scroll_delta (device, i, vals[n_val],
+                                                &direction, &delta))
+        {
+          has_scroll_valuators = TRUE;
+
+          if (direction == GDK_SCROLL_UP ||
+              direction == GDK_SCROLL_DOWN)
+            *dy = delta;
+          else
+            *dx = delta;
+        }
+
+      n_val++;
+    }
+
+  return has_scroll_valuators;
+}
+
+static gboolean
 gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
                                             GdkDisplay         *display,
                                             GdkEvent           *event,
@@ -1142,8 +1199,11 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
         XIDeviceEvent *xev = (XIDeviceEvent *) ev;
         GdkDevice *source_device;
 
-        if (ev->evtype == XI_ButtonPress &&
+        if (ev->evtype == XI_ButtonRelease &&
             (xev->detail >= 4 && xev->detail <= 7))
+          return FALSE;
+        else if (ev->evtype == XI_ButtonPress &&
+                 (xev->detail >= 4 && xev->detail <= 7))
           {
             /* Button presses of button 4-7 are scroll events */
             event->scroll.type = GDK_SCROLL;
@@ -1163,6 +1223,8 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
             event->scroll.y = (gdouble) xev->event_y;
             event->scroll.x_root = (gdouble) xev->root_x;
             event->scroll.y_root = (gdouble) xev->root_y;
+            event->scroll.delta_x = 0;
+            event->scroll.delta_y = 0;
 
             event->scroll.device = g_hash_table_lookup (device_manager->id_table,
                                                         GUINT_TO_POINTER (xev->deviceid));
@@ -1172,6 +1234,9 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
             gdk_event_set_source_device (event, source_device);
 
             event->scroll.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
+
+            if (xev->flags & XIPointerEmulated)
+              _gdk_event_set_pointer_emulated (event, TRUE);
           }
         else
           {
@@ -1233,6 +1298,36 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
       {
         XIDeviceEvent *xev = (XIDeviceEvent *) ev;
         GdkDevice *source_device;
+        gdouble delta_x, delta_y;
+
+        source_device = g_hash_table_lookup (device_manager->id_table,
+                                             GUINT_TO_POINTER (xev->sourceid));
+
+        if (scroll_valuators_changed (GDK_X11_DEVICE_XI2 (source_device),
+                                      &xev->valuators, &delta_x, &delta_y))
+          {
+            event->scroll.type = GDK_SCROLL;
+            event->scroll.direction = GDK_SCROLL_SMOOTH;
+
+            event->scroll.window = window;
+            event->scroll.time = xev->time;
+            event->scroll.x = (gdouble) xev->event_x;
+            event->scroll.y = (gdouble) xev->event_y;
+            event->scroll.x_root = (gdouble) xev->root_x;
+            event->scroll.y_root = (gdouble) xev->root_y;
+            event->scroll.delta_x = delta_x;
+            event->scroll.delta_y = delta_y;
+
+            event->scroll.device = g_hash_table_lookup (device_manager->id_table,
+                                                        GUINT_TO_POINTER (xev->deviceid));
+
+            gdk_event_set_source_device (event, source_device);
+
+            event->scroll.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
+            break;
+          }
+	else
+          _gdk_device_xi2_reset_scroll_valuators (GDK_X11_DEVICE_XI2 (source_device));
 
         event->motion.type = GDK_MOTION_NOTIFY;
         event->motion.window = window;
@@ -1245,8 +1340,6 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
         event->motion.device = g_hash_table_lookup (device_manager->id_table,
                                                     GINT_TO_POINTER (xev->deviceid));
 
-        source_device = g_hash_table_lookup (device_manager->id_table,
-                                             GUINT_TO_POINTER (xev->sourceid));
         gdk_event_set_source_device (event, source_device);
 
         event->motion.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h
index 98d7732..5eea9a4 100644
--- a/gdk/x11/gdkprivate-x11.h
+++ b/gdk/x11/gdkprivate-x11.h
@@ -255,6 +255,15 @@ gint     _gdk_x11_device_xi2_get_id               (GdkX11DeviceXI2 *device);
 
 GdkDevice * _gdk_x11_device_manager_xi2_lookup    (GdkX11DeviceManagerXI2 *device_manager_xi2,
                                                    gint                    device_id);
+void     _gdk_x11_device_xi2_add_scroll_valuator  (GdkX11DeviceXI2    *device,
+                                                   guint               n_valuator,
+                                                   GdkScrollDirection  direction);
+gboolean  _gdk_x11_device_xi2_get_scroll_delta    (GdkX11DeviceXI2    *device,
+                                                   guint               n_valuator,
+                                                   gdouble             valuator_value,
+                                                   GdkScrollDirection *direction_ret,
+                                                   gdouble            *delta_ret);
+void     _gdk_device_xi2_reset_scroll_valuators   (GdkX11DeviceXI2    *device);
 
 #endif
 



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