4 * An OpenGL based 'interactive canvas' library.
6 * Copyright © 2011 Intel Corp.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
21 * Author: Emmanuele Bassi <ebassi@linux.intel.com>
28 #include "clutter-device-manager-xi2.h"
30 #include "clutter-backend-x11.h"
31 #include "clutter-input-device-xi2.h"
32 #include "clutter-stage-x11.h"
34 #include "clutter-backend.h"
35 #include "clutter-debug.h"
36 #include "clutter-device-manager-private.h"
37 #include "clutter-event-private.h"
38 #include "clutter-event-translator.h"
39 #include "clutter-stage-private.h"
40 #include "clutter-private.h"
42 #include <X11/extensions/XInput2.h>
53 static GParamSpec *obj_props[PROP_LAST] = { NULL, };
55 static const char *clutter_input_axis_atom_names[] = {
56 "Abs X", /* CLUTTER_INPUT_AXIS_X */
57 "Abs Y", /* CLUTTER_INPUT_AXIS_Y */
58 "Abs Pressure", /* CLUTTER_INPUT_AXIS_PRESSURE */
59 "Abs Tilt X", /* CLUTTER_INPUT_AXIS_XTILT */
60 "Abs Tilt Y", /* CLUTTER_INPUT_AXIS_YTILT */
61 "Abs Wheel", /* CLUTTER_INPUT_AXIS_WHEEL */
62 "Abs Distance", /* CLUTTER_INPUT_AXIS_DISTANCE */
65 #define N_AXIS_ATOMS G_N_ELEMENTS (clutter_input_axis_atom_names)
67 static Atom clutter_input_axis_atoms[N_AXIS_ATOMS] = { 0, };
69 static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface);
71 #define clutter_device_manager_xi2_get_type _clutter_device_manager_xi2_get_type
73 G_DEFINE_TYPE_WITH_CODE (ClutterDeviceManagerXI2,
74 clutter_device_manager_xi2,
75 CLUTTER_TYPE_DEVICE_MANAGER,
76 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR,
77 clutter_event_translator_iface_init));
80 translate_valuator_class (Display *xdisplay,
81 ClutterInputDevice *device,
82 XIValuatorClassInfo *class)
84 static gboolean atoms_initialized = FALSE;
85 ClutterInputAxis i, axis = CLUTTER_INPUT_AXIS_IGNORE;
87 if (G_UNLIKELY (!atoms_initialized))
89 XInternAtoms (xdisplay,
90 (char **) clutter_input_axis_atom_names, N_AXIS_ATOMS,
92 clutter_input_axis_atoms);
94 atoms_initialized = TRUE;
97 for (i = CLUTTER_INPUT_AXIS_IGNORE;
98 i < CLUTTER_INPUT_AXIS_LAST;
101 if (clutter_input_axis_atoms[i] == class->label)
108 _clutter_input_device_add_axis (device, axis,
113 CLUTTER_NOTE (BACKEND,
114 "Added axis '%s' (min:%.2f, max:%.2fd, res:%d) of device %d",
115 clutter_input_axis_atom_names[axis],
123 translate_device_classes (Display *xdisplay,
124 ClutterInputDevice *device,
125 XIAnyClassInfo **classes,
130 for (i = 0; i < n_classes; i++)
132 XIAnyClassInfo *class_info = classes[i];
134 switch (class_info->type)
138 XIKeyClassInfo *key_info = (XIKeyClassInfo *) class_info;
141 _clutter_input_device_set_n_keys (device,
142 key_info->num_keycodes);
144 for (j = 0; j < key_info->num_keycodes; j++)
146 clutter_input_device_set_key (device, j,
147 key_info->keycodes[i],
153 case XIValuatorClass:
154 translate_valuator_class (xdisplay, device,
155 (XIValuatorClassInfo *) class_info);
158 #ifdef HAVE_XINPUT_2_2
161 XIScrollClassInfo *scroll_info = (XIScrollClassInfo *) class_info;
162 ClutterScrollDirection direction;
164 if (scroll_info->scroll_type == XIScrollTypeVertical)
165 direction = CLUTTER_SCROLL_DOWN;
167 direction = CLUTTER_SCROLL_RIGHT;
169 CLUTTER_NOTE (BACKEND, "Scroll valuator %d: %s, increment: %f",
171 scroll_info->scroll_type == XIScrollTypeVertical
174 scroll_info->increment);
176 _clutter_input_device_add_scroll_info (device,
179 scroll_info->increment);
182 #endif /* HAVE_XINPUT_2_2 */
191 is_touch_device (XIAnyClassInfo **classes,
193 ClutterInputDeviceType *device_type,
194 guint *n_touch_points)
196 #ifdef HAVE_XINPUT_2_2
199 for (i = 0; i < n_classes; i++)
201 XITouchClassInfo *class = (XITouchClassInfo *) classes[i];
203 if (class->type != XITouchClass)
206 if (class->num_touches > 0)
208 if (class->mode == XIDirectTouch)
209 *device_type = CLUTTER_TOUCHSCREEN_DEVICE;
210 else if (class->mode == XIDependentTouch)
211 *device_type = CLUTTER_TOUCHPAD_DEVICE;
215 *n_touch_points = class->num_touches;
225 static ClutterInputDevice *
226 create_device (ClutterDeviceManagerXI2 *manager_xi2,
227 ClutterBackendX11 *backend_x11,
230 ClutterInputDeviceType source, touch_source;
231 ClutterInputDevice *retval;
232 ClutterInputMode mode;
234 guint num_touches = 0;
236 if (info->use == XIMasterKeyboard || info->use == XISlaveKeyboard)
237 source = CLUTTER_KEYBOARD_DEVICE;
238 else if (info->use == XISlavePointer &&
239 is_touch_device (info->classes, info->num_classes,
243 source = touch_source;
249 name = g_ascii_strdown (info->name, -1);
251 if (strstr (name, "eraser") != NULL)
252 source = CLUTTER_ERASER_DEVICE;
253 else if (strstr (name, "cursor") != NULL)
254 source = CLUTTER_CURSOR_DEVICE;
255 else if (strstr (name, "wacom") != NULL || strstr (name, "pen") != NULL)
256 source = CLUTTER_PEN_DEVICE;
258 source = CLUTTER_POINTER_DEVICE;
265 case XIMasterKeyboard:
266 case XIMasterPointer:
267 mode = CLUTTER_INPUT_MODE_MASTER;
271 case XISlaveKeyboard:
273 mode = CLUTTER_INPUT_MODE_SLAVE;
277 case XIFloatingSlave:
279 mode = CLUTTER_INPUT_MODE_FLOATING;
284 retval = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_XI2,
286 "id", info->deviceid,
287 "has-cursor", (info->use == XIMasterPointer),
288 "device-manager", manager_xi2,
289 "device-type", source,
291 "backend", backend_x11,
292 "enabled", is_enabled,
295 translate_device_classes (backend_x11->xdpy, retval,
299 CLUTTER_NOTE (BACKEND, "Created device '%s' (id: %d, has-cursor: %s)",
302 info->use == XIMasterPointer ? "yes" : "no");
307 static ClutterInputDevice *
308 add_device (ClutterDeviceManagerXI2 *manager_xi2,
309 ClutterBackendX11 *backend_x11,
311 gboolean in_construction)
313 ClutterInputDevice *device;
315 device = create_device (manager_xi2, backend_x11, info);
317 /* we don't go through the DeviceManager::add_device() vfunc because
318 * that emits the signal, and we only do it conditionally
320 g_hash_table_replace (manager_xi2->devices_by_id,
321 GINT_TO_POINTER (info->deviceid),
322 g_object_ref (device));
324 if (info->use == XIMasterPointer ||
325 info->use == XIMasterKeyboard)
327 manager_xi2->master_devices =
328 g_list_prepend (manager_xi2->master_devices, device);
330 else if (info->use == XISlavePointer ||
331 info->use == XISlaveKeyboard ||
332 info->use == XIFloatingSlave)
334 manager_xi2->slave_devices =
335 g_list_prepend (manager_xi2->slave_devices, device);
338 g_warning ("Unhandled device: %s",
339 clutter_input_device_get_device_name (device));
341 /* relationships between devices and signal emissions are not
342 * necessary while we're constructing the device manager instance
344 if (!in_construction)
346 if (info->use == XISlavePointer || info->use == XISlaveKeyboard)
348 ClutterInputDevice *master;
350 master = g_hash_table_lookup (manager_xi2->devices_by_id,
351 GINT_TO_POINTER (info->attachment));
352 _clutter_input_device_set_associated_device (device, master);
353 _clutter_input_device_add_slave (master, device);
357 g_slist_free (manager_xi2->all_devices);
358 manager_xi2->all_devices = NULL;
360 g_signal_emit_by_name (manager_xi2, "device-added", device);
367 remove_device (ClutterDeviceManagerXI2 *manager_xi2,
370 ClutterInputDevice *device;
372 device = g_hash_table_lookup (manager_xi2->devices_by_id,
373 GINT_TO_POINTER (device_id));
377 manager_xi2->master_devices =
378 g_list_remove (manager_xi2->master_devices, device);
379 manager_xi2->slave_devices =
380 g_list_remove (manager_xi2->slave_devices, device);
383 g_slist_free (manager_xi2->all_devices);
384 manager_xi2->all_devices = NULL;
386 g_signal_emit_by_name (manager_xi2, "device-removed", device);
388 g_object_run_dispose (G_OBJECT (device));
390 g_hash_table_remove (manager_xi2->devices_by_id,
391 GINT_TO_POINTER (device_id));
396 translate_hierarchy_event (ClutterBackendX11 *backend_x11,
397 ClutterDeviceManagerXI2 *manager_xi2,
398 XIHierarchyEvent *ev)
402 for (i = 0; i < ev->num_info; i++)
404 if (ev->info[i].flags & XIDeviceEnabled)
409 CLUTTER_NOTE (EVENT, "Hierarchy event: device enabled");
411 info = XIQueryDevice (backend_x11->xdpy,
412 ev->info[i].deviceid,
414 add_device (manager_xi2, backend_x11, &info[0], FALSE);
416 else if (ev->info[i].flags & XIDeviceDisabled)
418 CLUTTER_NOTE (EVENT, "Hierarchy event: device disabled");
420 remove_device (manager_xi2, ev->info[i].deviceid);
422 else if ((ev->info[i].flags & XISlaveAttached) ||
423 (ev->info[i].flags & XISlaveDetached))
425 ClutterInputDevice *master, *slave;
428 gboolean send_changed = FALSE;
430 CLUTTER_NOTE (EVENT, "Hierarchy event: slave %s",
431 (ev->info[i].flags & XISlaveAttached)
435 slave = g_hash_table_lookup (manager_xi2->devices_by_id,
436 GINT_TO_POINTER (ev->info[i].deviceid));
437 master = clutter_input_device_get_associated_device (slave);
439 /* detach the slave in both cases */
442 _clutter_input_device_remove_slave (master, slave);
443 _clutter_input_device_set_associated_device (slave, NULL);
448 /* and attach the slave to the new master if needed */
449 if (ev->info[i].flags & XISlaveAttached)
451 info = XIQueryDevice (backend_x11->xdpy,
452 ev->info[i].deviceid,
454 master = g_hash_table_lookup (manager_xi2->devices_by_id,
455 GINT_TO_POINTER (info->attachment));
456 _clutter_input_device_set_associated_device (slave, master);
457 _clutter_input_device_add_slave (master, slave);
460 XIFreeDeviceInfo (info);
465 ClutterStage *stage = _clutter_input_device_get_stage (master);
467 _clutter_stage_x11_events_device_changed (CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage)),
469 CLUTTER_DEVICE_MANAGER (manager_xi2));
476 clutter_device_manager_xi2_select_events (ClutterDeviceManager *manager,
478 XIEventMask *event_mask)
482 xdisplay = clutter_x11_get_default_display ();
484 XISelectEvents (xdisplay, xwindow, event_mask, 1);
487 static ClutterStage *
488 get_event_stage (ClutterEventTranslator *translator,
491 Window xwindow = None;
493 switch (xi_event->evtype)
498 case XI_ButtonRelease:
500 #ifdef HAVE_XINPUT_2_2
504 #endif /* HAVE_XINPUT_2_2 */
506 XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
508 xwindow = xev->event;
517 XIEnterEvent *xev = (XIEnterEvent *) xi_event;
519 xwindow = xev->event;
530 return clutter_x11_get_stage_from_window (xwindow);
534 * print_key_sym: Translate a symbol to its printable form if any
535 * @symbol: the symbol to translate
536 * @buffer: the buffer where to put the translated string
537 * @len: size of the buffer
539 * Translates @symbol into a printable representation in @buffer, if possible.
541 * Return value: The number of bytes of the translated string, 0 if the
542 * symbol can't be printed
544 * Note: The code is derived from libX11's src/KeyBind.c
545 * Copyright 1985, 1987, 1998 The Open Group
547 * Note: This code works for Latin-1 symbols. clutter_keysym_to_unicode()
548 * does the work for the other keysyms.
551 print_keysym (uint32_t symbol,
555 unsigned long high_bytes;
558 high_bytes = symbol >> 8;
560 ((high_bytes == 0) ||
561 ((high_bytes == 0xFF) &&
562 (((symbol >= CLUTTER_KEY_BackSpace) &&
563 (symbol <= CLUTTER_KEY_Clear)) ||
564 (symbol == CLUTTER_KEY_Return) ||
565 (symbol == CLUTTER_KEY_Escape) ||
566 (symbol == CLUTTER_KEY_KP_Space) ||
567 (symbol == CLUTTER_KEY_KP_Tab) ||
568 (symbol == CLUTTER_KEY_KP_Enter) ||
569 ((symbol >= CLUTTER_KEY_KP_Multiply) &&
570 (symbol <= CLUTTER_KEY_KP_9)) ||
571 (symbol == CLUTTER_KEY_KP_Equal) ||
572 (symbol == CLUTTER_KEY_Delete))))))
575 /* if X keysym, convert to ascii by grabbing low 7 bits */
576 if (symbol == CLUTTER_KEY_KP_Space)
577 c = CLUTTER_KEY_space & 0x7F; /* patch encoding botch */
578 else if (high_bytes == 0xFF)
588 translate_axes (ClutterInputDevice *device,
591 ClutterStageX11 *stage_x11,
592 XIValuatorState *valuators)
594 guint n_axes = clutter_input_device_get_n_axes (device);
599 retval = g_new0 (gdouble, n_axes);
600 values = valuators->values;
602 for (i = 0; i < valuators->mask_len * 8; i++)
604 ClutterInputAxis axis;
607 if (!XIMaskIsSet (valuators->mask, i))
610 axis = clutter_input_device_get_axis (device, i);
615 case CLUTTER_INPUT_AXIS_X:
619 case CLUTTER_INPUT_AXIS_Y:
624 _clutter_input_device_translate_axis (device, i, val, &retval[i]);
633 scroll_valuators_changed (ClutterInputDevice *device,
634 XIValuatorState *valuators,
638 gboolean retval = FALSE;
639 guint n_axes, n_val, i;
642 n_axes = clutter_input_device_get_n_axes (device);
643 values = valuators->values;
649 for (i = 0; i < MIN (valuators->mask_len * 8, n_axes); i++)
651 ClutterScrollDirection direction;
654 if (!XIMaskIsSet (valuators->mask, i))
657 if (_clutter_input_device_get_scroll_delta (device, i,
664 if (direction == CLUTTER_SCROLL_UP ||
665 direction == CLUTTER_SCROLL_DOWN)
677 static ClutterTranslateReturn
678 clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
682 ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (translator);
683 ClutterTranslateReturn retval = CLUTTER_TRANSLATE_CONTINUE;
684 ClutterBackendX11 *backend_x11;
685 ClutterStageX11 *stage_x11 = NULL;
686 ClutterStage *stage = NULL;
687 ClutterInputDevice *device, *source_device;
688 XGenericEventCookie *cookie;
692 backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
696 cookie = &xevent->xcookie;
698 if (cookie->type != GenericEvent ||
699 cookie->extension != manager_xi2->opcode)
700 return CLUTTER_TRANSLATE_CONTINUE;
702 xi_event = (XIEvent *) cookie->data;
705 return CLUTTER_TRANSLATE_REMOVE;
707 if (!(xi_event->evtype == XI_HierarchyChanged ||
708 xi_event->evtype == XI_DeviceChanged))
710 stage = get_event_stage (translator, xi_event);
711 if (stage == NULL || CLUTTER_ACTOR_IN_DESTRUCTION (stage))
712 return CLUTTER_TRANSLATE_CONTINUE;
714 stage_x11 = CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage));
717 event->any.stage = stage;
719 switch (xi_event->evtype)
721 case XI_HierarchyChanged:
723 XIHierarchyEvent *xev = (XIHierarchyEvent *) xi_event;
725 translate_hierarchy_event (backend_x11, manager_xi2, xev);
727 retval = CLUTTER_TRANSLATE_REMOVE;
730 case XI_DeviceChanged:
732 XIDeviceChangedEvent *xev = (XIDeviceChangedEvent *) xi_event;
734 device = g_hash_table_lookup (manager_xi2->devices_by_id,
735 GINT_TO_POINTER (xev->deviceid));
738 _clutter_input_device_reset_axes (device);
739 _clutter_input_device_reset_scroll_info (device);
740 translate_device_classes (backend_x11->xdpy,
746 retval = CLUTTER_TRANSLATE_REMOVE;
752 XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
753 ClutterEventX11 *event_x11;
754 char buffer[7] = { 0, };
757 event->key.type = event->type = (xev->evtype == XI_KeyPress)
759 : CLUTTER_KEY_RELEASE;
761 event->key.time = xev->time;
762 event->key.stage = stage;
763 event->key.modifier_state =
764 _clutter_input_device_xi2_translate_state (&xev->mods, &xev->buttons);
765 event->key.hardware_keycode = xev->detail;
767 /* keyval is the key ignoring all modifiers ('1' vs. '!') */
769 _clutter_keymap_x11_translate_key_state (backend_x11->keymap,
770 event->key.hardware_keycode,
771 event->key.modifier_state,
774 /* KeyEvents have platform specific data associated to them */
775 event_x11 = _clutter_event_x11_new ();
776 _clutter_event_set_platform_data (event, event_x11);
778 event_x11->key_group =
779 _clutter_keymap_x11_get_key_group (backend_x11->keymap,
780 event->key.modifier_state);
781 event_x11->key_is_modifier =
782 _clutter_keymap_x11_get_is_modifier (backend_x11->keymap,
783 event->key.hardware_keycode);
784 event_x11->num_lock_set =
785 _clutter_keymap_x11_get_num_lock_state (backend_x11->keymap);
786 event_x11->caps_lock_set =
787 _clutter_keymap_x11_get_caps_lock_state (backend_x11->keymap);
789 source_device = g_hash_table_lookup (manager_xi2->devices_by_id,
790 GINT_TO_POINTER (xev->sourceid));
791 clutter_event_set_source_device (event, source_device);
793 device = g_hash_table_lookup (manager_xi2->devices_by_id,
794 GINT_TO_POINTER (xev->deviceid));
795 clutter_event_set_device (event, device);
797 /* XXX keep this in sync with the evdev device manager */
798 n = print_keysym (event->key.keyval, buffer, sizeof (buffer));
802 event->key.unicode_value = (gunichar) '\0';
806 event->key.unicode_value = g_utf8_get_char_validated (buffer, n);
807 if (event->key.unicode_value == -1 ||
808 event->key.unicode_value == -2)
809 event->key.unicode_value = (gunichar) '\0';
813 "%s: win:0x%x device:%d source:%d, key: %12s (%d)",
814 event->any.type == CLUTTER_KEY_PRESS
817 (unsigned int) stage_x11->xwin,
820 event->key.keyval ? buffer : "(none)",
823 if (xi_event->evtype == XI_KeyPress)
824 _clutter_stage_x11_set_user_time (stage_x11, event->key.time);
826 retval = CLUTTER_TRANSLATE_QUEUE;
831 case XI_ButtonRelease:
833 XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
841 event->scroll.type = event->type = CLUTTER_SCROLL;
843 if (xev->detail == 4)
844 event->scroll.direction = CLUTTER_SCROLL_UP;
845 else if (xev->detail == 5)
846 event->scroll.direction = CLUTTER_SCROLL_DOWN;
847 else if (xev->detail == 6)
848 event->scroll.direction = CLUTTER_SCROLL_LEFT;
850 event->scroll.direction = CLUTTER_SCROLL_RIGHT;
852 event->scroll.stage = stage;
854 event->scroll.time = xev->time;
855 event->scroll.x = xev->event_x;
856 event->scroll.y = xev->event_y;
857 event->scroll.modifier_state =
858 _clutter_input_device_xi2_translate_state (&xev->mods,
861 source_device = g_hash_table_lookup (manager_xi2->devices_by_id,
862 GINT_TO_POINTER (xev->sourceid));
863 clutter_event_set_source_device (event, source_device);
865 device = g_hash_table_lookup (manager_xi2->devices_by_id,
866 GINT_TO_POINTER (xev->deviceid));
867 clutter_event_set_device (event, device);
869 event->scroll.axes = translate_axes (event->scroll.device,
875 #ifdef HAVE_XINPUT_2_2
876 if (xev->flags & XIPointerEmulated)
877 _clutter_event_set_pointer_emulated (event, TRUE);
878 #endif /* HAVE_XINPUT_2_2 */
882 event->button.type = event->type =
883 (xi_event->evtype == XI_ButtonPress) ? CLUTTER_BUTTON_PRESS
884 : CLUTTER_BUTTON_RELEASE;
886 event->button.stage = stage;
888 event->button.time = xev->time;
889 event->button.x = xev->event_x;
890 event->button.y = xev->event_y;
891 event->button.button = xev->detail;
892 event->button.modifier_state =
893 _clutter_input_device_xi2_translate_state (&xev->mods,
896 source_device = g_hash_table_lookup (manager_xi2->devices_by_id,
897 GINT_TO_POINTER (xev->sourceid));
898 clutter_event_set_source_device (event, source_device);
900 device = g_hash_table_lookup (manager_xi2->devices_by_id,
901 GINT_TO_POINTER (xev->deviceid));
902 clutter_event_set_device (event, device);
904 event->button.axes = translate_axes (event->button.device,
912 if (source_device != NULL && device->stage != NULL)
913 _clutter_input_device_set_stage (source_device, device->stage);
916 "%s: win:0x%x, device:%s (button:%d, x:%.2f, y:%.2f, axes:%s)",
917 event->any.type == CLUTTER_BUTTON_PRESS
920 (unsigned int) stage_x11->xwin,
921 event->button.device->device_name,
922 event->button.button,
925 event->button.axes != NULL ? "yes" : "no");
927 #ifdef HAVE_XINPUT_2_2
928 if (xev->flags & XIPointerEmulated)
929 _clutter_event_set_pointer_emulated (event, TRUE);
930 #endif /* HAVE_XINPUT_2_2 */
932 if (xi_event->evtype == XI_ButtonPress)
933 _clutter_stage_x11_set_user_time (stage_x11, event->button.time);
935 retval = CLUTTER_TRANSLATE_QUEUE;
941 XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
942 gdouble delta_x, delta_y;
944 source_device = g_hash_table_lookup (manager_xi2->devices_by_id,
945 GINT_TO_POINTER (xev->sourceid));
947 if (scroll_valuators_changed (source_device,
951 event->scroll.type = event->type = CLUTTER_SCROLL;
952 event->scroll.direction = CLUTTER_SCROLL_SMOOTH;
954 event->scroll.stage = stage;
955 event->scroll.time = xev->time;
956 event->scroll.x = xev->event_x;
957 event->scroll.y = xev->event_y;
958 event->scroll.modifier_state =
959 _clutter_input_device_xi2_translate_state (&xev->mods,
962 clutter_event_set_scroll_delta (event, delta_x, delta_y);
963 clutter_event_set_source_device (event, source_device);
965 device = g_hash_table_lookup (manager_xi2->devices_by_id,
966 GINT_TO_POINTER (xev->deviceid));
967 clutter_event_set_device (event, device);
970 "smooth scroll: win:0x%x device:%s (x:%.2f, y:%.2f, delta:%f, %f)",
971 (unsigned int) stage_x11->xwin,
972 event->scroll.device->device_name,
977 retval = CLUTTER_TRANSLATE_QUEUE;
981 event->motion.type = event->type = CLUTTER_MOTION;
983 event->motion.stage = stage;
985 event->motion.time = xev->time;
986 event->motion.x = xev->event_x;
987 event->motion.y = xev->event_y;
988 event->motion.modifier_state =
989 _clutter_input_device_xi2_translate_state (&xev->mods,
992 clutter_event_set_source_device (event, source_device);
994 device = g_hash_table_lookup (manager_xi2->devices_by_id,
995 GINT_TO_POINTER (xev->deviceid));
996 clutter_event_set_device (event, device);
998 event->motion.axes = translate_axes (event->motion.device,
1004 if (source_device != NULL && device->stage != NULL)
1005 _clutter_input_device_set_stage (source_device, device->stage);
1007 #ifdef HAVE_XINPUT_2_2
1008 if (xev->flags & XIPointerEmulated)
1009 _clutter_event_set_pointer_emulated (event, TRUE);
1010 #endif /* HAVE_XINPUT_2_2 */
1012 CLUTTER_NOTE (EVENT, "motion: win:0x%x device:%s (x:%.2f, y:%.2f, axes:%s)",
1013 (unsigned int) stage_x11->xwin,
1014 event->motion.device->device_name,
1017 event->motion.axes != NULL ? "yes" : "no");
1019 retval = CLUTTER_TRANSLATE_QUEUE;
1023 #ifdef HAVE_XINPUT_2_2
1027 XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
1029 source_device = g_hash_table_lookup (manager_xi2->devices_by_id,
1030 GINT_TO_POINTER (xev->sourceid));
1032 if (xi_event->evtype == XI_TouchBegin)
1033 event->touch.type = event->type = CLUTTER_TOUCH_BEGIN;
1035 event->touch.type = event->type = CLUTTER_TOUCH_END;
1037 event->touch.stage = stage;
1038 event->touch.time = xev->time;
1039 event->touch.x = xev->event_x;
1040 event->touch.y = xev->event_y;
1041 event->touch.modifier_state =
1042 _clutter_input_device_xi2_translate_state (&xev->mods,
1045 clutter_event_set_source_device (event, source_device);
1047 device = g_hash_table_lookup (manager_xi2->devices_by_id,
1048 GINT_TO_POINTER (xev->deviceid));
1049 clutter_event_set_device (event, device);
1051 event->touch.axes = translate_axes (event->touch.device,
1057 if (source_device != NULL && device->stage != NULL)
1058 _clutter_input_device_set_stage (source_device, device->stage);
1060 if (xi_event->evtype == XI_TouchBegin)
1062 event->touch.modifier_state |= CLUTTER_BUTTON1_MASK;
1064 _clutter_stage_x11_set_user_time (stage_x11, event->touch.time);
1067 event->touch.sequence = GUINT_TO_POINTER (xev->detail);
1069 if (xev->flags & XITouchEmulatingPointer)
1070 _clutter_event_set_pointer_emulated (event, TRUE);
1072 CLUTTER_NOTE (EVENT, "touch %s: win:0x%x device:%s (x:%.2f, y:%.2f, axes:%s)",
1073 event->type == CLUTTER_TOUCH_BEGIN ? "begin" : "end",
1074 (unsigned int) stage_x11->xwin,
1075 event->touch.device->device_name,
1078 event->touch.axes != NULL ? "yes" : "no");
1080 retval = CLUTTER_TRANSLATE_QUEUE;
1084 case XI_TouchUpdate:
1086 XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
1088 source_device = g_hash_table_lookup (manager_xi2->devices_by_id,
1089 GINT_TO_POINTER (xev->sourceid));
1091 event->touch.type = event->type = CLUTTER_TOUCH_UPDATE;
1092 event->touch.stage = stage;
1093 event->touch.time = xev->time;
1094 event->touch.sequence = GUINT_TO_POINTER (xev->detail);
1095 event->touch.x = xev->event_x;
1096 event->touch.y = xev->event_y;
1098 clutter_event_set_source_device (event, source_device);
1100 device = g_hash_table_lookup (manager_xi2->devices_by_id,
1101 GINT_TO_POINTER (xev->deviceid));
1102 clutter_event_set_device (event, device);
1104 event->touch.axes = translate_axes (event->touch.device,
1110 if (source_device != NULL && device->stage != NULL)
1111 _clutter_input_device_set_stage (source_device, device->stage);
1113 event->touch.modifier_state =
1114 _clutter_input_device_xi2_translate_state (&xev->mods,
1116 event->touch.modifier_state |= CLUTTER_BUTTON1_MASK;
1118 if (xev->flags & XITouchEmulatingPointer)
1119 _clutter_event_set_pointer_emulated (event, TRUE);
1121 CLUTTER_NOTE (EVENT, "touch update: win:0x%x device:%s (x:%.2f, y:%.2f, axes:%s)",
1122 (unsigned int) stage_x11->xwin,
1123 event->touch.device->device_name,
1126 event->touch.axes != NULL ? "yes" : "no");
1128 retval = CLUTTER_TRANSLATE_QUEUE;
1131 #endif /* HAVE_XINPUT_2_2 */
1136 XIEnterEvent *xev = (XIEnterEvent *) xi_event;
1138 device = g_hash_table_lookup (manager_xi2->devices_by_id,
1139 GINT_TO_POINTER (xev->deviceid));
1141 source_device = g_hash_table_lookup (manager_xi2->devices_by_id,
1142 GINT_TO_POINTER (xev->sourceid));
1144 if (xi_event->evtype == XI_Enter)
1146 event->crossing.type = event->type = CLUTTER_ENTER;
1148 event->crossing.stage = stage;
1149 event->crossing.source = CLUTTER_ACTOR (stage);
1150 event->crossing.related = NULL;
1152 event->crossing.time = xev->time;
1153 event->crossing.x = xev->event_x;
1154 event->crossing.y = xev->event_y;
1156 _clutter_stage_add_device (stage, device);
1160 if (device->stage == NULL)
1162 CLUTTER_NOTE (EVENT,
1163 "Discarding Leave for ButtonRelease "
1166 retval = CLUTTER_TRANSLATE_REMOVE;
1170 event->crossing.type = event->type = CLUTTER_LEAVE;
1172 event->crossing.stage = stage;
1173 event->crossing.source = CLUTTER_ACTOR (stage);
1174 event->crossing.related = NULL;
1176 event->crossing.time = xev->time;
1177 event->crossing.x = xev->event_x;
1178 event->crossing.y = xev->event_y;
1180 _clutter_stage_remove_device (stage, device);
1183 _clutter_input_device_reset_scroll_info (source_device);
1185 clutter_event_set_device (event, device);
1186 clutter_event_set_source_device (event, source_device);
1188 retval = CLUTTER_TRANSLATE_QUEUE;
1194 retval = CLUTTER_TRANSLATE_CONTINUE;
1202 clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface)
1204 iface->translate_event = clutter_device_manager_xi2_translate_event;
1208 clutter_device_manager_xi2_add_device (ClutterDeviceManager *manager,
1209 ClutterInputDevice *device)
1215 clutter_device_manager_xi2_remove_device (ClutterDeviceManager *manager,
1216 ClutterInputDevice *device)
1221 static const GSList *
1222 clutter_device_manager_xi2_get_devices (ClutterDeviceManager *manager)
1224 ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (manager);
1225 GSList *all_devices = NULL;
1228 if (manager_xi2->all_devices != NULL)
1229 return manager_xi2->all_devices;
1231 for (l = manager_xi2->master_devices; l != NULL; l = l->next)
1232 all_devices = g_slist_prepend (all_devices, l->data);
1234 for (l = manager_xi2->slave_devices; l != NULL; l = l->next)
1235 all_devices = g_slist_prepend (all_devices, l->data);
1237 manager_xi2->all_devices = g_slist_reverse (all_devices);
1239 return manager_xi2->all_devices;
1242 static ClutterInputDevice *
1243 clutter_device_manager_xi2_get_device (ClutterDeviceManager *manager,
1246 ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (manager);
1248 return g_hash_table_lookup (manager_xi2->devices_by_id,
1249 GINT_TO_POINTER (id));
1252 static ClutterInputDevice *
1253 clutter_device_manager_xi2_get_core_device (ClutterDeviceManager *manager,
1254 ClutterInputDeviceType device_type)
1256 ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (manager);
1257 ClutterBackendX11 *backend_x11;
1258 ClutterInputDevice *device;
1262 CLUTTER_BACKEND_X11 (_clutter_device_manager_get_backend (manager));
1264 XIGetClientPointer (backend_x11->xdpy, None, &device_id);
1266 device = g_hash_table_lookup (manager_xi2->devices_by_id,
1267 GINT_TO_POINTER (device_id));
1269 switch (device_type)
1271 case CLUTTER_POINTER_DEVICE:
1274 case CLUTTER_KEYBOARD_DEVICE:
1275 return clutter_input_device_get_associated_device (device);
1285 relate_masters (gpointer key,
1289 ClutterDeviceManagerXI2 *manager_xi2 = data;
1290 ClutterInputDevice *device, *relative;
1292 device = g_hash_table_lookup (manager_xi2->devices_by_id, key);
1293 relative = g_hash_table_lookup (manager_xi2->devices_by_id, value);
1295 _clutter_input_device_set_associated_device (device, relative);
1296 _clutter_input_device_set_associated_device (relative, device);
1300 relate_slaves (gpointer key,
1304 ClutterDeviceManagerXI2 *manager_xi2 = data;
1305 ClutterInputDevice *master, *slave;
1307 master = g_hash_table_lookup (manager_xi2->devices_by_id, key);
1308 slave = g_hash_table_lookup (manager_xi2->devices_by_id, value);
1310 _clutter_input_device_set_associated_device (slave, master);
1311 _clutter_input_device_add_slave (master, slave);
1315 clutter_device_manager_xi2_constructed (GObject *gobject)
1317 ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (gobject);
1318 ClutterDeviceManager *manager = CLUTTER_DEVICE_MANAGER (gobject);
1319 ClutterBackendX11 *backend_x11;
1320 GHashTable *masters, *slaves;
1322 XIEventMask event_mask;
1323 unsigned char mask[2] = { 0, };
1327 CLUTTER_BACKEND_X11 (_clutter_device_manager_get_backend (manager));
1329 masters = g_hash_table_new (NULL, NULL);
1330 slaves = g_hash_table_new (NULL, NULL);
1332 info = XIQueryDevice (backend_x11->xdpy, XIAllDevices, &n_devices);
1334 for (i = 0; i < n_devices; i++)
1336 XIDeviceInfo *xi_device = &info[i];
1338 add_device (manager_xi2, backend_x11, xi_device, TRUE);
1340 if (xi_device->use == XIMasterPointer ||
1341 xi_device->use == XIMasterKeyboard)
1343 g_hash_table_insert (masters,
1344 GINT_TO_POINTER (xi_device->deviceid),
1345 GINT_TO_POINTER (xi_device->attachment));
1347 else if (xi_device->use == XISlavePointer ||
1348 xi_device->use == XISlaveKeyboard)
1350 g_hash_table_insert (slaves,
1351 GINT_TO_POINTER (xi_device->deviceid),
1352 GINT_TO_POINTER (xi_device->attachment));
1356 XIFreeDeviceInfo (info);
1358 g_hash_table_foreach (masters, relate_masters, manager_xi2);
1359 g_hash_table_destroy (masters);
1361 g_hash_table_foreach (slaves, relate_slaves, manager_xi2);
1362 g_hash_table_destroy (slaves);
1364 XISetMask (mask, XI_HierarchyChanged);
1365 XISetMask (mask, XI_DeviceChanged);
1367 event_mask.deviceid = XIAllDevices;
1368 event_mask.mask_len = sizeof (mask);
1369 event_mask.mask = mask;
1371 clutter_device_manager_xi2_select_events (manager,
1372 clutter_x11_get_root_window (),
1375 if (G_OBJECT_CLASS (clutter_device_manager_xi2_parent_class)->constructed)
1376 G_OBJECT_CLASS (clutter_device_manager_xi2_parent_class)->constructed (gobject);
1380 clutter_device_manager_xi2_set_property (GObject *gobject,
1382 const GValue *value,
1385 ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (gobject);
1390 manager_xi2->opcode = g_value_get_int (value);
1394 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
1400 clutter_device_manager_xi2_class_init (ClutterDeviceManagerXI2Class *klass)
1402 ClutterDeviceManagerClass *manager_class;
1403 GObjectClass *gobject_class;
1405 obj_props[PROP_OPCODE] =
1406 g_param_spec_int ("opcode",
1411 CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
1413 gobject_class = G_OBJECT_CLASS (klass);
1414 gobject_class->constructed = clutter_device_manager_xi2_constructed;
1415 gobject_class->set_property = clutter_device_manager_xi2_set_property;
1417 g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
1419 manager_class = CLUTTER_DEVICE_MANAGER_CLASS (klass);
1420 manager_class->add_device = clutter_device_manager_xi2_add_device;
1421 manager_class->remove_device = clutter_device_manager_xi2_remove_device;
1422 manager_class->get_devices = clutter_device_manager_xi2_get_devices;
1423 manager_class->get_core_device = clutter_device_manager_xi2_get_core_device;
1424 manager_class->get_device = clutter_device_manager_xi2_get_device;
1428 clutter_device_manager_xi2_init (ClutterDeviceManagerXI2 *self)
1430 self->devices_by_id = g_hash_table_new_full (NULL, NULL,
1432 (GDestroyNotify) g_object_unref);