[clutter] x11: Add support for touch events



commit 09a317d23dc7d4785c31f8393b54392b5f473f60
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Mon Mar 19 14:28:34 2012 +0000

    x11: Add support for touch events
    
    For the time being, we just relay everything we get from the X server to
    the Clutter application.

 clutter/clutter-event-private.h          |    3 +
 clutter/clutter-event.c                  |   12 ++
 clutter/x11/clutter-backend-x11.c        |    5 +
 clutter/x11/clutter-backend-x11.h        |    1 +
 clutter/x11/clutter-device-manager-xi2.c |  177 +++++++++++++++++++++++++++++-
 clutter/x11/clutter-input-device-xi2.c   |   10 ++
 6 files changed, 207 insertions(+), 1 deletions(-)
---
diff --git a/clutter/clutter-event-private.h b/clutter/clutter-event-private.h
index 1b3f9bb..eeb1080 100644
--- a/clutter/clutter-event-private.h
+++ b/clutter/clutter-event-private.h
@@ -5,6 +5,9 @@
 
 G_BEGIN_DECLS
 
+void            _clutter_event_set_pointer_emulated     (ClutterEvent       *event,
+                                                         gboolean            is_emulated);
+
 /* Reinjecting queued events for processing */
 void            _clutter_process_event                  (ClutterEvent       *event);
 
diff --git a/clutter/clutter-event.c b/clutter/clutter-event.c
index 1e2d251..fb5587e 100644
--- a/clutter/clutter-event.c
+++ b/clutter/clutter-event.c
@@ -53,6 +53,8 @@ typedef struct _ClutterEventPrivate {
   gdouble delta_y;
 
   gpointer platform_data;
+
+  guint is_pointer_emulated : 1;
 } ClutterEventPrivate;
 
 static GHashTable *all_events = NULL;
@@ -108,6 +110,16 @@ _clutter_event_set_platform_data (ClutterEvent *event,
   ((ClutterEventPrivate *) event)->platform_data = data;
 }
 
+void
+_clutter_event_set_pointer_emulated (ClutterEvent *event,
+                                     gboolean      is_emulated)
+{
+  if (!is_event_allocated (event))
+    return;
+
+  ((ClutterEventPrivate *) event)->is_pointer_emulated = !!is_emulated;
+}
+
 /**
  * clutter_event_type:
  * @event: a #ClutterEvent
diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c
index 7cd6a78..be02d34 100644
--- a/clutter/x11/clutter-backend-x11.c
+++ b/clutter/x11/clutter-backend-x11.c
@@ -255,6 +255,8 @@ clutter_backend_x11_create_device_manager (ClutterBackendX11 *backend_x11)
                                   "backend", backend_x11,
                                   "opcode", event_base,
                                   NULL);
+
+                  backend_x11->xi_minor = minor;
                 }
               else
 #endif /* HAVE_XINPUT_2 */
@@ -267,6 +269,7 @@ clutter_backend_x11_create_device_manager (ClutterBackendX11 *backend_x11)
                                   "event-base", first_event,
                                   NULL);
 
+                  backend_x11->xi_minor = -1;
                 }
             }
         }
@@ -279,6 +282,8 @@ clutter_backend_x11_create_device_manager (ClutterBackendX11 *backend_x11)
             g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_X11,
                           "backend", backend_x11,
                           NULL);
+
+          backend_x11->xi_minor = -1;
         }
 
       backend = CLUTTER_BACKEND (backend_x11);
diff --git a/clutter/x11/clutter-backend-x11.h b/clutter/x11/clutter-backend-x11.h
index 2922733..2ffe2f6 100644
--- a/clutter/x11/clutter-backend-x11.h
+++ b/clutter/x11/clutter-backend-x11.h
@@ -100,6 +100,7 @@ struct _ClutterBackendX11
 
   ClutterDeviceManager *device_manager;
   gboolean has_xinput;
+  int xi_minor;
 
   XSettingsClient *xsettings;
   Window xsettings_xwin;
diff --git a/clutter/x11/clutter-device-manager-xi2.c b/clutter/x11/clutter-device-manager-xi2.c
index da669bb..aad69c7 100644
--- a/clutter/x11/clutter-device-manager-xi2.c
+++ b/clutter/x11/clutter-device-manager-xi2.c
@@ -186,18 +186,61 @@ translate_device_classes (Display             *xdisplay,
     }
 }
 
