From 09a317d23dc7d4785c31f8393b54392b5f473f60 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 19 Mar 2012 14:28:34 +0000 Subject: [PATCH] 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 deletion(-) 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; -- 2.7.4