x11: Add support for touch events

For the time being, we just relay everything we get from the X server to
the Clutter application.
This commit is contained in:
Emmanuele Bassi 2012-03-19 14:28:34 +00:00
parent d15b828cc5
commit 09a317d23d
6 changed files with 207 additions and 1 deletions

View File

@ -5,6 +5,9 @@
G_BEGIN_DECLS G_BEGIN_DECLS
void _clutter_event_set_pointer_emulated (ClutterEvent *event,
gboolean is_emulated);
/* Reinjecting queued events for processing */ /* Reinjecting queued events for processing */
void _clutter_process_event (ClutterEvent *event); void _clutter_process_event (ClutterEvent *event);

View File

@ -53,6 +53,8 @@ typedef struct _ClutterEventPrivate {
gdouble delta_y; gdouble delta_y;
gpointer platform_data; gpointer platform_data;
guint is_pointer_emulated : 1;
} ClutterEventPrivate; } ClutterEventPrivate;
static GHashTable *all_events = NULL; static GHashTable *all_events = NULL;
@ -108,6 +110,16 @@ _clutter_event_set_platform_data (ClutterEvent *event,
((ClutterEventPrivate *) event)->platform_data = data; ((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: * clutter_event_type:
* @event: a #ClutterEvent * @event: a #ClutterEvent

View File

@ -255,6 +255,8 @@ clutter_backend_x11_create_device_manager (ClutterBackendX11 *backend_x11)
"backend", backend_x11, "backend", backend_x11,
"opcode", event_base, "opcode", event_base,
NULL); NULL);
backend_x11->xi_minor = minor;
} }
else else
#endif /* HAVE_XINPUT_2 */ #endif /* HAVE_XINPUT_2 */
@ -267,6 +269,7 @@ clutter_backend_x11_create_device_manager (ClutterBackendX11 *backend_x11)
"event-base", first_event, "event-base", first_event,
NULL); 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, g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_X11,
"backend", backend_x11, "backend", backend_x11,
NULL); NULL);
backend_x11->xi_minor = -1;
} }
backend = CLUTTER_BACKEND (backend_x11); backend = CLUTTER_BACKEND (backend_x11);

View File

@ -100,6 +100,7 @@ struct _ClutterBackendX11
ClutterDeviceManager *device_manager; ClutterDeviceManager *device_manager;
gboolean has_xinput; gboolean has_xinput;
int xi_minor;
XSettingsClient *xsettings; XSettingsClient *xsettings;
Window xsettings_xwin; Window xsettings_xwin;

View File

@ -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 * static ClutterInputDevice *
create_device (ClutterDeviceManagerXI2 *manager_xi2, create_device (ClutterDeviceManagerXI2 *manager_xi2,
ClutterBackendX11 *backend_x11, ClutterBackendX11 *backend_x11,
XIDeviceInfo *info) XIDeviceInfo *info)
{ {
ClutterInputDeviceType source; ClutterInputDeviceType source, touch_source;
ClutterInputDevice *retval; ClutterInputDevice *retval;
ClutterInputMode mode; ClutterInputMode mode;
gboolean is_enabled; gboolean is_enabled;
guint num_touches = 0;
if (info->use == XIMasterKeyboard || info->use == XISlaveKeyboard) if (info->use == XIMasterKeyboard || info->use == XISlaveKeyboard)
source = CLUTTER_KEYBOARD_DEVICE; 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 else
{ {
gchar *name; gchar *name;
@ -208,6 +251,9 @@ create_device (ClutterDeviceManagerXI2 *manager_xi2,
source = CLUTTER_ERASER_DEVICE; source = CLUTTER_ERASER_DEVICE;
else if (strstr (name, "cursor") != NULL) else if (strstr (name, "cursor") != NULL)
source = CLUTTER_CURSOR_DEVICE; 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) else if (strstr (name, "wacom") != NULL || strstr (name, "pen") != NULL)
source = CLUTTER_PEN_DEVICE; source = CLUTTER_PEN_DEVICE;
else else
@ -440,6 +486,11 @@ get_event_stage (ClutterEventTranslator *translator,
case XI_ButtonPress: case XI_ButtonPress:
case XI_ButtonRelease: case XI_ButtonRelease:
case XI_Motion: 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; XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
@ -807,6 +858,10 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
stage_x11, stage_x11,
&xev->valuators); &xev->valuators);
#ifdef XINPUT_2_2
if (xev->flags & XIPointerEmulated)
_clutter_event_set_pointer_emulated (event, TRUE);
#endif /* XINPUT_2_2 */
break; break;
default: default:
@ -855,6 +910,11 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
event->button.y, event->button.y,
event->button.axes != NULL ? "yes" : "no"); 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) if (xi_event->evtype == XI_ButtonPress)
_clutter_stage_x11_set_user_time (stage_x11, event->button.time); _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) if (source_device != NULL && device->stage != NULL)
_clutter_input_device_set_stage (source_device, device->stage); _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)", CLUTTER_NOTE (EVENT, "motion: win:0x%x device:%s (x:%.2f, y:%.2f, axes:%s)",
(unsigned int) stage_x11->xwin, (unsigned int) stage_x11->xwin,
event->motion.device->device_name, event->motion.device->device_name,
@ -941,6 +1006,116 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
} }
break; 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_Enter:
case XI_Leave: case XI_Leave:
{ {

View File

@ -92,6 +92,16 @@ clutter_input_device_xi2_select_stage_events (ClutterInputDevice *device,
if (event_mask & LeaveWindowMask) if (event_mask & LeaveWindowMask)
XISetMask (mask, XI_Leave); 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.deviceid = device_xi2->device_id;
xi_event_mask.mask = mask; xi_event_mask.mask = mask;
xi_event_mask.mask_len = len; xi_event_mask.mask_len = len;