[gtk/gtk-3-24: 1/3] gdk/x11: Implement XI2.4 touchpad gesture support




commit a1a2f8ab56b460fcfe9737be5743ec8176f04996
Author: Povilas Kanapickas <povilas radix lt>
Date:   Thu Dec 2 23:19:09 2021 +0200

    gdk/x11: Implement XI2.4 touchpad gesture support

 config.h.meson                 |   3 +
 config.h.win32.in              |   3 +
 configure.ac                   |  12 ++-
 demos/gtk-demo/gestures.c      |   2 +-
 gdk/gdkseatdefault.c           |   3 +-
 gdk/gdkwindow.c                |   2 +-
 gdk/x11/gdkdevice-xi2.c        |  45 +++++++++++-
 gdk/x11/gdkdevicemanager-x11.c |   2 +-
 gdk/x11/gdkdevicemanager-xi2.c | 161 ++++++++++++++++++++++++++++++++++++++++-
 gdk/x11/gdkprivate-x11.h       |   5 ++
 meson.build                    |   8 ++
 11 files changed, 239 insertions(+), 7 deletions(-)
---
diff --git a/config.h.meson b/config.h.meson
index eb347ae538..ce2aeb2946 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -244,6 +244,9 @@
 /* Define to 1 if XInput 2.2 is available */
 #mesondefine XINPUT_2_2
 
+/* Define to 1 if XInput 2.4 is available */
+#mesondefine XINPUT_2_4
+
 /* Enable large inode numbers on Mac OS X 10.5.  */
 #ifndef _DARWIN_USE_64_BIT_INODE
 # define _DARWIN_USE_64_BIT_INODE 1
diff --git a/config.h.win32.in b/config.h.win32.in
index 9bbf65fe10..9666b1b872 100644
--- a/config.h.win32.in
+++ b/config.h.win32.in
@@ -300,6 +300,9 @@
 /* Define to 1 if XInput 2.2 is available */
 /* #undef XINPUT_2_2 */
 
+/* Define to 1 if XInput 2.4 is available */
+/* #undef XINPUT_2_4 */
+
 /* Define to 1 if the X Window System is missing or not being used. */
 /* #undef X_DISPLAY_MISSING */
 
