1 /*
2 * Copyright (C) 2019 Red Hat Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Author: Carlos Garnacho <carlosg@gnome.org>
18 */
19 #include "config.h"
20 #ifdef __linux__
21 #include <linux/input-event-codes.h>
22 #endif
23 #include <X11/extensions/XInput2.h>
24 #include <X11/extensions/XKB.h>
25
26 #include "backends/meta-input-settings-private.h"
27 #include "backends/x11/meta-backend-x11.h"
28 #include "backends/x11/meta-clutter-backend-x11.h"
29 #include "backends/x11/meta-event-x11.h"
30 #include "backends/x11/meta-input-device-tool-x11.h"
31 #include "backends/x11/meta-input-device-x11.h"
32 #include "backends/x11/meta-keymap-x11.h"
33 #include "backends/x11/meta-stage-x11.h"
34 #include "backends/x11/meta-virtual-input-device-x11.h"
35 #include "backends/x11/meta-xkb-a11y-x11.h"
36 #include "clutter/clutter-mutter.h"
37 #include "core/bell.h"
38 #include "meta-seat-x11.h"
39
40 enum
41 {
42 PROP_0,
43 PROP_OPCODE,
44 PROP_POINTER_ID,
45 PROP_KEYBOARD_ID,
46 N_PROPS,
47
48 /* This property is overridden */
49 PROP_TOUCH_MODE,
50 };
51
52 typedef struct _MetaTouchInfo MetaTouchInfo;
53
54 struct _MetaTouchInfo
55 {
56 ClutterEventSequence *sequence;
57 double x;
58 double y;
59 };
60
61 struct _MetaSeatX11
62 {
63 ClutterSeat parent_instance;
64 ClutterInputDevice *core_pointer;
65 ClutterInputDevice *core_keyboard;
66 GList *devices;
67 GHashTable *devices_by_id;
68 GHashTable *tools_by_serial;
69 GHashTable *touch_coords;
70 MetaKeymapX11 *keymap;
71
72 int pointer_id;
73 int keyboard_id;
74 int opcode;
75 guint has_touchscreens : 1;
76 guint touch_mode : 1;
77 guint has_pointer_focus : 1;
78 };
79
80 static GParamSpec *props[N_PROPS] = { 0 };
81
82 G_DEFINE_TYPE (MetaSeatX11, meta_seat_x11, CLUTTER_TYPE_SEAT)
83
84 static const char *clutter_input_axis_atom_names[] = {
85 "Abs X", /* CLUTTER_INPUT_AXIS_X */
86 "Abs Y", /* CLUTTER_INPUT_AXIS_Y */
87 "Abs Pressure", /* CLUTTER_INPUT_AXIS_PRESSURE */
88 "Abs Tilt X", /* CLUTTER_INPUT_AXIS_XTILT */
89 "Abs Tilt Y", /* CLUTTER_INPUT_AXIS_YTILT */
90 "Abs Wheel", /* CLUTTER_INPUT_AXIS_WHEEL */
91 "Abs Distance", /* CLUTTER_INPUT_AXIS_DISTANCE */
92 };
93
94 static const char *wacom_type_atoms[] = {
95 "STYLUS",
96 "CURSOR",
97 "ERASER",
98 "PAD",
99 "TOUCH"
100 };
101 #define N_WACOM_TYPE_ATOMS G_N_ELEMENTS (wacom_type_atoms)
102
103 enum
104 {
105 WACOM_TYPE_STYLUS,
106 WACOM_TYPE_CURSOR,
107 WACOM_TYPE_ERASER,
108 WACOM_TYPE_PAD,
109 WACOM_TYPE_TOUCH,
110 };
111
112 enum
113 {
114 PAD_AXIS_FIRST = 3, /* First axes are always x/y/pressure, ignored in pads */
115 PAD_AXIS_STRIP1 = PAD_AXIS_FIRST,
116 PAD_AXIS_STRIP2,
117 PAD_AXIS_RING1,
118 PAD_AXIS_RING2,
119 };
120
121 #define N_AXIS_ATOMS G_N_ELEMENTS (clutter_input_axis_atom_names)
122
123 static Atom clutter_input_axis_atoms[N_AXIS_ATOMS] = { 0, };
124
125 static void
translate_valuator_class(Display * xdisplay,ClutterInputDevice * device,XIValuatorClassInfo * class)126 translate_valuator_class (Display *xdisplay,
127 ClutterInputDevice *device,
128 XIValuatorClassInfo *class)
129 {
130 static gboolean atoms_initialized = FALSE;
131 ClutterInputAxis i, axis = CLUTTER_INPUT_AXIS_IGNORE;
132
133 if (G_UNLIKELY (!atoms_initialized))
134 {
135 XInternAtoms (xdisplay,
136 (char **) clutter_input_axis_atom_names, N_AXIS_ATOMS,
137 False,
138 clutter_input_axis_atoms);
139
140 atoms_initialized = TRUE;
141 }
142
143 for (i = 0;
144 i < N_AXIS_ATOMS;
145 i += 1)
146 {
147 if (clutter_input_axis_atoms[i] == class->label)
148 {
149 axis = i + 1;
150 break;
151 }
152 }
153
154 meta_input_device_x11_add_axis (device, axis,
155 class->min,
156 class->max,
157 class->resolution);
158
159 g_debug ("Added axis '%s' (min:%.2f, max:%.2fd, res:%d) of device %d",
160 clutter_input_axis_atom_names[axis],
161 class->min,
162 class->max,
163 class->resolution,
164 meta_input_device_x11_get_device_id (device));
165 }
166
167 static void
translate_device_classes(Display * xdisplay,ClutterInputDevice * device,XIAnyClassInfo ** classes,int n_classes)168 translate_device_classes (Display *xdisplay,
169 ClutterInputDevice *device,
170 XIAnyClassInfo **classes,
171 int n_classes)
172 {
173 int i;
174
175 for (i = 0; i < n_classes; i++)
176 {
177 XIAnyClassInfo *class_info = classes[i];
178
179 switch (class_info->type)
180 {
181 case XIValuatorClass:
182 translate_valuator_class (xdisplay, device,
183 (XIValuatorClassInfo *) class_info);
184 break;
185
186 case XIScrollClass:
187 {
188 XIScrollClassInfo *scroll_info = (XIScrollClassInfo *) class_info;
189 ClutterScrollDirection direction;
190
191 if (scroll_info->scroll_type == XIScrollTypeVertical)
192 direction = CLUTTER_SCROLL_DOWN;
193 else
194 direction = CLUTTER_SCROLL_RIGHT;
195
196 g_debug ("Scroll valuator %d: %s, increment: %f",
197 scroll_info->number,
198 scroll_info->scroll_type == XIScrollTypeVertical
199 ? "vertical"
200 : "horizontal",
201 scroll_info->increment);
202
203 meta_input_device_x11_add_scroll_info (device,
204 scroll_info->number,
205 direction,
206 scroll_info->increment);
207 }
208 break;
209
210 default:
211 break;
212 }
213 }
214 }
215
216 static gboolean
is_touch_device(XIAnyClassInfo ** classes,int n_classes,ClutterInputDeviceType * device_type,uint32_t * n_touch_points)217 is_touch_device (XIAnyClassInfo **classes,
218 int n_classes,
219 ClutterInputDeviceType *device_type,
220 uint32_t *n_touch_points)
221 {
222 int i;
223
224 for (i = 0; i < n_classes; i++)
225 {
226 XITouchClassInfo *class = (XITouchClassInfo *) classes[i];
227
228 if (class->type != XITouchClass)
229 continue;
230
231 if (class->num_touches > 0)
232 {
233 if (class->mode == XIDirectTouch)
234 *device_type = CLUTTER_TOUCHSCREEN_DEVICE;
235 else if (class->mode == XIDependentTouch)
236 *device_type = CLUTTER_TOUCHPAD_DEVICE;
237 else
238 continue;
239
240 *n_touch_points = class->num_touches;
241
242 return TRUE;
243 }
244 }
245
246 return FALSE;
247 }
248
249 static gboolean
is_touchpad_device(XIDeviceInfo * info)250 is_touchpad_device (XIDeviceInfo *info)
251 {
252 gulong nitems, bytes_after;
253 uint32_t *data = NULL;
254 int rc, format;
255 Atom type;
256 Atom prop;
257
258 prop = XInternAtom (meta_clutter_x11_get_default_display (),
259 "libinput Tapping Enabled", True);
260 if (prop == None)
261 return FALSE;
262
263 meta_clutter_x11_trap_x_errors ();
264 rc = XIGetProperty (meta_clutter_x11_get_default_display (),
265 info->deviceid,
266 prop,
267 0, 1, False, XA_INTEGER, &type, &format, &nitems, &bytes_after,
268 (guchar **) &data);
269 meta_clutter_x11_untrap_x_errors ();
270
271 /* We don't care about the data */
272 XFree (data);
273
274 if (rc != Success || type != XA_INTEGER || format != 8 || nitems != 1)
275 return FALSE;
276
277 return TRUE;
278 }
279
280 static gboolean
get_device_ids(XIDeviceInfo * info,char ** vendor_id,char ** product_id)281 get_device_ids (XIDeviceInfo *info,
282 char **vendor_id,
283 char **product_id)
284 {
285 gulong nitems, bytes_after;
286 uint32_t *data = NULL;
287 int rc, format;
288 Atom type;
289
290 meta_clutter_x11_trap_x_errors ();
291 rc = XIGetProperty (meta_clutter_x11_get_default_display (),
292 info->deviceid,
293 XInternAtom (meta_clutter_x11_get_default_display (), "Device Product ID", False),
294 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after,
295 (guchar **) &data);
296 meta_clutter_x11_untrap_x_errors ();
297
298 if (rc != Success || type != XA_INTEGER || format != 32 || nitems != 2)
299 {
300 XFree (data);
301 return FALSE;
302 }
303
304 if (vendor_id)
305 *vendor_id = g_strdup_printf ("%.4x", data[0]);
306 if (product_id)
307 *product_id = g_strdup_printf ("%.4x", data[1]);
308
309 XFree (data);
310
311 return TRUE;
312 }
313
314 static char *
get_device_node_path(XIDeviceInfo * info)315 get_device_node_path (XIDeviceInfo *info)
316 {
317 gulong nitems, bytes_after;
318 guchar *data;
319 int rc, format;
320 Atom prop, type;
321 char *node_path;
322
323 prop = XInternAtom (meta_clutter_x11_get_default_display (), "Device Node", False);
324 if (prop == None)
325 return NULL;
326
327 meta_clutter_x11_trap_x_errors ();
328
329 rc = XIGetProperty (meta_clutter_x11_get_default_display (),
330 info->deviceid, prop, 0, 1024, False,
331 XA_STRING, &type, &format, &nitems, &bytes_after,
332 (guchar **) &data);
333
334 if (meta_clutter_x11_untrap_x_errors ())
335 return NULL;
336
337 if (rc != Success || type != XA_STRING || format != 8)
338 {
339 XFree (data);
340 return FALSE;
341 }
342
343 node_path = g_strdup ((char *) data);
344 XFree (data);
345
346 return node_path;
347 }
348
349 static void
get_pad_features(XIDeviceInfo * info,uint32_t * n_rings,uint32_t * n_strips)350 get_pad_features (XIDeviceInfo *info,
351 uint32_t *n_rings,
352 uint32_t *n_strips)
353 {
354 int i, rings = 0, strips = 0;
355
356 for (i = PAD_AXIS_FIRST; i < info->num_classes; i++)
357 {
358 XIValuatorClassInfo *valuator = (XIValuatorClassInfo*) info->classes[i];
359 int axis = valuator->number;
360
361 if (valuator->type != XIValuatorClass)
362 continue;
363 if (valuator->max <= 1)
364 continue;
365
366 /* Ring/strip axes are fixed in pad devices as handled by the
367 * wacom driver. Match those to detect pad features.
368 */
369 if (axis == PAD_AXIS_STRIP1 || axis == PAD_AXIS_STRIP2)
370 strips++;
371 else if (axis == PAD_AXIS_RING1 || axis == PAD_AXIS_RING2)
372 rings++;
373 }
374
375 *n_rings = rings;
376 *n_strips = strips;
377 }
378
379 /* The Wacom driver exports the tool type as property. Use that over
380 guessing based on the device name */
381 static gboolean
guess_source_from_wacom_type(XIDeviceInfo * info,ClutterInputDeviceType * source_out)382 guess_source_from_wacom_type (XIDeviceInfo *info,
383 ClutterInputDeviceType *source_out)
384 {
385 gulong nitems, bytes_after;
386 uint32_t *data = NULL;
387 int rc, format;
388 Atom type;
389 Atom prop;
390 Atom device_type;
391 Atom types[N_WACOM_TYPE_ATOMS];
392
393 prop = XInternAtom (meta_clutter_x11_get_default_display (), "Wacom Tool Type", True);
394 if (prop == None)
395 return FALSE;
396
397 meta_clutter_x11_trap_x_errors ();
398 rc = XIGetProperty (meta_clutter_x11_get_default_display (),
399 info->deviceid,
400 prop,
401 0, 1, False, XA_ATOM, &type, &format, &nitems, &bytes_after,
402 (guchar **) &data);
403 meta_clutter_x11_untrap_x_errors ();
404
405 if (rc != Success || type != XA_ATOM || format != 32 || nitems != 1)
406 {
407 XFree (data);
408 return FALSE;
409 }
410
411 device_type = *data;
412 XFree (data);
413
414 if (device_type == 0)
415 return FALSE;
416
417 rc = XInternAtoms (meta_clutter_x11_get_default_display (),
418 (char **)wacom_type_atoms,
419 N_WACOM_TYPE_ATOMS,
420 False,
421 types);
422 if (rc == 0)
423 return FALSE;
424
425 if (device_type == types[WACOM_TYPE_STYLUS])
426 {
427 *source_out = CLUTTER_PEN_DEVICE;
428 }
429 else if (device_type == types[WACOM_TYPE_CURSOR])
430 {
431 *source_out = CLUTTER_CURSOR_DEVICE;
432 }
433 else if (device_type == types[WACOM_TYPE_ERASER])
434 {
435 *source_out = CLUTTER_ERASER_DEVICE;
436 }
437 else if (device_type == types[WACOM_TYPE_PAD])
438 {
439 *source_out = CLUTTER_PAD_DEVICE;
440 }
441 else if (device_type == types[WACOM_TYPE_TOUCH])
442 {
443 uint32_t num_touches = 0;
444
445 if (!is_touch_device (info->classes, info->num_classes,
446 source_out, &num_touches))
447 *source_out = CLUTTER_TOUCHSCREEN_DEVICE;
448 }
449 else
450 {
451 return FALSE;
452 }
453
454 return TRUE;
455 }
456
457 static ClutterInputDevice *
create_device(MetaSeatX11 * seat_x11,ClutterBackend * backend,XIDeviceInfo * info)458 create_device (MetaSeatX11 *seat_x11,
459 ClutterBackend *backend,
460 XIDeviceInfo *info)
461 {
462 ClutterInputDeviceType source, touch_source;
463 ClutterInputDevice *retval;
464 ClutterInputMode mode;
465 uint32_t num_touches = 0, num_rings = 0, num_strips = 0;
466 char *vendor_id = NULL, *product_id = NULL, *node_path = NULL;
467
468 if (info->use == XIMasterKeyboard || info->use == XISlaveKeyboard)
469 {
470 source = CLUTTER_KEYBOARD_DEVICE;
471 }
472 else if (is_touchpad_device (info))
473 {
474 source = CLUTTER_TOUCHPAD_DEVICE;
475 }
476 else if (info->use == XISlavePointer &&
477 is_touch_device (info->classes, info->num_classes,
478 &touch_source,
479 &num_touches))
480 {
481 source = touch_source;
482 }
483 else if (!guess_source_from_wacom_type (info, &source))
484 {
485 char *name;
486
487 name = g_ascii_strdown (info->name, -1);
488
489 if (strstr (name, "eraser") != NULL)
490 source = CLUTTER_ERASER_DEVICE;
491 else if (strstr (name, "cursor") != NULL)
492 source = CLUTTER_CURSOR_DEVICE;
493 else if (strstr (name, " pad") != NULL)
494 source = CLUTTER_PAD_DEVICE;
495 else if (strstr (name, "wacom") != NULL || strstr (name, "pen") != NULL)
496 source = CLUTTER_PEN_DEVICE;
497 else if (strstr (name, "touchpad") != NULL)
498 source = CLUTTER_TOUCHPAD_DEVICE;
499 else
500 source = CLUTTER_POINTER_DEVICE;
501
502 g_free (name);
503 }
504
505 switch (info->use)
506 {
507 case XIMasterKeyboard:
508 case XIMasterPointer:
509 mode = CLUTTER_INPUT_MODE_LOGICAL;
510 break;
511
512 case XISlaveKeyboard:
513 case XISlavePointer:
514 mode = CLUTTER_INPUT_MODE_PHYSICAL;
515 break;
516
517 case XIFloatingSlave:
518 default:
519 mode = CLUTTER_INPUT_MODE_FLOATING;
520 break;
521 }
522
523 if (info->use != XIMasterKeyboard &&
524 info->use != XIMasterPointer)
525 {
526 get_device_ids (info, &vendor_id, &product_id);
527 node_path = get_device_node_path (info);
528 }
529
530 if (source == CLUTTER_PAD_DEVICE)
531 get_pad_features (info, &num_rings, &num_strips);
532
533 retval = g_object_new (META_TYPE_INPUT_DEVICE_X11,
534 "name", info->name,
535 "id", info->deviceid,
536 "has-cursor", (info->use == XIMasterPointer),
537 "device-type", source,
538 "device-mode", mode,
539 "backend", backend,
540 "vendor-id", vendor_id,
541 "product-id", product_id,
542 "device-node", node_path,
543 "n-rings", num_rings,
544 "n-strips", num_strips,
545 "n-mode-groups", MAX (num_rings, num_strips),
546 "seat", seat_x11,
547 NULL);
548
549 translate_device_classes (meta_clutter_x11_get_default_display (), retval,
550 info->classes,
551 info->num_classes);
552
553 g_free (vendor_id);
554 g_free (product_id);
555 g_free (node_path);
556
557 g_debug ("Created device '%s' (id: %d, has-cursor: %s)",
558 info->name,
559 info->deviceid,
560 info->use == XIMasterPointer ? "yes" : "no");
561
562 return retval;
563 }
564
565 static void
pad_passive_button_grab(ClutterInputDevice * device)566 pad_passive_button_grab (ClutterInputDevice *device)
567 {
568 XIGrabModifiers xi_grab_mods = { XIAnyModifier, };
569 XIEventMask xi_event_mask;
570 int device_id, rc;
571
572 device_id = meta_input_device_x11_get_device_id (device);
573
574 xi_event_mask.deviceid = device_id;
575 xi_event_mask.mask_len = XIMaskLen (XI_LASTEVENT);
576 xi_event_mask.mask = g_new0 (unsigned char, xi_event_mask.mask_len);
577
578 XISetMask (xi_event_mask.mask, XI_Motion);
579 XISetMask (xi_event_mask.mask, XI_ButtonPress);
580 XISetMask (xi_event_mask.mask, XI_ButtonRelease);
581
582 meta_clutter_x11_trap_x_errors ();
583 rc = XIGrabButton (meta_clutter_x11_get_default_display (),
584 device_id, XIAnyButton,
585 meta_clutter_x11_get_root_window (), None,
586 XIGrabModeSync, XIGrabModeSync,
587 True, &xi_event_mask, 1, &xi_grab_mods);
588 if (rc != 0)
589 {
590 g_warning ("Could not passively grab pad device: %s",
591 clutter_input_device_get_device_name (device));
592 }
593 else
594 {
595 XIAllowEvents (meta_clutter_x11_get_default_display (),
596 device_id, XIAsyncDevice,
597 CLUTTER_CURRENT_TIME);
598 }
599
600 meta_clutter_x11_untrap_x_errors ();
601
602 g_free (xi_event_mask.mask);
603 }
604
605 static void
update_touch_mode(MetaSeatX11 * seat_x11)606 update_touch_mode (MetaSeatX11 *seat_x11)
607 {
608 gboolean touch_mode;
609
610 touch_mode = seat_x11->has_touchscreens;
611
612 if (seat_x11->touch_mode == touch_mode)
613 return;
614
615 seat_x11->touch_mode = touch_mode;
616 g_object_notify (G_OBJECT (seat_x11), "touch-mode");
617 }
618
619 static ClutterInputDevice *
add_device(MetaSeatX11 * seat_x11,ClutterBackend * backend,XIDeviceInfo * info)620 add_device (MetaSeatX11 *seat_x11,
621 ClutterBackend *backend,
622 XIDeviceInfo *info)
623 {
624 ClutterInputDevice *device;
625
626 device = create_device (seat_x11, backend, info);
627
628 g_hash_table_replace (seat_x11->devices_by_id,
629 GINT_TO_POINTER (info->deviceid),
630 device);
631
632 if (info->use == XIMasterPointer &&
633 info->deviceid == seat_x11->pointer_id)
634 {
635 seat_x11->core_pointer = device;
636 }
637 else if (info->use == XIMasterKeyboard &&
638 info->deviceid == seat_x11->keyboard_id)
639 {
640 seat_x11->core_keyboard = device;
641 }
642 else if ((info->use == XISlavePointer &&
643 info->attachment == seat_x11->pointer_id) ||
644 (info->use == XISlaveKeyboard &&
645 info->attachment == seat_x11->keyboard_id))
646 {
647 seat_x11->devices = g_list_prepend (seat_x11->devices, device);
648 }
649 else
650 {
651 g_warning ("Unhandled device: %s",
652 clutter_input_device_get_device_name (device));
653 }
654
655 if (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE)
656 pad_passive_button_grab (device);
657
658 return device;
659 }
660
661 static gboolean
has_touchscreens(MetaSeatX11 * seat_x11)662 has_touchscreens (MetaSeatX11 *seat_x11)
663 {
664 GList *l;
665
666 for (l = seat_x11->devices; l; l = l->next)
667 {
668 if (clutter_input_device_get_device_type (l->data) == CLUTTER_TOUCHSCREEN_DEVICE)
669 return TRUE;
670 }
671
672 return FALSE;
673 }
674
675 static void
remove_device(MetaSeatX11 * seat_x11,ClutterInputDevice * device)676 remove_device (MetaSeatX11 *seat_x11,
677 ClutterInputDevice *device)
678 {
679 if (seat_x11->core_pointer == device)
680 {
681 seat_x11->core_pointer = NULL;
682 }
683 else if (seat_x11->core_keyboard == device)
684 {
685 seat_x11->core_keyboard = NULL;
686 }
687 else
688 {
689 seat_x11->devices = g_list_remove (seat_x11->devices, device);
690 }
691 }
692
693 static gboolean
meta_seat_x11_handle_event_post(ClutterSeat * seat,const ClutterEvent * event)694 meta_seat_x11_handle_event_post (ClutterSeat *seat,
695 const ClutterEvent *event)
696 {
697 MetaSeatX11 *seat_x11 = META_SEAT_X11 (seat);
698 ClutterInputDevice *device;
699 MetaInputSettings *input_settings;
700 gboolean is_touch;
701
702 if (event->type != CLUTTER_DEVICE_ADDED &&
703 event->type != CLUTTER_DEVICE_REMOVED)
704 return TRUE;
705
706 device = clutter_event_get_device (event);
707 is_touch =
708 clutter_input_device_get_device_type (device) == CLUTTER_TOUCHSCREEN_DEVICE;
709 input_settings = meta_backend_get_input_settings (meta_get_backend ());
710
711 switch (event->type)
712 {
713 case CLUTTER_DEVICE_ADDED:
714 meta_input_settings_add_device (input_settings, device);
715 seat_x11->has_touchscreens |= is_touch;
716 break;
717 case CLUTTER_DEVICE_REMOVED:
718 if (is_touch)
719 seat_x11->has_touchscreens = has_touchscreens (seat_x11);
720 meta_input_settings_remove_device (input_settings, device);
721 break;
722 default:
723 break;
724 }
725
726 if (is_touch)
727 update_touch_mode (seat_x11);
728
729 return TRUE;
730 }
731
732 static uint
device_get_tool_serial(ClutterInputDevice * device)733 device_get_tool_serial (ClutterInputDevice *device)
734 {
735 gulong nitems, bytes_after;
736 uint32_t *data = NULL;
737 int serial_id = 0;
738 int rc, format;
739 Atom type;
740 Atom prop;
741
742 prop = XInternAtom (meta_clutter_x11_get_default_display (),
743 "Wacom Serial IDs", True);
744 if (prop == None)
745 return 0;
746
747 meta_clutter_x11_trap_x_errors ();
748 rc = XIGetProperty (meta_clutter_x11_get_default_display (),
749 meta_input_device_x11_get_device_id (device),
750 prop, 0, 4, FALSE, XA_INTEGER, &type, &format, &nitems, &bytes_after,
751 (guchar **) &data);
752 meta_clutter_x11_untrap_x_errors ();
753
754 if (rc == Success && type == XA_INTEGER && format == 32 && nitems >= 4)
755 serial_id = data[3];
756
757 XFree (data);
758
759 return serial_id;
760 }
761
762 static gboolean
translate_hierarchy_event(ClutterBackend * backend,MetaSeatX11 * seat_x11,XIHierarchyEvent * ev,ClutterEvent * event)763 translate_hierarchy_event (ClutterBackend *backend,
764 MetaSeatX11 *seat_x11,
765 XIHierarchyEvent *ev,
766 ClutterEvent *event)
767 {
768 int i;
769 gboolean retval = FALSE;
770
771 for (i = 0; i < ev->num_info; i++)
772 {
773 if (ev->info[i].flags & XIDeviceEnabled &&
774 !g_hash_table_lookup (seat_x11->devices_by_id,
775 GINT_TO_POINTER (ev->info[i].deviceid)))
776 {
777 XIDeviceInfo *info;
778 int n_devices;
779
780 g_debug ("Hierarchy event: device enabled");
781
782 meta_clutter_x11_trap_x_errors ();
783 info = XIQueryDevice (meta_clutter_x11_get_default_display (),
784 ev->info[i].deviceid,
785 &n_devices);
786 meta_clutter_x11_untrap_x_errors ();
787 if (info != NULL)
788 {
789 ClutterInputDevice *device;
790
791 device = add_device (seat_x11, backend, &info[0]);
792
793 event->any.type = CLUTTER_DEVICE_ADDED;
794 event->any.time = ev->time;
795 clutter_event_set_device (event, device);
796
797 retval = TRUE;
798 XIFreeDeviceInfo (info);
799 }
800 }
801 else if (ev->info[i].flags & XIDeviceDisabled)
802 {
803 g_autoptr (ClutterInputDevice) device = NULL;
804 g_debug ("Hierarchy event: device disabled");
805
806 g_hash_table_steal_extended (seat_x11->devices_by_id,
807 GINT_TO_POINTER (ev->info[i].deviceid),
808 NULL,
809 (gpointer) &device);
810
811 if (device != NULL)
812 {
813 remove_device (seat_x11, device);
814
815 event->any.type = CLUTTER_DEVICE_REMOVED;
816 event->any.time = ev->time;
817 clutter_event_set_device (event, device);
818
819 retval = TRUE;
820 }
821 }
822 else if ((ev->info[i].flags & XISlaveAttached) ||
823 (ev->info[i].flags & XISlaveDetached))
824 {
825 g_debug ("Hierarchy event: physical device %s",
826 (ev->info[i].flags & XISlaveAttached)
827 ? "attached"
828 : "detached");
829 }
830 }
831
832 return retval;
833 }
834
835 static void
translate_property_event(MetaSeatX11 * seat_x11,XIEvent * event)836 translate_property_event (MetaSeatX11 *seat_x11,
837 XIEvent *event)
838 {
839 XIPropertyEvent *xev = (XIPropertyEvent *) event;
840 Atom serial_ids_prop;
841 ClutterInputDevice *device;
842
843 serial_ids_prop = XInternAtom (meta_clutter_x11_get_default_display (),
844 "Wacom Serial IDs", True);
845 if (serial_ids_prop == None)
846 return;
847
848 device = g_hash_table_lookup (seat_x11->devices_by_id,
849 GINT_TO_POINTER (xev->deviceid));
850 if (!device)
851 return;
852
853 if (xev->property == serial_ids_prop)
854 {
855 ClutterInputDeviceTool *tool = NULL;
856 ClutterInputDeviceToolType type;
857 MetaInputSettings *input_settings;
858 int serial_id;
859
860 serial_id = device_get_tool_serial (device);
861
862 if (serial_id != 0)
863 {
864 tool = g_hash_table_lookup (seat_x11->tools_by_serial,
865 GUINT_TO_POINTER (serial_id));
866 if (!tool)
867 {
868 type = clutter_input_device_get_device_type (device) == CLUTTER_ERASER_DEVICE ?
869 CLUTTER_INPUT_DEVICE_TOOL_ERASER : CLUTTER_INPUT_DEVICE_TOOL_PEN;
870 tool = meta_input_device_tool_x11_new (serial_id, type);
871 g_hash_table_insert (seat_x11->tools_by_serial,
872 GUINT_TO_POINTER (serial_id),
873 tool);
874 }
875 }
876
877 meta_input_device_x11_update_tool (device, tool);
878 input_settings = meta_backend_get_input_settings (meta_get_backend ());
879 meta_input_settings_notify_tool_change (input_settings, device, tool);
880 }
881 }
882
883 static void
emulate_motion(MetaSeatX11 * seat_x11,double x,double y)884 emulate_motion (MetaSeatX11 *seat_x11,
885 double x,
886 double y)
887 {
888 ClutterInputDevice *pointer;
889 ClutterEvent *event;
890 ClutterStage *stage;
891
892 pointer = clutter_seat_get_pointer (CLUTTER_SEAT (seat_x11));
893 stage = CLUTTER_STAGE (meta_backend_get_stage (meta_get_backend ()));
894
895 event = clutter_event_new (CLUTTER_MOTION);
896 clutter_event_set_flags (event, CLUTTER_EVENT_FLAG_SYNTHETIC);
897 clutter_event_set_coords (event, x, y);
898 clutter_event_set_device (event, pointer);
899 clutter_event_set_source_device (event, NULL);
900 clutter_event_set_stage (event, stage);
901
902 clutter_event_put (event);
903 clutter_event_free (event);
904 }
905
906 static void
translate_raw_event(MetaSeatX11 * seat_x11,XEvent * xevent)907 translate_raw_event (MetaSeatX11 *seat_x11,
908 XEvent *xevent)
909 {
910 ClutterInputDevice *device;
911 XGenericEventCookie *cookie;
912 XIEvent *xi_event;
913 XIRawEvent *xev;
914 float x,y;
915
916 cookie = &xevent->xcookie;
917 xi_event = (XIEvent *) cookie->data;
918 xev = (XIRawEvent *) xi_event;
919
920 device = g_hash_table_lookup (seat_x11->devices_by_id,
921 GINT_TO_POINTER (xev->deviceid));
922 if (device == NULL)
923 return;
924
925 switch (cookie->evtype)
926 {
927 case XI_RawMotion:
928 g_debug ("raw motion: device:%d '%s'",
929 meta_input_device_x11_get_device_id (device),
930 clutter_input_device_get_device_name (device));
931
932 /* We don't get actual pointer location with raw events, and we cannot
933 * rely on `clutter_input_device_get_coords()` either because of
934 * unreparented toplevels (like all client-side decoration windows),
935 * so we need to explicitly query the pointer here...
936 */
937 if (meta_input_device_x11_get_pointer_location (device, &x, &y))
938 {
939 if (_clutter_is_input_pointer_a11y_enabled (device))
940 _clutter_input_pointer_a11y_on_motion_event (device, x, y);
941 if (!seat_x11->has_pointer_focus)
942 emulate_motion (seat_x11, x, y);
943 }
944 break;
945 case XI_RawButtonPress:
946 case XI_RawButtonRelease:
947 g_debug ("raw button %s: device:%d '%s' button %i",
948 cookie->evtype == XI_RawButtonPress
949 ? "press "
950 : "release",
951 meta_input_device_x11_get_device_id (device),
952 clutter_input_device_get_device_name (device),
953 xev->detail);
954 if (_clutter_is_input_pointer_a11y_enabled (device))
955 {
956 _clutter_input_pointer_a11y_on_button_event (device,
957 xev->detail,
958 (cookie->evtype == XI_RawButtonPress));
959 }
960 break;
961 }
962 }
963
964 static gboolean
translate_pad_axis(ClutterInputDevice * device,XIValuatorState * valuators,ClutterEventType * evtype,uint32_t * number,double * value)965 translate_pad_axis (ClutterInputDevice *device,
966 XIValuatorState *valuators,
967 ClutterEventType *evtype,
968 uint32_t *number,
969 double *value)
970 {
971 double *values;
972 int i;
973
974 values = valuators->values;
975
976 for (i = PAD_AXIS_FIRST; i < valuators->mask_len * 8; i++)
977 {
978 double val;
979 uint32_t axis_number = 0;
980
981 if (!XIMaskIsSet (valuators->mask, i))
982 continue;
983
984 val = *values++;
985 if (val <= 0)
986 continue;
987
988 meta_input_device_x11_translate_axis (device, i, val, value);
989
990 if (i == PAD_AXIS_RING1 || i == PAD_AXIS_RING2)
991 {
992 *evtype = CLUTTER_PAD_RING;
993 (*value) *= 360.0;
994 }
995 else if (i == PAD_AXIS_STRIP1 || i == PAD_AXIS_STRIP2)
996 {
997 *evtype = CLUTTER_PAD_STRIP;
998 }
999 else
1000 continue;
1001
1002 if (i == PAD_AXIS_STRIP2 || i == PAD_AXIS_RING2)
1003 axis_number++;
1004
1005 *number = axis_number;
1006 return TRUE;
1007 }
1008
1009 return FALSE;
1010 }
1011
1012 static gboolean
translate_pad_event(ClutterEvent * event,XIDeviceEvent * xev,ClutterInputDevice * device)1013 translate_pad_event (ClutterEvent *event,
1014 XIDeviceEvent *xev,
1015 ClutterInputDevice *device)
1016 {
1017 double value;
1018 uint32_t number, mode = 0;
1019
1020 if (!translate_pad_axis (device, &xev->valuators,
1021 &event->any.type,
1022 &number, &value))
1023 return FALSE;
1024
1025 /* When touching a ring/strip a first XI_Motion event
1026 * is generated. Use it to reset the pad state, so
1027 * later events actually have a directionality.
1028 */
1029 if (xev->evtype == XI_Motion)
1030 value = -1;
1031
1032 #ifdef HAVE_LIBWACOM
1033 mode = meta_input_device_x11_get_pad_group_mode (device, number);
1034 #endif
1035
1036 if (event->any.type == CLUTTER_PAD_RING)
1037 {
1038 event->pad_ring.ring_number = number;
1039 event->pad_ring.angle = value;
1040 event->pad_ring.mode = mode;
1041 }
1042 else
1043 {
1044 event->pad_strip.strip_number = number;
1045 event->pad_strip.value = value;
1046 event->pad_strip.mode = mode;
1047 }
1048
1049 event->any.time = xev->time;
1050 clutter_event_set_device (event, device);
1051 clutter_event_set_source_device (event, device);
1052
1053 g_debug ("%s: win:0x%x, device:%d '%s', time:%d "
1054 "(value:%f)",
1055 event->any.type == CLUTTER_PAD_RING
1056 ? "pad ring "
1057 : "pad strip",
1058 (unsigned int) xev->event,
1059 meta_input_device_x11_get_device_id (device),
1060 clutter_input_device_get_device_name (device),
1061 event->any.time, value);
1062
1063 return TRUE;
1064 }
1065
1066 static ClutterStage *
get_event_stage(MetaSeatX11 * seat_x11,XIEvent * xi_event)1067 get_event_stage (MetaSeatX11 *seat_x11,
1068 XIEvent *xi_event)
1069 {
1070 Window xwindow = None;
1071
1072 switch (xi_event->evtype)
1073 {
1074 case XI_KeyPress:
1075 case XI_KeyRelease:
1076 case XI_ButtonPress:
1077 case XI_ButtonRelease:
1078 case XI_Motion:
1079 case XI_TouchBegin:
1080 case XI_TouchUpdate:
1081 case XI_TouchEnd:
1082 {
1083 XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
1084
1085 xwindow = xev->event;
1086 }
1087 break;
1088
1089 case XI_Enter:
1090 case XI_Leave:
1091 case XI_FocusIn:
1092 case XI_FocusOut:
1093 {
1094 XIEnterEvent *xev = (XIEnterEvent *) xi_event;
1095
1096 xwindow = xev->event;
1097 }
1098 break;
1099
1100 case XI_HierarchyChanged:
1101 return CLUTTER_STAGE (meta_backend_get_stage (meta_get_backend ()));
1102
1103 default:
1104 break;
1105 }
1106
1107 if (xwindow == None)
1108 return NULL;
1109
1110 return meta_x11_get_stage_from_window (xwindow);
1111 }
1112
1113 /*
1114 * print_key_sym: Translate a symbol to its printable form if any
1115 * @symbol: the symbol to translate
1116 * @buffer: the buffer where to put the translated string
1117 * @len: size of the buffer
1118 *
1119 * Translates @symbol into a printable representation in @buffer, if possible.
1120 *
1121 * Return value: The number of bytes of the translated string, 0 if the
1122 * symbol can't be printed
1123 *
1124 * Note: The code is derived from libX11's src/KeyBind.c
1125 * Copyright 1985, 1987, 1998 The Open Group
1126 *
1127 * Note: This code works for Latin-1 symbols. clutter_keysym_to_unicode()
1128 * does the work for the other keysyms.
1129 */
1130 static int
print_keysym(uint32_t symbol,char * buffer,int len)1131 print_keysym (uint32_t symbol,
1132 char *buffer,
1133 int len)
1134 {
1135 unsigned long high_bytes;
1136 unsigned char c;
1137
1138 high_bytes = symbol >> 8;
1139 if (!(len &&
1140 ((high_bytes == 0) ||
1141 ((high_bytes == 0xFF) &&
1142 (((symbol >= CLUTTER_KEY_BackSpace) &&
1143 (symbol <= CLUTTER_KEY_Clear)) ||
1144 (symbol == CLUTTER_KEY_Return) ||
1145 (symbol == CLUTTER_KEY_Escape) ||
1146 (symbol == CLUTTER_KEY_KP_Space) ||
1147 (symbol == CLUTTER_KEY_KP_Tab) ||
1148 (symbol == CLUTTER_KEY_KP_Enter) ||
1149 ((symbol >= CLUTTER_KEY_KP_Multiply) &&
1150 (symbol <= CLUTTER_KEY_KP_9)) ||
1151 (symbol == CLUTTER_KEY_KP_Equal) ||
1152 (symbol == CLUTTER_KEY_Delete))))))
1153 return 0;
1154
1155 /* if X keysym, convert to ascii by grabbing low 7 bits */
1156 if (symbol == CLUTTER_KEY_KP_Space)
1157 c = CLUTTER_KEY_space & 0x7F; /* patch encoding botch */
1158 else if (high_bytes == 0xFF)
1159 c = symbol & 0x7F;
1160 else
1161 c = symbol & 0xFF;
1162
1163 buffer[0] = c;
1164 return 1;
1165 }
1166
1167 static double *
translate_axes(ClutterInputDevice * device,double x,double y,XIValuatorState * valuators)1168 translate_axes (ClutterInputDevice *device,
1169 double x,
1170 double y,
1171 XIValuatorState *valuators)
1172 {
1173 uint32_t i;
1174 double *retval;
1175 double *values;
1176
1177 retval = g_new0 (double, CLUTTER_INPUT_AXIS_LAST);
1178 values = valuators->values;
1179
1180 for (i = 0; i < valuators->mask_len * 8; i++)
1181 {
1182 ClutterInputAxis axis;
1183 double val;
1184
1185 if (!XIMaskIsSet (valuators->mask, i))
1186 continue;
1187 if (!meta_input_device_x11_get_axis (device, i, &axis))
1188 continue;
1189
1190 val = *values++;
1191
1192 switch (axis)
1193 {
1194 case CLUTTER_INPUT_AXIS_X:
1195 retval[axis] = x;
1196 break;
1197
1198 case CLUTTER_INPUT_AXIS_Y:
1199 retval[axis] = y;
1200 break;
1201
1202 default:
1203 meta_input_device_x11_translate_axis (device, i, val, &retval[axis]);
1204 break;
1205 }
1206 }
1207
1208 return retval;
1209 }
1210
1211 static double
scroll_valuators_changed(ClutterInputDevice * device,XIValuatorState * valuators,double * dx_p,double * dy_p)1212 scroll_valuators_changed (ClutterInputDevice *device,
1213 XIValuatorState *valuators,
1214 double *dx_p,
1215 double *dy_p)
1216 {
1217 gboolean retval = FALSE;
1218 uint32_t n_axes, n_val, i;
1219 double *values;
1220
1221 n_axes = meta_input_device_x11_get_n_axes (device);
1222 values = valuators->values;
1223
1224 *dx_p = *dy_p = 0.0;
1225
1226 n_val = 0;
1227
1228 for (i = 0; i < MIN (valuators->mask_len * 8, n_axes); i++)
1229 {
1230 ClutterScrollDirection direction;
1231 double delta;
1232
1233 if (!XIMaskIsSet (valuators->mask, i))
1234 continue;
1235
1236 if (meta_input_device_x11_get_scroll_delta (device, i,
1237 values[n_val],
1238 &direction,
1239 &delta))
1240 {
1241 retval = TRUE;
1242
1243 if (direction == CLUTTER_SCROLL_UP ||
1244 direction == CLUTTER_SCROLL_DOWN)
1245 *dy_p = delta;
1246 else
1247 *dx_p = delta;
1248 }
1249
1250 n_val += 1;
1251 }
1252
1253 return retval;
1254 }
1255
1256 static void
translate_coords(MetaStageX11 * stage_x11,double event_x,double event_y,float * x_out,float * y_out)1257 translate_coords (MetaStageX11 *stage_x11,
1258 double event_x,
1259 double event_y,
1260 float *x_out,
1261 float *y_out)
1262 {
1263 MetaStageImpl *stage_impl = META_STAGE_IMPL (stage_x11);
1264 ClutterActor *stage = CLUTTER_ACTOR (stage_impl->wrapper);
1265 float stage_width;
1266 float stage_height;
1267
1268 clutter_actor_get_size (stage, &stage_width, &stage_height);
1269
1270 *x_out = CLAMP (event_x, 0, stage_width);
1271 *y_out = CLAMP (event_y, 0, stage_height);
1272 }
1273
1274 static void
on_keymap_state_change(MetaKeymapX11 * keymap_x11,gpointer data)1275 on_keymap_state_change (MetaKeymapX11 *keymap_x11,
1276 gpointer data)
1277 {
1278 ClutterSeat *seat = data;
1279 MetaInputSettings *input_settings;
1280 MetaKbdA11ySettings kbd_a11y_settings;
1281
1282 /* On keymaps state change, just reapply the current settings, it'll
1283 * take care of enabling/disabling mousekeys based on NumLock state.
1284 */
1285 input_settings = meta_backend_get_input_settings (meta_get_backend ());
1286 meta_input_settings_get_kbd_a11y_settings (input_settings, &kbd_a11y_settings);
1287 meta_seat_x11_apply_kbd_a11y_settings (seat, &kbd_a11y_settings);
1288 }
1289
1290 static void
meta_seat_x11_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1291 meta_seat_x11_set_property (GObject *object,
1292 guint prop_id,
1293 const GValue *value,
1294 GParamSpec *pspec)
1295 {
1296 MetaSeatX11 *seat_x11 = META_SEAT_X11 (object);
1297
1298 switch (prop_id)
1299 {
1300 case PROP_OPCODE:
1301 seat_x11->opcode = g_value_get_int (value);
1302 break;
1303 case PROP_POINTER_ID:
1304 seat_x11->pointer_id = g_value_get_int (value);
1305 break;
1306 case PROP_KEYBOARD_ID:
1307 seat_x11->keyboard_id = g_value_get_int (value);
1308 break;
1309 case PROP_TOUCH_MODE:
1310 default:
1311 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1312 }
1313 }
1314
1315 static void
meta_seat_x11_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1316 meta_seat_x11_get_property (GObject *object,
1317 guint prop_id,
1318 GValue *value,
1319 GParamSpec *pspec)
1320 {
1321 MetaSeatX11 *seat_x11 = META_SEAT_X11 (object);
1322
1323 switch (prop_id)
1324 {
1325 case PROP_OPCODE:
1326 g_value_set_int (value, seat_x11->opcode);
1327 break;
1328 case PROP_POINTER_ID:
1329 g_value_set_int (value, seat_x11->pointer_id);
1330 break;
1331 case PROP_KEYBOARD_ID:
1332 g_value_set_int (value, seat_x11->keyboard_id);
1333 break;
1334 case PROP_TOUCH_MODE:
1335 g_value_set_boolean (value, seat_x11->touch_mode);
1336 break;
1337 default:
1338 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1339 }
1340 }
1341
1342 void
meta_seat_x11_notify_devices(MetaSeatX11 * seat_x11,ClutterStage * stage)1343 meta_seat_x11_notify_devices (MetaSeatX11 *seat_x11,
1344 ClutterStage *stage)
1345 {
1346 GHashTableIter iter;
1347 ClutterInputDevice *device;
1348
1349 g_hash_table_iter_init (&iter, seat_x11->devices_by_id);
1350 while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &device))
1351 {
1352 ClutterEvent *event;
1353
1354 event = clutter_event_new (CLUTTER_DEVICE_ADDED);
1355 clutter_event_set_device (event, device);
1356 clutter_event_set_stage (event, stage);
1357 clutter_event_put (event);
1358 clutter_event_free (event);
1359 }
1360 }
1361
1362 static void
meta_seat_x11_constructed(GObject * object)1363 meta_seat_x11_constructed (GObject *object)
1364 {
1365 MetaSeatX11 *seat_x11 = META_SEAT_X11 (object);
1366 ClutterBackend *backend = clutter_get_default_backend ();
1367 XIDeviceInfo *info;
1368 XIEventMask event_mask;
1369 unsigned char mask[XIMaskLen(XI_LASTEVENT)] = { 0, };
1370 int n_devices, i;
1371 Display *xdisplay;
1372
1373 xdisplay = meta_clutter_x11_get_default_display ();
1374
1375 info = XIQueryDevice (xdisplay, XIAllDevices, &n_devices);
1376
1377 for (i = 0; i < n_devices; i++)
1378 {
1379 XIDeviceInfo *xi_device = &info[i];
1380
1381 if (!xi_device->enabled)
1382 continue;
1383
1384 add_device (seat_x11, backend, xi_device);
1385 }
1386
1387 XIFreeDeviceInfo (info);
1388
1389 XISetMask (mask, XI_HierarchyChanged);
1390 XISetMask (mask, XI_DeviceChanged);
1391 XISetMask (mask, XI_PropertyEvent);
1392
1393 event_mask.deviceid = XIAllDevices;
1394 event_mask.mask_len = sizeof (mask);
1395 event_mask.mask = mask;
1396
1397 XISelectEvents (xdisplay, meta_clutter_x11_get_root_window (),
1398 &event_mask, 1);
1399
1400 memset(mask, 0, sizeof (mask));
1401 XISetMask (mask, XI_RawMotion);
1402 XISetMask (mask, XI_RawButtonPress);
1403 XISetMask (mask, XI_RawButtonRelease);
1404
1405 event_mask.deviceid = XIAllMasterDevices;
1406 event_mask.mask_len = sizeof (mask);
1407 event_mask.mask = mask;
1408
1409 XISelectEvents (xdisplay, meta_clutter_x11_get_root_window (),
1410 &event_mask, 1);
1411
1412 XSync (xdisplay, False);
1413
1414 seat_x11->keymap = g_object_new (META_TYPE_KEYMAP_X11,
1415 "backend", backend,
1416 NULL);
1417 g_signal_connect (seat_x11->keymap,
1418 "state-changed",
1419 G_CALLBACK (on_keymap_state_change),
1420 seat_x11);
1421
1422 meta_seat_x11_a11y_init (CLUTTER_SEAT (seat_x11));
1423
1424 if (G_OBJECT_CLASS (meta_seat_x11_parent_class)->constructed)
1425 G_OBJECT_CLASS (meta_seat_x11_parent_class)->constructed (object);
1426 }
1427
1428 static void
meta_seat_x11_finalize(GObject * object)1429 meta_seat_x11_finalize (GObject *object)
1430 {
1431 MetaSeatX11 *seat_x11 = META_SEAT_X11 (object);
1432
1433 g_hash_table_unref (seat_x11->devices_by_id);
1434 g_hash_table_unref (seat_x11->tools_by_serial);
1435 g_hash_table_unref (seat_x11->touch_coords);
1436 g_list_free (seat_x11->devices);
1437
1438 G_OBJECT_CLASS (meta_seat_x11_parent_class)->finalize (object);
1439 }
1440
1441 static ClutterInputDevice *
meta_seat_x11_get_pointer(ClutterSeat * seat)1442 meta_seat_x11_get_pointer (ClutterSeat *seat)
1443 {
1444 MetaSeatX11 *seat_x11 = META_SEAT_X11 (seat);
1445
1446 return seat_x11->core_pointer;
1447 }
1448
1449 static ClutterInputDevice *
meta_seat_x11_get_keyboard(ClutterSeat * seat)1450 meta_seat_x11_get_keyboard (ClutterSeat *seat)
1451 {
1452 MetaSeatX11 *seat_x11 = META_SEAT_X11 (seat);
1453
1454 return seat_x11->core_keyboard;
1455 }
1456
1457 static const GList *
meta_seat_x11_peek_devices(ClutterSeat * seat)1458 meta_seat_x11_peek_devices (ClutterSeat *seat)
1459 {
1460 MetaSeatX11 *seat_x11 = META_SEAT_X11 (seat);
1461
1462 return (const GList *) seat_x11->devices;
1463 }
1464
1465 static void
meta_seat_x11_bell_notify(ClutterSeat * seat)1466 meta_seat_x11_bell_notify (ClutterSeat *seat)
1467 {
1468 MetaDisplay *display = meta_get_display ();
1469
1470 meta_bell_notify (display, NULL);
1471 }
1472
1473 static ClutterKeymap *
meta_seat_x11_get_keymap(ClutterSeat * seat)1474 meta_seat_x11_get_keymap (ClutterSeat *seat)
1475 {
1476 return CLUTTER_KEYMAP (META_SEAT_X11 (seat)->keymap);
1477 }
1478
1479 static ClutterVirtualInputDevice *
meta_seat_x11_create_virtual_device(ClutterSeat * seat,ClutterInputDeviceType device_type)1480 meta_seat_x11_create_virtual_device (ClutterSeat *seat,
1481 ClutterInputDeviceType device_type)
1482 {
1483 return g_object_new (META_TYPE_VIRTUAL_INPUT_DEVICE_X11,
1484 "seat", seat,
1485 "device-type", device_type,
1486 NULL);
1487 }
1488
1489 static ClutterVirtualDeviceType
meta_seat_x11_get_supported_virtual_device_types(ClutterSeat * seat)1490 meta_seat_x11_get_supported_virtual_device_types (ClutterSeat *seat)
1491 {
1492 return (CLUTTER_VIRTUAL_DEVICE_TYPE_KEYBOARD |
1493 CLUTTER_VIRTUAL_DEVICE_TYPE_POINTER);
1494 }
1495
1496 static void
meta_seat_x11_warp_pointer(ClutterSeat * seat,int x,int y)1497 meta_seat_x11_warp_pointer (ClutterSeat *seat,
1498 int x,
1499 int y)
1500 {
1501 MetaSeatX11 *seat_x11 = META_SEAT_X11 (seat);
1502
1503 meta_clutter_x11_trap_x_errors ();
1504 XIWarpPointer (meta_clutter_x11_get_default_display (),
1505 seat_x11->pointer_id,
1506 None,
1507 meta_clutter_x11_get_root_window (),
1508 0, 0, 0, 0,
1509 x, y);
1510 meta_clutter_x11_untrap_x_errors ();
1511 }
1512
1513 static uint32_t
translate_state(XIButtonState * button_state,XIModifierState * modifier_state,XIGroupState * group_state)1514 translate_state (XIButtonState *button_state,
1515 XIModifierState *modifier_state,
1516 XIGroupState *group_state)
1517 {
1518 uint32_t state = 0;
1519 int i;
1520
1521 if (modifier_state)
1522 state |= modifier_state->effective;
1523
1524 if (button_state)
1525 {
1526 for (i = 1; i < button_state->mask_len * 8; i++)
1527 {
1528 if (!XIMaskIsSet (button_state->mask, i))
1529 continue;
1530
1531 switch (i)
1532 {
1533 case 1:
1534 state |= CLUTTER_BUTTON1_MASK;
1535 break;
1536 case 2:
1537 state |= CLUTTER_BUTTON2_MASK;
1538 break;
1539 case 3:
1540 state |= CLUTTER_BUTTON3_MASK;
1541 break;
1542 case 8:
1543 state |= CLUTTER_BUTTON4_MASK;
1544 break;
1545 case 9:
1546 state |= CLUTTER_BUTTON5_MASK;
1547 break;
1548 default:
1549 break;
1550 }
1551 }
1552 }
1553
1554 if (group_state)
1555 state |= XkbBuildCoreState (0, group_state->effective);
1556
1557 return state;
1558 }
1559
1560 static gboolean
meta_seat_x11_query_state(ClutterSeat * seat,ClutterInputDevice * device,ClutterEventSequence * sequence,graphene_point_t * coords,ClutterModifierType * modifiers)1561 meta_seat_x11_query_state (ClutterSeat *seat,
1562 ClutterInputDevice *device,
1563 ClutterEventSequence *sequence,
1564 graphene_point_t *coords,
1565 ClutterModifierType *modifiers)
1566 {
1567 MetaBackendX11 *backend_x11 = META_BACKEND_X11 (meta_get_backend ());
1568 MetaSeatX11 *seat_x11 = META_SEAT_X11 (seat);
1569 Window root_ret, child_ret;
1570 double root_x, root_y, win_x, win_y;
1571 XIButtonState button_state = { 0 };
1572 XIModifierState modifier_state;
1573 XIGroupState group_state;
1574
1575 meta_clutter_x11_trap_x_errors ();
1576 XIQueryPointer (meta_clutter_x11_get_default_display (),
1577 seat_x11->pointer_id,
1578 meta_backend_x11_get_xwindow (backend_x11),
1579 &root_ret, &child_ret,
1580 &root_x, &root_y, &win_x, &win_y,
1581 &button_state, &modifier_state, &group_state);
1582 if (meta_clutter_x11_untrap_x_errors ())
1583 {
1584 g_free (button_state.mask);
1585 return FALSE;
1586 }
1587
1588 if (sequence)
1589 {
1590 MetaTouchInfo *touch_info;
1591
1592 touch_info = g_hash_table_lookup (seat_x11->touch_coords, sequence);
1593 if (!touch_info)
1594 {
1595 g_free (button_state.mask);
1596 return FALSE;
1597 }
1598
1599 if (coords)
1600 {
1601 coords->x = touch_info->x;
1602 coords->y = touch_info->y;
1603 }
1604 }
1605 else
1606 {
1607 if (coords)
1608 {
1609 coords->x = win_x;
1610 coords->y = win_y;
1611 }
1612 }
1613
1614 if (modifiers)
1615 *modifiers = translate_state (&button_state, &modifier_state, &group_state);
1616
1617 g_free (button_state.mask);
1618 return TRUE;
1619 }
1620
1621 static void
meta_seat_x11_update_touchpoint(MetaSeatX11 * seat,ClutterEventSequence * sequence,double x,double y)1622 meta_seat_x11_update_touchpoint (MetaSeatX11 *seat,
1623 ClutterEventSequence *sequence,
1624 double x,
1625 double y)
1626 {
1627 MetaTouchInfo *touch_info;
1628
1629 touch_info = g_hash_table_lookup (seat->touch_coords, sequence);
1630 if (!touch_info)
1631 {
1632 touch_info = g_new0 (MetaTouchInfo, 1);
1633 touch_info->sequence = sequence;
1634 g_hash_table_insert (seat->touch_coords, sequence, touch_info);
1635 }
1636
1637 touch_info->x = x;
1638 touch_info->y = y;
1639 }
1640
1641 static void
meta_seat_x11_remove_touchpoint(MetaSeatX11 * seat,ClutterEventSequence * sequence)1642 meta_seat_x11_remove_touchpoint (MetaSeatX11 *seat,
1643 ClutterEventSequence *sequence)
1644 {
1645 g_hash_table_remove (seat->touch_coords, sequence);
1646 }
1647
1648 static void
meta_touch_info_free(MetaTouchInfo * touch_info)1649 meta_touch_info_free (MetaTouchInfo *touch_info)
1650 {
1651 g_free (touch_info);
1652 }
1653
1654 static void
meta_seat_x11_class_init(MetaSeatX11Class * klass)1655 meta_seat_x11_class_init (MetaSeatX11Class *klass)
1656 {
1657 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1658 ClutterSeatClass *seat_class = CLUTTER_SEAT_CLASS (klass);
1659
1660 object_class->set_property = meta_seat_x11_set_property;
1661 object_class->get_property = meta_seat_x11_get_property;
1662 object_class->constructed = meta_seat_x11_constructed;
1663 object_class->finalize = meta_seat_x11_finalize;
1664
1665 seat_class->get_pointer = meta_seat_x11_get_pointer;
1666 seat_class->get_keyboard = meta_seat_x11_get_keyboard;
1667 seat_class->peek_devices = meta_seat_x11_peek_devices;
1668 seat_class->bell_notify = meta_seat_x11_bell_notify;
1669 seat_class->get_keymap = meta_seat_x11_get_keymap;
1670 seat_class->create_virtual_device = meta_seat_x11_create_virtual_device;
1671 seat_class->get_supported_virtual_device_types = meta_seat_x11_get_supported_virtual_device_types;
1672 seat_class->warp_pointer = meta_seat_x11_warp_pointer;
1673 seat_class->handle_event_post = meta_seat_x11_handle_event_post;
1674 seat_class->query_state = meta_seat_x11_query_state;
1675
1676 props[PROP_OPCODE] =
1677 g_param_spec_int ("opcode",
1678 "Opcode",
1679 "Opcode",
1680 0, G_MAXINT, 0,
1681 G_PARAM_READWRITE |
1682 G_PARAM_CONSTRUCT_ONLY);
1683 props[PROP_POINTER_ID] =
1684 g_param_spec_int ("pointer-id",
1685 "Pointer ID",
1686 "Pointer ID",
1687 2, G_MAXINT, 2,
1688 G_PARAM_READWRITE |
1689 G_PARAM_CONSTRUCT_ONLY);
1690 props[PROP_KEYBOARD_ID] =
1691 g_param_spec_int ("keyboard-id",
1692 "Keyboard ID",
1693 "Keyboard ID",
1694 2, G_MAXINT, 2,
1695 G_PARAM_READWRITE |
1696 G_PARAM_CONSTRUCT_ONLY);
1697
1698 g_object_class_install_properties (object_class, N_PROPS, props);
1699
1700 g_object_class_override_property (object_class, PROP_TOUCH_MODE,
1701 "touch-mode");
1702 }
1703
1704 static void
meta_seat_x11_init(MetaSeatX11 * seat)1705 meta_seat_x11_init (MetaSeatX11 *seat)
1706 {
1707 seat->devices_by_id = g_hash_table_new_full (NULL, NULL,
1708 NULL,
1709 (GDestroyNotify) g_object_unref);
1710 seat->tools_by_serial = g_hash_table_new_full (NULL, NULL, NULL,
1711 (GDestroyNotify) g_object_unref);
1712 seat->touch_coords = g_hash_table_new_full (NULL, NULL, NULL,
1713 (GDestroyNotify) meta_touch_info_free);
1714 }
1715
1716 MetaSeatX11 *
meta_seat_x11_new(int opcode,int logical_pointer,int logical_keyboard)1717 meta_seat_x11_new (int opcode,
1718 int logical_pointer,
1719 int logical_keyboard)
1720 {
1721 return g_object_new (META_TYPE_SEAT_X11,
1722 "opcode", opcode,
1723 "pointer-id", logical_pointer,
1724 "keyboard-id", logical_keyboard,
1725 NULL);
1726 }
1727
1728 static ClutterInputDevice *
get_source_device_checked(MetaSeatX11 * seat,XIDeviceEvent * xev)1729 get_source_device_checked (MetaSeatX11 *seat,
1730 XIDeviceEvent *xev)
1731 {
1732 ClutterInputDevice *source_device;
1733
1734 source_device = g_hash_table_lookup (seat->devices_by_id,
1735 GINT_TO_POINTER (xev->sourceid));
1736
1737 if (!source_device)
1738 g_warning ("Impossible to get the source device with id %d for event of "
1739 "type %d", xev->sourceid, xev->evtype);
1740
1741 return source_device;
1742 }
1743 #ifdef __linux__
1744 static uint32_t
evdev_button_code(uint32_t x_button)1745 evdev_button_code (uint32_t x_button)
1746 {
1747 uint32_t button;
1748
1749 switch (x_button)
1750 {
1751 case 1:
1752 button = BTN_LEFT;
1753 break;
1754
1755 /* The evdev input right and middle button numbers are swapped
1756 relative to how Clutter numbers them */
1757 case 2:
1758 button = BTN_MIDDLE;
1759 break;
1760
1761 case 3:
1762 button = BTN_RIGHT;
1763 break;
1764
1765 default:
1766 button = x_button + (BTN_LEFT - 1) + 4;
1767 break;
1768 }
1769
1770 return button;
1771 }
1772 #endif
1773 gboolean
meta_seat_x11_translate_event(MetaSeatX11 * seat,XEvent * xevent,ClutterEvent * event)1774 meta_seat_x11_translate_event (MetaSeatX11 *seat,
1775 XEvent *xevent,
1776 ClutterEvent *event)
1777 {
1778 gboolean retval = FALSE;
1779 ClutterBackend *backend = clutter_get_default_backend ();
1780 ClutterStage *stage = NULL;
1781 MetaStageX11 *stage_x11 = NULL;
1782 ClutterInputDevice *device, *source_device;
1783 XGenericEventCookie *cookie;
1784 XIEvent *xi_event;
1785
1786 if (meta_keymap_x11_handle_event (seat->keymap, xevent))
1787 return FALSE;
1788
1789 cookie = &xevent->xcookie;
1790
1791 if (cookie->type != GenericEvent ||
1792 cookie->extension != seat->opcode)
1793 return FALSE;
1794
1795 xi_event = (XIEvent *) cookie->data;
1796
1797 if (!xi_event)
1798 return FALSE;
1799
1800 if (cookie->evtype == XI_RawMotion ||
1801 cookie->evtype == XI_RawButtonPress ||
1802 cookie->evtype == XI_RawButtonRelease)
1803 {
1804 translate_raw_event (seat, xevent);
1805 return FALSE;
1806 }
1807
1808 if (!(xi_event->evtype == XI_DeviceChanged ||
1809 xi_event->evtype == XI_PropertyEvent))
1810 {
1811 stage = get_event_stage (seat, xi_event);
1812 if (stage == NULL || CLUTTER_ACTOR_IN_DESTRUCTION (stage))
1813 return FALSE;
1814 else
1815 stage_x11 = META_STAGE_X11 (_clutter_stage_get_window (stage));
1816 }
1817
1818 event->any.stage = stage;
1819
1820 switch (xi_event->evtype)
1821 {
1822 case XI_HierarchyChanged:
1823 {
1824 XIHierarchyEvent *xev = (XIHierarchyEvent *) xi_event;
1825
1826 retval = translate_hierarchy_event (backend, seat, xev, event);
1827 }
1828 break;
1829
1830 case XI_DeviceChanged:
1831 {
1832 XIDeviceChangedEvent *xev = (XIDeviceChangedEvent *) xi_event;
1833
1834 device = g_hash_table_lookup (seat->devices_by_id,
1835 GINT_TO_POINTER (xev->deviceid));
1836 source_device = g_hash_table_lookup (seat->devices_by_id,
1837 GINT_TO_POINTER (xev->sourceid));
1838 if (device)
1839 {
1840 meta_input_device_x11_reset_axes (device);
1841 translate_device_classes (meta_clutter_x11_get_default_display (),
1842 device,
1843 xev->classes,
1844 xev->num_classes);
1845 }
1846
1847 if (source_device)
1848 meta_input_device_x11_reset_scroll_info (source_device);
1849 }
1850 retval = FALSE;
1851 break;
1852 case XI_KeyPress:
1853 case XI_KeyRelease:
1854 {
1855 XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
1856 MetaKeymapX11 *keymap_x11 = seat->keymap;
1857 char buffer[7] = { 0, };
1858 gunichar n;
1859
1860 source_device = get_source_device_checked (seat, xev);
1861 if (!source_device)
1862 return FALSE;
1863
1864 event->key.type = event->type = (xev->evtype == XI_KeyPress)
1865 ? CLUTTER_KEY_PRESS
1866 : CLUTTER_KEY_RELEASE;
1867
1868 if (xev->evtype == XI_KeyPress && xev->flags & XIKeyRepeat)
1869 clutter_event_set_flags (event, CLUTTER_EVENT_FLAG_REPEATED);
1870
1871 event->key.time = xev->time;
1872 event->key.stage = stage;
1873 meta_input_device_x11_translate_state (event, &xev->mods, &xev->buttons, &xev->group);
1874 event->key.hardware_keycode = xev->detail;
1875
1876 /* clutter-xkb-utils.c adds a fixed offset of 8 to go into XKB's
1877 * range, so we do the reverse here. */
1878 event->key.evdev_code = event->key.hardware_keycode - 8;
1879
1880 /* keyval is the key ignoring all modifiers ('1' vs. '!') */
1881 event->key.keyval =
1882 meta_keymap_x11_translate_key_state (keymap_x11,
1883 event->key.hardware_keycode,
1884 &event->key.modifier_state,
1885 NULL);
1886
1887 clutter_event_set_source_device (event, source_device);
1888
1889 device = g_hash_table_lookup (seat->devices_by_id,
1890 GINT_TO_POINTER (xev->deviceid));
1891 clutter_event_set_device (event, device);
1892
1893 /* XXX keep this in sync with the evdev device manager */
1894 n = print_keysym (event->key.keyval, buffer, sizeof (buffer));
1895 if (n == 0)
1896 {
1897 /* not printable */
1898 event->key.unicode_value = (gunichar) '\0';
1899 }
1900 else
1901 {
1902 event->key.unicode_value = g_utf8_get_char_validated (buffer, n);
1903 if (event->key.unicode_value == -1 ||
1904 event->key.unicode_value == -2)
1905 event->key.unicode_value = (gunichar) '\0';
1906 }
1907
1908 g_debug ("%s: win:0x%x device:%d source:%d, key: %12s (%d)",
1909 event->any.type == CLUTTER_KEY_PRESS
1910 ? "key press "
1911 : "key release",
1912 (unsigned int) stage_x11->xwin,
1913 xev->deviceid,
1914 xev->sourceid,
1915 event->key.keyval ? buffer : "(none)",
1916 event->key.keyval);
1917
1918 if (xi_event->evtype == XI_KeyPress)
1919 meta_stage_x11_set_user_time (stage_x11, event->key.time);
1920
1921 retval = TRUE;
1922 }
1923 break;
1924
1925 case XI_ButtonPress:
1926 case XI_ButtonRelease:
1927 {
1928 XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
1929
1930 source_device = get_source_device_checked (seat, xev);
1931 if (!source_device)
1932 return FALSE;
1933
1934 device = g_hash_table_lookup (seat->devices_by_id,
1935 GINT_TO_POINTER (xev->deviceid));
1936
1937 if (clutter_input_device_get_device_type (source_device) == CLUTTER_PAD_DEVICE)
1938 {
1939 /* We got these events because of the passive button grab */
1940 XIAllowEvents (meta_clutter_x11_get_default_display (),
1941 xev->sourceid,
1942 XIAsyncDevice,
1943 xev->time);
1944
1945 event->any.stage = stage;
1946
1947 if (xev->detail >= 4 && xev->detail <= 7)
1948 {
1949 retval = FALSE;
1950
1951 if (xi_event->evtype == XI_ButtonPress &&
1952 translate_pad_event (event, xev, source_device))
1953 retval = TRUE;
1954
1955 break;
1956 }
1957
1958 event->any.type =
1959 (xi_event->evtype == XI_ButtonPress) ? CLUTTER_PAD_BUTTON_PRESS
1960 : CLUTTER_PAD_BUTTON_RELEASE;
1961 event->any.time = xev->time;
1962
1963 /* The 4-7 button range is taken as non-existent on pad devices,
1964 * let the buttons above that take over this range.
1965 */
1966 if (xev->detail > 7)
1967 xev->detail -= 4;
1968
1969 /* Pad buttons are 0-indexed */
1970 event->pad_button.button = xev->detail - 1;
1971 #ifdef HAVE_LIBWACOM
1972 meta_input_device_x11_update_pad_state (device,
1973 event->pad_button.button,
1974 (xi_event->evtype == XI_ButtonPress),
1975 &event->pad_button.group,
1976 &event->pad_button.mode);
1977 #endif
1978 clutter_event_set_device (event, device);
1979 clutter_event_set_source_device (event, source_device);
1980
1981 g_debug ("%s: win:0x%x, device:%d '%s', time:%d "
1982 "(button:%d)",
1983 event->any.type == CLUTTER_BUTTON_PRESS
1984 ? "pad button press "
1985 : "pad button release",
1986 (unsigned int) stage_x11->xwin,
1987 meta_input_device_x11_get_device_id (device),
1988 clutter_input_device_get_device_name (device),
1989 event->any.time,
1990 event->pad_button.button);
1991 retval = TRUE;
1992 break;
1993 }
1994
1995 switch (xev->detail)
1996 {
1997 case 4:
1998 case 5:
1999 case 6:
2000 case 7:
2001 /* we only generate Scroll events on ButtonPress */
2002 if (xi_event->evtype == XI_ButtonRelease)
2003 return FALSE;
2004
2005 event->scroll.type = event->type = CLUTTER_SCROLL;
2006
2007 if (xev->detail == 4)
2008 event->scroll.direction = CLUTTER_SCROLL_UP;
2009 else if (xev->detail == 5)
2010 event->scroll.direction = CLUTTER_SCROLL_DOWN;
2011 else if (xev->detail == 6)
2012 event->scroll.direction = CLUTTER_SCROLL_LEFT;
2013 else
2014 event->scroll.direction = CLUTTER_SCROLL_RIGHT;
2015
2016 event->scroll.stage = stage;
2017
2018 event->scroll.time = xev->time;
2019 translate_coords (stage_x11, xev->event_x, xev->event_y, &event->scroll.x, &event->scroll.y);
2020 meta_input_device_x11_translate_state (event,
2021 &xev->mods,
2022 &xev->buttons,
2023 &xev->group);
2024
2025 clutter_event_set_source_device (event, source_device);
2026 clutter_event_set_device (event, device);
2027
2028 event->scroll.axes = translate_axes (event->scroll.device,
2029 event->scroll.x,
2030 event->scroll.y,
2031 &xev->valuators);
2032 g_debug ("scroll: win:0x%x, device:%d '%s', time:%d "
2033 "(direction:%s, "
2034 "x:%.2f, y:%.2f, "
2035 "emulated:%s)",
2036 (unsigned int) stage_x11->xwin,
2037 meta_input_device_x11_get_device_id (device),
2038 clutter_input_device_get_device_name (device),
2039 event->any.time,
2040 event->scroll.direction == CLUTTER_SCROLL_UP ? "up" :
2041 event->scroll.direction == CLUTTER_SCROLL_DOWN ? "down" :
2042 event->scroll.direction == CLUTTER_SCROLL_LEFT ? "left" :
2043 event->scroll.direction == CLUTTER_SCROLL_RIGHT ? "right" :
2044 "invalid",
2045 event->scroll.x,
2046 event->scroll.y,
2047 (xev->flags & XIPointerEmulated) ? "yes" : "no");
2048 break;
2049
2050 default:
2051 event->button.type = event->type =
2052 (xi_event->evtype == XI_ButtonPress) ? CLUTTER_BUTTON_PRESS
2053 : CLUTTER_BUTTON_RELEASE;
2054
2055 event->button.stage = stage;
2056
2057 event->button.time = xev->time;
2058 translate_coords (stage_x11, xev->event_x, xev->event_y, &event->button.x, &event->button.y);
2059 event->button.button = xev->detail;
2060 #ifdef __linux__
2061 event->button.evdev_code = evdev_button_code (xev->detail);
2062 #endif
2063 meta_input_device_x11_translate_state (event,
2064 &xev->mods,
2065 &xev->buttons,
2066 &xev->group);
2067
2068 clutter_event_set_source_device (event, source_device);
2069 clutter_event_set_device (event, device);
2070 clutter_event_set_device_tool (event,
2071 meta_input_device_x11_get_current_tool (source_device));
2072
2073 event->button.axes = translate_axes (event->button.device,
2074 event->button.x,
2075 event->button.y,
2076 &xev->valuators);
2077 g_debug ("%s: win:0x%x, device:%d '%s', time:%d "
2078 "(button:%d, "
2079 "x:%.2f, y:%.2f, "
2080 "axes:%s, "
2081 "emulated:%s)",
2082 event->any.type == CLUTTER_BUTTON_PRESS
2083 ? "button press "
2084 : "button release",
2085 (unsigned int) stage_x11->xwin,
2086 meta_input_device_x11_get_device_id (device),
2087 clutter_input_device_get_device_name (device),
2088 event->any.time,
2089 event->button.button,
2090 event->button.x,
2091 event->button.y,
2092 event->button.axes != NULL ? "yes" : "no",
2093 (xev->flags & XIPointerEmulated) ? "yes" : "no");
2094 break;
2095 }
2096
2097 if (xev->flags & XIPointerEmulated)
2098 _clutter_event_set_pointer_emulated (event, TRUE);
2099
2100 if (xi_event->evtype == XI_ButtonPress)
2101 meta_stage_x11_set_user_time (stage_x11, event->button.time);
2102
2103 retval = TRUE;
2104 }
2105 break;
2106
2107 case XI_Motion:
2108 {
2109 XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
2110 double delta_x, delta_y;
2111
2112 source_device = get_source_device_checked (seat, xev);
2113 if (!source_device)
2114 return FALSE;
2115
2116 device = g_hash_table_lookup (seat->devices_by_id,
2117 GINT_TO_POINTER (xev->deviceid));
2118
2119 if (clutter_input_device_get_device_type (source_device) == CLUTTER_PAD_DEVICE)
2120 {
2121 event->any.stage = stage;
2122
2123 if (translate_pad_event (event, xev, source_device))
2124 retval = TRUE;
2125 break;
2126 }
2127
2128 if (scroll_valuators_changed (source_device,
2129 &xev->valuators,
2130 &delta_x, &delta_y))
2131 {
2132 event->scroll.type = event->type = CLUTTER_SCROLL;
2133 event->scroll.direction = CLUTTER_SCROLL_SMOOTH;
2134
2135 event->scroll.stage = stage;
2136 event->scroll.time = xev->time;
2137 translate_coords (stage_x11, xev->event_x, xev->event_y, &event->scroll.x, &event->scroll.y);
2138 meta_input_device_x11_translate_state (event,
2139 &xev->mods,
2140 &xev->buttons,
2141 &xev->group);
2142
2143 clutter_event_set_scroll_delta (event, delta_x, delta_y);
2144 clutter_event_set_source_device (event, source_device);
2145 clutter_event_set_device (event, device);
2146
2147 g_debug ("smooth scroll: win:0x%x device:%d '%s' (x:%.2f, y:%.2f, delta:%f, %f)",
2148 (unsigned int) stage_x11->xwin,
2149 meta_input_device_x11_get_device_id (event->scroll.device),
2150 clutter_input_device_get_device_name (event->scroll.device),
2151 event->scroll.x,
2152 event->scroll.y,
2153 delta_x, delta_y);
2154
2155 retval = TRUE;
2156 break;
2157 }
2158
2159 event->motion.type = event->type = CLUTTER_MOTION;
2160
2161 event->motion.stage = stage;
2162
2163 event->motion.time = xev->time;
2164 translate_coords (stage_x11, xev->event_x, xev->event_y, &event->motion.x, &event->motion.y);
2165 meta_input_device_x11_translate_state (event,
2166 &xev->mods,
2167 &xev->buttons,
2168 &xev->group);
2169
2170 clutter_event_set_source_device (event, source_device);
2171 clutter_event_set_device (event, device);
2172 clutter_event_set_device_tool (event,
2173 meta_input_device_x11_get_current_tool (source_device));
2174
2175 event->motion.axes = translate_axes (event->motion.device,
2176 event->motion.x,
2177 event->motion.y,
2178 &xev->valuators);
2179
2180 if (xev->flags & XIPointerEmulated)
2181 _clutter_event_set_pointer_emulated (event, TRUE);
2182
2183 g_debug ("motion: win:0x%x device:%d '%s' (x:%.2f, y:%.2f, axes:%s)",
2184 (unsigned int) stage_x11->xwin,
2185 meta_input_device_x11_get_device_id (event->motion.device),
2186 clutter_input_device_get_device_name (event->motion.device),
2187 event->motion.x,
2188 event->motion.y,
2189 event->motion.axes != NULL ? "yes" : "no");
2190
2191 retval = TRUE;
2192 }
2193 break;
2194
2195 case XI_TouchBegin:
2196 {
2197 XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
2198 device = g_hash_table_lookup (seat->devices_by_id,
2199 GINT_TO_POINTER (xev->deviceid));
2200 }
2201 /* Fall through */
2202 case XI_TouchEnd:
2203 {
2204 XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
2205
2206 source_device = g_hash_table_lookup (seat->devices_by_id,
2207 GINT_TO_POINTER (xev->sourceid));
2208
2209 if (xi_event->evtype == XI_TouchBegin)
2210 event->touch.type = event->type = CLUTTER_TOUCH_BEGIN;
2211 else
2212 event->touch.type = event->type = CLUTTER_TOUCH_END;
2213
2214 event->touch.stage = stage;
2215 event->touch.time = xev->time;
2216 translate_coords (stage_x11, xev->event_x, xev->event_y, &event->touch.x, &event->touch.y);
2217 meta_input_device_x11_translate_state (event,
2218 &xev->mods,
2219 &xev->buttons,
2220 &xev->group);
2221
2222 clutter_event_set_source_device (event, source_device);
2223
2224 device = g_hash_table_lookup (seat->devices_by_id,
2225 GINT_TO_POINTER (xev->deviceid));
2226 clutter_event_set_device (event, device);
2227
2228 event->touch.axes = translate_axes (event->touch.device,
2229 event->motion.x,
2230 event->motion.y,
2231 &xev->valuators);
2232
2233 if (xi_event->evtype == XI_TouchBegin)
2234 {
2235 event->touch.modifier_state |= CLUTTER_BUTTON1_MASK;
2236
2237 meta_stage_x11_set_user_time (stage_x11, event->touch.time);
2238 meta_seat_x11_update_touchpoint (seat,
2239 GUINT_TO_POINTER (xev->detail),
2240 xev->root_x,
2241 xev->root_y);
2242 }
2243 else if (xi_event->evtype == XI_TouchEnd)
2244 {
2245 meta_seat_x11_remove_touchpoint (seat,
2246 GUINT_TO_POINTER (xev->detail));
2247 }
2248
2249 /* "NULL" sequences are special cased in clutter */
2250 event->touch.sequence = GINT_TO_POINTER (MAX (1, xev->detail + 1));
2251
2252 if (xev->flags & XITouchEmulatingPointer)
2253 _clutter_event_set_pointer_emulated (event, TRUE);
2254
2255 g_debug ("touch %s: win:0x%x device:%d '%s' (seq:%d, x:%.2f, y:%.2f, axes:%s)",
2256 event->type == CLUTTER_TOUCH_BEGIN ? "begin" : "end",
2257 (unsigned int) stage_x11->xwin,
2258 meta_input_device_x11_get_device_id (event->touch.device),
2259 clutter_input_device_get_device_name (event->touch.device),
2260 GPOINTER_TO_UINT (event->touch.sequence),
2261 event->touch.x,
2262 event->touch.y,
2263 event->touch.axes != NULL ? "yes" : "no");
2264
2265 retval = TRUE;
2266 }
2267 break;
2268
2269 case XI_TouchUpdate:
2270 {
2271 XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
2272
2273 source_device = g_hash_table_lookup (seat->devices_by_id,
2274 GINT_TO_POINTER (xev->sourceid));
2275
2276 event->touch.type = event->type = CLUTTER_TOUCH_UPDATE;
2277 event->touch.stage = stage;
2278 event->touch.time = xev->time;
2279 /* "NULL" sequences are special cased in clutter */
2280 event->touch.sequence = GINT_TO_POINTER (MAX (1, xev->detail + 1));
2281 translate_coords (stage_x11, xev->event_x, xev->event_y, &event->touch.x, &event->touch.y);
2282
2283 clutter_event_set_source_device (event, source_device);
2284
2285 device = g_hash_table_lookup (seat->devices_by_id,
2286 GINT_TO_POINTER (xev->deviceid));
2287 clutter_event_set_device (event, device);
2288
2289 event->touch.axes = translate_axes (event->touch.device,
2290 event->motion.x,
2291 event->motion.y,
2292 &xev->valuators);
2293
2294 meta_input_device_x11_translate_state (event,
2295 &xev->mods,
2296 &xev->buttons,
2297 &xev->group);
2298 event->touch.modifier_state |= CLUTTER_BUTTON1_MASK;
2299
2300 if (xev->flags & XITouchEmulatingPointer)
2301 _clutter_event_set_pointer_emulated (event, TRUE);
2302
2303 meta_seat_x11_update_touchpoint (seat,
2304 event->touch.sequence,
2305 xev->root_x,
2306 xev->root_y);
2307
2308 g_debug ("touch update: win:0x%x device:%d '%s' (seq:%d, x:%.2f, y:%.2f, axes:%s)",
2309 (unsigned int) stage_x11->xwin,
2310 meta_input_device_x11_get_device_id (event->touch.device),
2311 clutter_input_device_get_device_name (event->touch.device),
2312 GPOINTER_TO_UINT (event->touch.sequence),
2313 event->touch.x,
2314 event->touch.y,
2315 event->touch.axes != NULL ? "yes" : "no");
2316
2317 retval = TRUE;
2318 }
2319 break;
2320
2321 case XI_Enter:
2322 case XI_Leave:
2323 {
2324 XIEnterEvent *xev = (XIEnterEvent *) xi_event;
2325
2326 device = g_hash_table_lookup (seat->devices_by_id,
2327 GINT_TO_POINTER (xev->deviceid));
2328
2329 source_device = g_hash_table_lookup (seat->devices_by_id,
2330 GINT_TO_POINTER (xev->sourceid));
2331
2332 if (xi_event->evtype == XI_Enter)
2333 {
2334 event->crossing.type = event->type = CLUTTER_ENTER;
2335
2336 event->crossing.stage = stage;
2337 event->crossing.source = CLUTTER_ACTOR (stage);
2338 event->crossing.related = NULL;
2339
2340 event->crossing.time = xev->time;
2341 translate_coords (stage_x11, xev->event_x, xev->event_y, &event->crossing.x, &event->crossing.y);
2342
2343 if (xev->deviceid == seat->pointer_id)
2344 seat->has_pointer_focus = TRUE;
2345 }
2346 else
2347 {
2348 event->crossing.type = event->type = CLUTTER_LEAVE;
2349
2350 event->crossing.stage = stage;
2351 event->crossing.source = CLUTTER_ACTOR (stage);
2352 event->crossing.related = NULL;
2353
2354 event->crossing.time = xev->time;
2355 translate_coords (stage_x11, xev->event_x, xev->event_y, &event->crossing.x, &event->crossing.y);
2356
2357 if (xev->deviceid == seat->pointer_id)
2358 seat->has_pointer_focus = FALSE;
2359 }
2360
2361 meta_input_device_x11_reset_scroll_info (source_device);
2362
2363 clutter_event_set_device (event, device);
2364 clutter_event_set_source_device (event, source_device);
2365
2366 retval = TRUE;
2367 }
2368 break;
2369
2370 case XI_FocusIn:
2371 case XI_FocusOut:
2372 retval = FALSE;
2373 break;
2374 case XI_PropertyEvent:
2375 translate_property_event (seat, xi_event);
2376 retval = FALSE;
2377 break;
2378 }
2379
2380 return retval;
2381 }
2382
2383 ClutterInputDevice *
meta_seat_x11_lookup_device_id(MetaSeatX11 * seat_x11,int device_id)2384 meta_seat_x11_lookup_device_id (MetaSeatX11 *seat_x11,
2385 int device_id)
2386 {
2387 return g_hash_table_lookup (seat_x11->devices_by_id,
2388 GINT_TO_POINTER (device_id));
2389 }
2390
2391 void
meta_seat_x11_select_stage_events(MetaSeatX11 * seat,ClutterStage * stage)2392 meta_seat_x11_select_stage_events (MetaSeatX11 *seat,
2393 ClutterStage *stage)
2394 {
2395 MetaStageX11 *stage_x11;
2396 XIEventMask xi_event_mask;
2397 unsigned char *mask;
2398 int len;
2399
2400 stage_x11 = META_STAGE_X11 (_clutter_stage_get_window (stage));
2401
2402 len = XIMaskLen (XI_LASTEVENT);
2403 mask = g_new0 (unsigned char, len);
2404
2405 XISetMask (mask, XI_Motion);
2406 XISetMask (mask, XI_ButtonPress);
2407 XISetMask (mask, XI_ButtonRelease);
2408 XISetMask (mask, XI_KeyPress);
2409 XISetMask (mask, XI_KeyRelease);
2410 XISetMask (mask, XI_Enter);
2411 XISetMask (mask, XI_Leave);
2412
2413 XISetMask (mask, XI_TouchBegin);
2414 XISetMask (mask, XI_TouchUpdate);
2415 XISetMask (mask, XI_TouchEnd);
2416
2417 xi_event_mask.deviceid = XIAllMasterDevices;
2418 xi_event_mask.mask = mask;
2419 xi_event_mask.mask_len = len;
2420
2421 XISelectEvents (meta_clutter_x11_get_default_display (),
2422 stage_x11->xwin, &xi_event_mask, 1);
2423
2424 g_free (mask);
2425 }
2426