+static gboolean
+is_touch_device (XIAnyClassInfo         **classes,
+                 guint                    n_classes,
+                 ClutterInputDeviceType  *device_type,
+                 guint                   *n_touch_points)
+{
+#ifdef XINPUT_2_2
+  guint i;
+
+  for (i = 0; i < n_classes; i++)
+    {
+      XITouchClassInfo *class = (XITouchClassInfo *) classes[i];
+
+      if (class->type != XITouchClass)
+        continue;
+
+      if (class->num_touches > 0)
+        {
+          if (class->mode == XIDirectTouch)
+            *device_type = CLUTTER_TOUCHSCREEN_DEVICE;
+          else if (class->mode == XIDependentTouch)
+            *device_type = CLUTTER_TOUCHPAD_DEVICE;
+          else
+            continue;
+
+          *n_touch_points = class->num_touches;
+
+          return TRUE;
+        }
+    }
+#endif
+
+  return FALSE;
+}
+
 static ClutterInputDevice *
 create_device (ClutterDeviceManagerXI2 *manager_xi2,
                ClutterBackendX11       *backend_x11,
                XIDeviceInfo            *info)
 {
-  ClutterInputDeviceType source;
+  ClutterInputDeviceType source, touch_source;
   ClutterInputDevice *retval;
   ClutterInputMode mode;
   gboolean is_enabled;
+  guint num_touches = 0;
 
   if (info->use == XIMasterKeyboard || info->use == XISlaveKeyboard)
     source = CLUTTER_KEYBOARD_DEVICE;
+  else if (info->use == XISlavePointer &&
+           is_touch_device (info->classes, info->num_classes,
+                            &touch_source,
+                            &num_touches))
+    {
+      source = touch_source;
+    }
   else
     {
       gchar *name;
@@ -208,6 +251,9 @@ create_device (ClutterDeviceManagerXI2 *manager_xi2,
         source = CLUTTER_ERASER_DEVICE;
       else if (strstr (name, "cursor") != NULL)
         source = CLUTTER_CURSOR_DEVICE;
+      else if (strstr (name, "finger") != NULL ||
+               (strstr (name, "touch") != NULL && strstr (name, "touchpad") == NULL))
+        source = CLUTTER_TOUCHSCREEN_DEVICE;
       else if (strstr (name, "wacom") != NULL || strstr (name, "pen") != NULL)
         source = CLUTTER_PEN_DEVICE;
       else
@@ -440,6 +486,11 @@ get_event_stage (ClutterEventTranslator *translator,
     case XI_ButtonPress:
     case XI_ButtonRelease:
     case XI_Motion:
+#ifdef XINPUT_2_2
+    case XI_TouchBegin:
+    case XI_TouchUpdate:
+    case XI_TouchEnd:
+#endif /* XINPUT_2_2 */
       {
         XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
 
@@ -807,6 +858,10 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
                                                  stage_x11,
                                                  &xev->valuators);
 
+#ifdef XINPUT_2_2
+            if (xev->flags & XIPointerEmulated)
+              _clutter_event_set_pointer_emulated (event, TRUE);
+#endif /* XINPUT_2_2 */
             break;
 
           default:
@@ -855,6 +910,11 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
                       event->button.y,
                       event->button.axes != NULL ? "yes" : "no");
 
+#ifdef XINPUT_2_2
+        if (xev->flags & XIPointerEmulated)
+          _clutter_event_set_pointer_emulated (event, TRUE);
+#endif /* XINPUT_2_2 */
+
         if (xi_event->evtype == XI_ButtonPress)
           _clutter_stage_x11_set_user_time (stage_x11, event->button.time);
 
@@ -930,6 +990,11 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
         if (source_device != NULL && device->stage != NULL)
           _clutter_input_device_set_stage (source_device, device->stage);
 
+#ifdef XINPUT_2_2
+        if (xev->flags & XIPointerEmulated)
+          _clutter_event_set_pointer_emulated (event, TRUE);
+#endif /* XINPUT_2_2 */
+
         CLUTTER_NOTE (EVENT, "motion: win:0x%x device:%s (x:%.2f, y:%.2f, axes:%s)",
                       (unsigned int) stage_x11->xwin,
                       event->motion.device->device_name,
@@ -941,6 +1006,116 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
       }
       break;
 
+#ifdef XINPUT_2_2
+    case XI_TouchBegin:
+    case XI_TouchEnd:
+      {
+        XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
+
+        source_device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                             GINT_TO_POINTER (xev->sourceid));
+
+        if (xi_event->evtype == XI_TouchBegin)
+          event->touch.type = event->type = CLUTTER_TOUCH_BEGIN;
+        else
+          event->touch.type = event->type = CLUTTER_TOUCH_END;
+
+        event->touch.stage = stage;
+        event->touch.time = xev->time;
+        event->touch.x = xev->event_x;
+        event->touch.y = xev->event_y;
+        event->touch.modifier_state =
+          _clutter_input_device_xi2_translate_state (&xev->mods,
+                                                     &xev->buttons);
+
+        clutter_event_set_source_device (event, source_device);
+
+        device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                      GINT_TO_POINTER (xev->deviceid));
+        clutter_event_set_device (event, device);
+
+        event->touch.axes = translate_axes (event->motion.device,
+                                            event->motion.x,
+                                            event->motion.y,
+                                            stage_x11,
+                                            &xev->valuators);
+
+        if (source_device != NULL && device->stage != NULL)
+          _clutter_input_device_set_stage (source_device, device->stage);
+
+        if (xi_event->evtype == XI_TouchBegin)
+          {
+            event->touch.modifier_state |= CLUTTER_BUTTON1_MASK;
+
+            _clutter_stage_x11_set_user_time (stage_x11, event->touch.time);
+          }
+
+        event->touch.sequence = GUINT_TO_POINTER (xev->detail);
+
+        if (xev->flags & XITouchEmulatingPointer)
+          _clutter_event_set_pointer_emulated (event, TRUE);
+
+        CLUTTER_NOTE (EVENT, "touch %s: win:0x%x device:%s (x:%.2f, y:%.2f, axes:%s)",
+                      event->type == CLUTTER_TOUCH_BEGIN ? "begin" : "end",
+                      (unsigned int) stage_x11->xwin,
+                      event->touch.device->device_name,
+                      event->touch.x,
+                      event->touch.y,
+                      event->touch.axes != NULL ? "yes" : "no");
+
+        retval = CLUTTER_TRANSLATE_QUEUE;
+      }
+      break;
+
+    case XI_TouchUpdate:
+      {
+        XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
+
+        source_device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                             GINT_TO_POINTER (xev->sourceid));
+
+        event->touch.type = event->type = CLUTTER_TOUCH_UPDATE;
+        event->touch.stage = stage;
+        event->touch.time = xev->time;
+        event->touch.sequence = GUINT_TO_POINTER (xev->detail);
+        event->touch.x = xev->event_x;
+        event->touch.y = xev->event_y;
+
+        clutter_event_set_source_device (event, source_device);
+
+        device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                      GINT_TO_POINTER (xev->deviceid));
+        clutter_event_set_device (event, device);
+
+        event->touch.axes = translate_axes (event->motion.device,
+                                            event->motion.x,
+                                            event->motion.y,
+                                            stage_x11,
+                                            &xev->valuators);
+
+        if (source_device != NULL && device->stage != NULL)
+          _clutter_input_device_set_stage (source_device, device->stage);
+
+        event->touch.modifier_state =
+          _clutter_input_device_xi2_translate_state (&xev->mods,
+                                                     &xev->buttons);
+        event->touch.modifier_state |= CLUTTER_BUTTON1_MASK;
+
+        if (xev->flags & XITouchEmulatingPointer)
+          _clutter_event_set_pointer_emulated (event, TRUE);
+
+        CLUTTER_NOTE (EVENT, "touch update: win:0x%x device:%s (x:%.2f, y:%.2f, axes:%s)",
+                      (unsigned int) stage_x11->xwin,
+                      event->touch.device->device_name,
+                      event->touch.x,
+                      event->touch.y,
+                      event->touch.axes != NULL ? "yes" : "no");
+
+        retval = CLUTTER_TRANSLATE_QUEUE;
+      }
+      break;
+#endif /* XINPUT_2_2 */
+
     case XI_Enter:
     case XI_Leave:
       {
diff --git a/clutter/x11/clutter-input-device-xi2.c b/clutter/x11/clutter-input-device-xi2.c
index 620df91..fb9f272 100644
--- a/clutter/x11/clutter-input-device-xi2.c
+++ b/clutter/x11/clutter-input-device-xi2.c
@@ -92,6 +92,16 @@ clutter_input_device_xi2_select_stage_events (ClutterInputDevice *device,
   if (event_mask & LeaveWindowMask)
     XISetMask (mask, XI_Leave);
 
+#ifdef XINPUT_2_2
+  /* enable touch event support if we're running on XInput 2.2 */
+  if (backend_x11->xi_minor >= 2)
+    {
+      XISetMask (mask, XI_TouchBegin);
+      XISetMask (mask, XI_TouchUpdate);
+      XISetMask (mask, XI_TouchEnd);
+    }
+#endif /* XINPUT_2_2 */
+
   xi_event_mask.deviceid = device_xi2->device_id;
   xi_event_mask.mask = mask;
   xi_event_mask.mask_len = len;



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