diff --git a/clutter/clutter/Makefile.am b/clutter/clutter/Makefile.am
index 2f7e6c372..8b1d54ecd 100644
--- a/clutter/clutter/Makefile.am
+++ b/clutter/clutter/Makefile.am
@@ -413,11 +413,13 @@ x11_source_c_priv = \
x11_source_c += \
x11/clutter-device-manager-xi2.c \
x11/clutter-input-device-xi2.c \
+ x11/clutter-input-device-tool-xi2.c \
$(NULL)
x11_source_h_priv += \
x11/clutter-device-manager-xi2.h \
x11/clutter-input-device-xi2.h \
+ x11/clutter-input-device-tool-xi2.h \
$(NULL)
x11_source_c += \
diff --git a/clutter/clutter/x11/clutter-device-manager-xi2.c b/clutter/clutter/x11/clutter-device-manager-xi2.c
index 62a12c40c..8bddebf1d 100644
--- a/clutter/clutter/x11/clutter-device-manager-xi2.c
+++ b/clutter/clutter/x11/clutter-device-manager-xi2.c
@@ -29,6 +29,7 @@
#include "clutter-backend-x11.h"
#include "clutter-input-device-xi2.h"
+#include "clutter-input-device-tool-xi2.h"
#include "clutter-virtual-input-device-x11.h"
#include "clutter-stage-x11.h"
@@ -952,6 +953,78 @@ clutter_device_manager_xi2_select_stage_events (ClutterDeviceManager *manager,
g_free (mask);
}
+static guint
+device_get_tool_serial (ClutterBackendX11 *backend_x11,
+ ClutterInputDevice *device)
+{
+ gulong nitems, bytes_after;
+ guint32 *data = NULL;
+ guint serial_id = 0;
+ int rc, format;
+ Atom type;
+ Atom prop;
+
+ prop = XInternAtom (backend_x11->xdpy, "Wacom Serial IDs", True);
+ if (prop == None)
+ return 0;
+
+ clutter_x11_trap_x_errors ();
+ rc = XIGetProperty (backend_x11->xdpy,
+ clutter_input_device_get_device_id (device),
+ prop, 0, 4, FALSE, XA_INTEGER, &type, &format, &nitems, &bytes_after,
+ (guchar **) &data);
+ clutter_x11_untrap_x_errors ();
+
+ if (rc == Success && type == XA_INTEGER && format == 32 && nitems >= 4)
+ serial_id = data[3];
+
+ XFree (data);
+
+ return serial_id;
+}
+
+static void
+handle_property_event (ClutterDeviceManagerXI2 *manager_xi2,
+ XIEvent *event)
+{
+ XIPropertyEvent *xev = (XIPropertyEvent *) event;
+ ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
+ Atom serial_ids_prop = XInternAtom (backend_x11->xdpy, "Wacom Serial IDs", True);
+ ClutterInputDevice *device;
+
+ device = g_hash_table_lookup (manager_xi2->devices_by_id,
+ GINT_TO_POINTER (xev->deviceid));
+ if (!device)
+ return;
+
+ if (xev->property == serial_ids_prop)
+ {
+ ClutterInputDeviceTool *tool = NULL;
+ ClutterInputDeviceToolType type;
+ guint serial_id;
+
+ serial_id = device_get_tool_serial (backend_x11, device);
+
+ if (serial_id != 0)
+ {
+ tool = g_hash_table_lookup (manager_xi2->tools_by_serial,
+ GUINT_TO_POINTER (serial_id));
+ if (!tool)
+ {
+ type = clutter_input_device_get_device_type (device) == CLUTTER_ERASER_DEVICE ?
+ CLUTTER_INPUT_DEVICE_TOOL_ERASER : CLUTTER_INPUT_DEVICE_TOOL_PEN;
+ tool = clutter_input_device_tool_xi2_new (serial_id, type);
+ g_hash_table_insert (manager_xi2->tools_by_serial,
+ GUINT_TO_POINTER (serial_id),
+ tool);
+ }
+ }
+
+ clutter_input_device_xi2_update_tool (device, tool);
+ g_signal_emit_by_name (manager_xi2, "tool-changed", device, tool);
+ }
+}
+
static ClutterTranslateReturn
clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
gpointer native,
@@ -983,7 +1056,8 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
return CLUTTER_TRANSLATE_REMOVE;
if (!(xi_event->evtype == XI_HierarchyChanged ||
- xi_event->evtype == XI_DeviceChanged))
+ xi_event->evtype == XI_DeviceChanged ||
+ xi_event->evtype == XI_PropertyEvent))
{
stage = get_event_stage (translator, xi_event);
if (stage == NULL || CLUTTER_ACTOR_IN_DESTRUCTION (stage))
@@ -1247,6 +1321,8 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
clutter_event_set_source_device (event, source_device);
clutter_event_set_device (event, device);
+ clutter_event_set_device_tool (event,
+ clutter_input_device_xi2_get_current_tool (source_device));
event->button.axes = translate_axes (event->button.device,
event->button.x,
@@ -1355,6 +1431,8 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
clutter_event_set_source_device (event, source_device);
clutter_event_set_device (event, device);
+ clutter_event_set_device_tool (event,
+ clutter_input_device_xi2_get_current_tool (source_device));
event->motion.axes = translate_axes (event->motion.device,
event->motion.x,
@@ -1556,6 +1634,10 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
case XI_FocusOut:
retval = CLUTTER_TRANSLATE_CONTINUE;
break;
+ case XI_PropertyEvent:
+ handle_property_event (manager_xi2, xi_event);
+ retval = CLUTTER_TRANSLATE_CONTINUE;
+ break;
}
return retval;
@@ -1733,6 +1815,7 @@ clutter_device_manager_xi2_constructed (GObject *gobject)
XISetMask (mask, XI_HierarchyChanged);
XISetMask (mask, XI_DeviceChanged);
+ XISetMask (mask, XI_PropertyEvent);
event_mask.deviceid = XIAllDevices;
event_mask.mask_len = sizeof (mask);
@@ -1814,4 +1897,6 @@ clutter_device_manager_xi2_init (ClutterDeviceManagerXI2 *self)
self->devices_by_id = g_hash_table_new_full (NULL, NULL,
NULL,
(GDestroyNotify) g_object_unref);
+ self->tools_by_serial = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) g_object_unref);
}
diff --git a/clutter/clutter/x11/clutter-device-manager-xi2.h b/clutter/clutter/x11/clutter-device-manager-xi2.h
index 2ceb623a6..c8e66f949 100644
--- a/clutter/clutter/x11/clutter-device-manager-xi2.h
+++ b/clutter/clutter/x11/clutter-device-manager-xi2.h
@@ -43,6 +43,7 @@ struct _ClutterDeviceManagerXI2
ClutterDeviceManager parent_instance;
GHashTable *devices_by_id;
+ GHashTable *tools_by_serial;
GSList *all_devices;
diff --git a/clutter/clutter/x11/clutter-input-device-tool-xi2.c b/clutter/clutter/x11/clutter-input-device-tool-xi2.c
new file mode 100644
index 000000000..396b84736
--- /dev/null
+++ b/clutter/clutter/x11/clutter-input-device-tool-xi2.c
@@ -0,0 +1,51 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright © 2016 Red Hat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Author: Carlos Garnacho
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "clutter-build-config.h"
+#endif
+
+#include "clutter-input-device-tool-xi2.h"
+
+G_DEFINE_TYPE (ClutterInputDeviceToolXI2, clutter_input_device_tool_xi2,
+ CLUTTER_TYPE_INPUT_DEVICE_TOOL)
+
+static void
+clutter_input_device_tool_xi2_class_init (ClutterInputDeviceToolXI2Class *klass)
+{
+}
+
+static void
+clutter_input_device_tool_xi2_init (ClutterInputDeviceToolXI2 *tool)
+{
+}
+
+ClutterInputDeviceTool *
+clutter_input_device_tool_xi2_new (guint serial,
+ ClutterInputDeviceToolType type)
+{
+ return g_object_new (CLUTTER_TYPE_INPUT_DEVICE_TOOL_XI2,
+ "type", type,
+ "serial", serial,
+ NULL);
+}
diff --git a/clutter/clutter/x11/clutter-input-device-tool-xi2.h b/clutter/clutter/x11/clutter-input-device-tool-xi2.h
new file mode 100644
index 000000000..1878b9def
--- /dev/null
+++ b/clutter/clutter/x11/clutter-input-device-tool-xi2.h
@@ -0,0 +1,74 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright © 2016 Red Hat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Author: Carlos Garnacho
+ */
+
+#ifndef __CLUTTER_INPUT_DEVICE_XI2_TOOL_H__
+#define __CLUTTER_INPUT_DEVICE_XI2_TOOL_H__
+
+#include
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_INPUT_DEVICE_TOOL_XI2 (clutter_input_device_tool_xi2_get_type ())
+
+#define CLUTTER_INPUT_DEVICE_TOOL_XI2(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), \
+ CLUTTER_TYPE_INPUT_DEVICE_TOOL_XI2, ClutterInputDeviceToolXI2))
+
+#define CLUTTER_IS_INPUT_DEVICE_TOOL_XI2(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), \
+ CLUTTER_TYPE_INPUT_DEVICE_TOOL_XI2))
+
+#define CLUTTER_INPUT_DEVICE_TOOL_XI2_CLASS(c) \
+ (G_TYPE_CHECK_CLASS_CAST ((c), \
+ CLUTTER_TYPE_INPUT_DEVICE_TOOL_XI2, ClutterInputDeviceToolXI2Class))
+
+#define CLUTTER_IS_INPUT_DEVICE_TOOL_XI2_CLASS(c) \
+ (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ CLUTTER_TYPE_INPUT_DEVICE_TOOL_XI2))
+
+#define CLUTTER_INPUT_DEVICE_TOOL_XI2_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), \
+ CLUTTER_TYPE_INPUT_DEVICE_TOOL_XI2, ClutterInputDeviceToolXI2Class))
+
+typedef struct _ClutterInputDeviceToolXI2 ClutterInputDeviceToolXI2;
+typedef struct _ClutterInputDeviceToolXI2Class ClutterInputDeviceToolXI2Class;
+
+struct _ClutterInputDeviceToolXI2
+{
+ ClutterInputDeviceTool parent_instance;
+ struct libinput_tablet_tool *tool;
+};
+
+struct _ClutterInputDeviceToolXI2Class
+{
+ ClutterInputDeviceToolClass parent_class;
+};
+
+GType clutter_input_device_xi2_evdev_get_type (void) G_GNUC_CONST;
+
+ClutterInputDeviceTool * clutter_input_device_tool_xi2_new (guint serial,
+ ClutterInputDeviceToolType type);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_INPUT_DEVICE_XI2_TOOL_H__ */
diff --git a/clutter/clutter/x11/clutter-input-device-xi2.c b/clutter/clutter/x11/clutter-input-device-xi2.c
index 00416a33c..d6bb87fdf 100644
--- a/clutter/clutter/x11/clutter-input-device-xi2.c
+++ b/clutter/clutter/x11/clutter-input-device-xi2.c
@@ -44,6 +44,7 @@ struct _ClutterInputDeviceXI2
ClutterInputDevice device;
gint device_id;
+ ClutterInputDeviceTool *current_tool;
};
#define N_BUTTONS 5
@@ -172,3 +173,18 @@ _clutter_input_device_xi2_translate_state (ClutterEvent *event,
_clutter_event_set_state_full (event, button, base, latched, locked, effective);
}
+
+void
+clutter_input_device_xi2_update_tool (ClutterInputDevice *device,
+ ClutterInputDeviceTool *tool)
+{
+ ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device);
+ g_set_object (&device_xi2->current_tool, tool);
+}
+
+ClutterInputDeviceTool *
+clutter_input_device_xi2_get_current_tool (ClutterInputDevice *device)
+{
+ ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device);
+ return device_xi2->current_tool;
+}
diff --git a/clutter/clutter/x11/clutter-input-device-xi2.h b/clutter/clutter/x11/clutter-input-device-xi2.h
index 92dadc965..b93684f71 100644
--- a/clutter/clutter/x11/clutter-input-device-xi2.h
+++ b/clutter/clutter/x11/clutter-input-device-xi2.h
@@ -41,6 +41,9 @@ void _clutter_input_device_xi2_translate_state (ClutterEvent *event,
XIModifierState *modifiers_state,
XIButtonState *buttons_state,
XIGroupState *group_state);
+void clutter_input_device_xi2_update_tool (ClutterInputDevice *device,
+ ClutterInputDeviceTool *tool);
+ClutterInputDeviceTool * clutter_input_device_xi2_get_current_tool (ClutterInputDevice *device);
G_END_DECLS