diff --git a/configure.ac b/configure.ac
index 412ddbf6d7..cc141e04ea 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1167,13 +1167,23 @@ if test "x$enable_x11_backend" = xyes; then
                        AC_DEFINE(XINPUT_2_2, 1, [Define to 1 if XInput 2.2 is available]),
                        have_xinput2_2=no,
                        [[#include <X11/extensions/XInput2.h>]])])
-    LIBS="$gtk_save_LIBS"
 
     if test "x$have_xinput2_2" = "xyes"; then
       X_EXTENSIONS="$X_EXTENSIONS XI2.2"
     else
       X_EXTENSIONS="$X_EXTENSIONS XI2"
     fi
+
+    AC_CHECK_MEMBER([XIGesturePinchEvent.type],
+                    have_xinput2_4=yes
+                    AC_DEFINE(XINPUT_2_4, 1, [Define to 1 if XInput 2.4 is available]),
+                    have_xinput2_4=no,
+                    [[#include <X11/extensions/XInput2.h>]])
+
+    if test "x$have_xinput2_4" = "xyes"; then
+      X_EXTENSIONS="$X_EXTENSIONS XI2.4"
+    fi
+    LIBS="$gtk_save_LIBS"
   fi
 
   AS_IF([test "x$have_xinput2" != "xyes"],
diff --git a/demos/gtk-demo/gestures.c b/demos/gtk-demo/gestures.c
index 9632e7d665..6d3ceca521 100644
--- a/demos/gtk-demo/gestures.c
+++ b/demos/gtk-demo/gestures.c
@@ -160,7 +160,7 @@ do_gestures (GtkWidget *do_widget)
       gtk_container_add (GTK_CONTAINER (window), drawing_area);
       gtk_widget_add_events (drawing_area,
                              GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
-                             GDK_POINTER_MOTION_MASK | GDK_TOUCH_MASK);
+                             GDK_POINTER_MOTION_MASK | GDK_TOUCH_MASK | GDK_TOUCHPAD_GESTURE_MASK);
 
       g_signal_connect (drawing_area, "draw",
                         G_CALLBACK (drawing_area_draw), NULL);
diff --git a/gdk/gdkseatdefault.c b/gdk/gdkseatdefault.c
index 98ea6335fa..4dd4dca99b 100644
--- a/gdk/gdkseatdefault.c
+++ b/gdk/gdkseatdefault.c
@@ -43,7 +43,8 @@ struct _GdkSeatDefaultPrivate
                          GDK_ENTER_NOTIFY_MASK |                        \
                          GDK_LEAVE_NOTIFY_MASK |                        \
                          GDK_PROXIMITY_IN_MASK |                        \
-                         GDK_PROXIMITY_OUT_MASK)
+                         GDK_PROXIMITY_OUT_MASK |                       \
+                         GDK_TOUCHPAD_GESTURE_MASK)
 
 G_DEFINE_TYPE_WITH_PRIVATE (GdkSeatDefault, gdk_seat_default, GDK_TYPE_SEAT)
 
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 2de8ba4a09..2d0ed0f963 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -1286,7 +1286,7 @@ get_native_device_event_mask (GdkWindow *private,
       if (gdk_window_is_toplevel (private) ||
           mask & GDK_BUTTON_PRESS_MASK)
         mask |=
-          GDK_TOUCH_MASK |
+          GDK_TOUCH_MASK | GDK_TOUCHPAD_GESTURE_MASK |
           GDK_POINTER_MOTION_MASK |
           GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
           GDK_SCROLL_MASK;
diff --git a/gdk/x11/gdkdevice-xi2.c b/gdk/x11/gdkdevice-xi2.c
index cd1849c51e..f089a56b5e 100644
--- a/gdk/x11/gdkdevice-xi2.c
+++ b/gdk/x11/gdkdevice-xi2.c
@@ -61,7 +61,6 @@ struct _GdkX11DeviceXI2Class
 
 G_DEFINE_TYPE (GdkX11DeviceXI2, gdk_x11_device_xi2, GDK_TYPE_DEVICE)
 
-
 static void gdk_x11_device_xi2_finalize     (GObject      *object);
 static void gdk_x11_device_xi2_get_property (GObject      *object,
                                              guint         prop_id,
@@ -762,6 +761,20 @@ _gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *device_manager
     }
 #endif /* XINPUT_2_2 */
 
+#ifdef XINPUT_2_4
+  /* XInput 2.4 includes multitouch support */
+  if (minor >= 4 &&
+      event_mask & GDK_TOUCHPAD_GESTURE_MASK)
+    {
+      XISetMask (mask, XI_GesturePinchBegin);
+      XISetMask (mask, XI_GesturePinchUpdate);
+      XISetMask (mask, XI_GesturePinchEnd);
+      XISetMask (mask, XI_GestureSwipeBegin);
+      XISetMask (mask, XI_GestureSwipeUpdate);
+      XISetMask (mask, XI_GestureSwipeEnd);
+    }
+#endif
+
   return mask;
 }
 
@@ -810,6 +823,36 @@ _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
   return state;
 }
 
+#ifdef XINPUT_2_4
+guint
+_gdk_x11_device_xi2_gesture_type_to_phase (int evtype, int flags)
+{
+  switch (evtype)
+    {
+    case XI_GesturePinchBegin:
+    case XI_GestureSwipeBegin:
+      return GDK_TOUCHPAD_GESTURE_PHASE_BEGIN;
+
+    case XI_GesturePinchUpdate:
+    case XI_GestureSwipeUpdate:
+      return GDK_TOUCHPAD_GESTURE_PHASE_UPDATE;
+
+    case XI_GesturePinchEnd:
+      if (flags & XIGesturePinchEventCancelled)
+        return GDK_TOUCHPAD_GESTURE_PHASE_CANCEL;
+      return GDK_TOUCHPAD_GESTURE_PHASE_END;
+
+    case XI_GestureSwipeEnd:
+      if (flags & XIGestureSwipeEventCancelled)
+        return GDK_TOUCHPAD_GESTURE_PHASE_CANCEL;
+      return GDK_TOUCHPAD_GESTURE_PHASE_END;
+    default:
+      g_assert_not_reached ();
+      return GDK_TOUCHPAD_GESTURE_PHASE_END;
+    }
+}
+#endif /* XINPUT_2_4 */
+
 void
 _gdk_x11_device_xi2_add_scroll_valuator (GdkX11DeviceXI2    *device,
                                          guint               n_valuator,
diff --git a/gdk/x11/gdkdevicemanager-x11.c b/gdk/x11/gdkdevicemanager-x11.c
index 2e7ea1f41b..1ad3323cc4 100644
--- a/gdk/x11/gdkdevicemanager-x11.c
+++ b/gdk/x11/gdkdevicemanager-x11.c
@@ -48,7 +48,7 @@ _gdk_x11_device_manager_new (GdkDisplay *display)
           int major, minor;
 
           major = 2;
-         minor = 3;
+          minor = 4;
 
           if (!_gdk_disable_multidevice &&
               XIQueryVersion (xdisplay, &major, &minor) != BadRequest)
diff --git a/gdk/x11/gdkdevicemanager-xi2.c b/gdk/x11/gdkdevicemanager-xi2.c
index 00e64d2a84..193dd47beb 100644
--- a/gdk/x11/gdkdevicemanager-xi2.c
+++ b/gdk/x11/gdkdevicemanager-xi2.c
@@ -1335,6 +1335,26 @@ get_event_window (GdkEventTranslator *translator,
           }
       }
       break;
+#ifdef XINPUT_2_4
+    case XI_GesturePinchBegin:
+    case XI_GesturePinchUpdate:
+    case XI_GesturePinchEnd:
+      {
+        XIGesturePinchEvent *xev = (XIGesturePinchEvent *) ev;
+
+        window = gdk_x11_window_lookup_for_display (display, xev->event);
+      }
+      break;
+    case XI_GestureSwipeBegin:
+    case XI_GestureSwipeUpdate:
+    case XI_GestureSwipeEnd:
+      {
+        XIGestureSwipeEvent *xev = (XIGestureSwipeEvent *) ev;
+
+        window = gdk_x11_window_lookup_for_display (display, xev->event);
+      }
+      break;
+#endif /* XINPUT_2_4 */
     case XI_Enter:
     case XI_Leave:
     case XI_FocusIn:
@@ -1950,6 +1970,144 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
       break;
 #endif  /* XINPUT_2_2 */
 
+#ifdef XINPUT_2_4
+    case XI_GesturePinchBegin:
+    case XI_GesturePinchUpdate:
+    case XI_GesturePinchEnd:
+      {
+        XIGesturePinchEvent *xev = (XIGesturePinchEvent *) ev;
+
+#ifdef G_ENABLE_DEBUG
+        const char* event_name = "";
+        switch (xev->evtype)
+          {
+          case XI_GesturePinchBegin:
+            event_name = "begin";
+            break;
+          case XI_GesturePinchUpdate:
+            event_name = "update";
+            break;
+          case XI_GesturePinchEnd:
+            event_name = "end";
+            break;
+          }
+#endif
+
+        GDK_NOTE(EVENTS,
+                 g_message ("pinch gesture %s:\twindow %ld\n\tfinger_count: %u%s",
+                            event_name,
+                            xev->event,
+                            xev->detail,
+                            xev->flags & XIGesturePinchEventCancelled ? "\n\tcancelled" : ""));
+
+        event->touchpad_pinch.type = GDK_TOUCHPAD_PINCH;
+        event->touchpad_pinch.phase =
+            _gdk_x11_device_xi2_gesture_type_to_phase (xev->evtype, xev->flags);
+        event->touchpad_pinch.window = window;
+        event->touchpad_pinch.time = xev->time;
+        event->touchpad_pinch.x = (gdouble) xev->event_x / scale;
+        event->touchpad_pinch.y = (gdouble) xev->event_y / scale;
+        event->touchpad_pinch.x_root = (gdouble) xev->root_x / scale;
+        event->touchpad_pinch.y_root = (gdouble) xev->root_y / scale;
+        event->touchpad_pinch.dx = xev->delta_x;
+        event->touchpad_pinch.dy = xev->delta_y;
+        event->touchpad_pinch.scale = xev->scale;
+        event->touchpad_pinch.angle_delta = xev->delta_angle * G_PI / 180;
+        event->touchpad_pinch.n_fingers = xev->detail;
+
+        device = g_hash_table_lookup (device_manager->id_table,
+                                      GUINT_TO_POINTER (xev->deviceid));
+        gdk_event_set_device (event, device);
+
+        source_device = g_hash_table_lookup (device_manager->id_table,
+                                             GUINT_TO_POINTER (xev->sourceid));
+        gdk_event_set_source_device (event, source_device);
+        gdk_event_set_seat (event, gdk_device_get_seat (device));
+
+        event->touchpad_pinch.state = _gdk_x11_device_xi2_translate_state (&xev->mods, NULL, &xev->group);
+
+        if (xev->evtype == XI_GesturePinchBegin || xev->evtype == XI_GesturePinchEnd)
+          {
+            if (!set_screen_from_root (display, event, xev->root))
+              {
+                return_val = FALSE;
+                break;
+              }
+          }
+
+        if (ev->evtype == XI_GesturePinchBegin)
+          set_user_time (event);
+      }
+      break;
+
+    case XI_GestureSwipeBegin:
+    case XI_GestureSwipeUpdate:
+    case XI_GestureSwipeEnd:
+      {
+        XIGestureSwipeEvent *xev = (XIGestureSwipeEvent *) ev;
+
+#ifdef G_ENABLE_DEBUG
+        const char* event_name = "";
+        switch (xev->evtype)
+          {
+          case XI_GestureSwipeBegin:
+            event_name = "begin";
+            break;
+          case XI_GestureSwipeUpdate:
+            event_name = "update";
+            break;
+          case XI_GestureSwipeEnd:
+            event_name = "end";
+            break;
+          }
+#endif
+
+        GDK_NOTE(EVENTS,
+                 g_message ("swipe gesture %s:\twindow %ld\n\tfinger_count: %u%s",
+                            event_name,
+                            xev->event,
+                            xev->detail,
+                            xev->flags & XIGestureSwipeEventCancelled ? "\n\tcancelled" : ""));
+
+        event->touchpad_swipe.type = GDK_TOUCHPAD_SWIPE;
+        event->touchpad_pinch.phase =
+            _gdk_x11_device_xi2_gesture_type_to_phase (xev->evtype, xev->flags);
+        event->touchpad_swipe.window = window;
+        event->touchpad_swipe.time = xev->time;
+        event->touchpad_swipe.x = (gdouble) xev->event_x / scale;
+        event->touchpad_swipe.y = (gdouble) xev->event_y / scale;
+        event->touchpad_swipe.x_root = (gdouble) xev->root_x / scale;
+        event->touchpad_swipe.y_root = (gdouble) xev->root_y / scale;
+        event->touchpad_swipe.dx = xev->delta_x;
+        event->touchpad_swipe.dy = xev->delta_y;
+        event->touchpad_swipe.n_fingers = xev->detail;
+
+        device = g_hash_table_lookup (device_manager->id_table,
+                                      GUINT_TO_POINTER (xev->deviceid));
+        gdk_event_set_device (event, device);
+
+        source_device = g_hash_table_lookup (device_manager->id_table,
+                                             GUINT_TO_POINTER (xev->sourceid));
+        gdk_event_set_source_device (event, source_device);
+        gdk_event_set_seat (event, gdk_device_get_seat (device));
+
+        event->touchpad_swipe.state = _gdk_x11_device_xi2_translate_state (&xev->mods, NULL, &xev->group);
+
+        if (xev->evtype == XI_GestureSwipeBegin || xev->evtype == XI_GestureSwipeEnd)
+          {
+            if (!set_screen_from_root (display, event, xev->root))
+              {
+                return_val = FALSE;
+                break;
+              }
+          }
+
+        if (ev->evtype == XI_GestureSwipeBegin)
+          set_user_time (event);
+      }
+      break;
+#endif  /* XINPUT_2_4 */
+
     case XI_Enter:
     case XI_Leave:
       {
@@ -2078,7 +2236,8 @@ gdk_x11_device_manager_xi2_get_handled_events (GdkEventTranslator *translator)
           GDK_BUTTON3_MOTION_MASK |
           GDK_BUTTON_MOTION_MASK |
           GDK_FOCUS_CHANGE_MASK |
-          GDK_TOUCH_MASK);
+          GDK_TOUCH_MASK |
+          GDK_TOUCHPAD_GESTURE_MASK);
 }
 
 static void
diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h
index beb84c2ab5..72039585e4 100644
--- a/gdk/x11/gdkprivate-x11.h
+++ b/gdk/x11/gdkprivate-x11.h
@@ -230,6 +230,11 @@ guchar * _gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *devic
 guint    _gdk_x11_device_xi2_translate_state      (XIModifierState *mods_state,
                                                    XIButtonState   *buttons_state,
                                                    XIGroupState    *group_state);
+
+#ifdef XINPUT_2_4
+guint _gdk_x11_device_xi2_gesture_type_to_phase (int evtype, int flags);
+#endif
+
 gint     _gdk_x11_device_xi2_get_id               (GdkX11DeviceXI2 *device);
 void     _gdk_device_xi2_unset_scroll_valuators   (GdkX11DeviceXI2 *device);
 
diff --git a/meson.build b/meson.build
index 82123e7a61..8e4c224436 100644
--- a/meson.build
+++ b/meson.build
@@ -629,6 +629,14 @@ if x11_enabled
     endif
   endif
 
+  has_gesture_pinch_event = cc.has_member('XIGesturePinchEvent', 'type', dependencies: xi_dep,
+                                          prefix: '''#include <X11/Xlib.h>
+                                                     #include <X11/extensions/XInput2.h>''')
+  if has_gesture_pinch_event
+    cdata.set('XINPUT_2_4', 1)
+  endif
+
+
   enable_xinerama = get_option('xinerama')
   if enable_xinerama != 'no'
     want_xinerama = enable_xinerama == 'yes'


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