1 | /* GDK - The GIMP Drawing Kit |
2 | * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org> |
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 | |
18 | #include "config.h" |
19 | |
20 | #include "gdkx11devicemanager-xi2.h" |
21 | |
22 | #include "gdkdevice-xi2-private.h" |
23 | #include "gdkdeviceprivate.h" |
24 | #include "gdkdevicetoolprivate.h" |
25 | #include "gdkdisplayprivate.h" |
26 | #include "gdkeventsprivate.h" |
27 | #include "gdkeventtranslator.h" |
28 | #include "gdkkeys-x11.h" |
29 | #include "gdkprivate-x11.h" |
30 | #include "gdkdisplay-x11.h" |
31 | #include "gdkintl.h" |
32 | #include "gdkkeysyms.h" |
33 | #include "gdkseatdefaultprivate.h" |
34 | |
35 | #include <X11/Xlib.h> |
36 | #include <X11/Xutil.h> |
37 | #include <X11/extensions/XInput2.h> |
38 | #include <X11/Xatom.h> |
39 | |
40 | #include <string.h> |
41 | |
42 | #ifdef G_ENABLE_DEBUG |
43 | static const char notify_modes[][19] = { |
44 | "NotifyNormal" , |
45 | "NotifyGrab" , |
46 | "NotifyUngrab" , |
47 | "NotifyWhileGrabbed" |
48 | }; |
49 | |
50 | static const char notify_details[][23] = { |
51 | "NotifyAncestor" , |
52 | "NotifyVirtual" , |
53 | "NotifyInferior" , |
54 | "NotifyNonlinear" , |
55 | "NotifyNonlinearVirtual" , |
56 | "NotifyPointer" , |
57 | "NotifyPointerRoot" , |
58 | "NotifyDetailNone" |
59 | }; |
60 | #endif |
61 | |
62 | #define HAS_FOCUS(toplevel) \ |
63 | ((toplevel)->has_focus || (toplevel)->has_pointer_focus) |
64 | |
65 | static const char *wacom_type_atoms[] = { |
66 | "STYLUS" , |
67 | "CURSOR" , |
68 | "ERASER" , |
69 | "PAD" , |
70 | "TOUCH" |
71 | }; |
72 | #define N_WACOM_TYPE_ATOMS G_N_ELEMENTS (wacom_type_atoms) |
73 | |
74 | enum { |
75 | WACOM_TYPE_STYLUS, |
76 | WACOM_TYPE_CURSOR, |
77 | WACOM_TYPE_ERASER, |
78 | WACOM_TYPE_PAD, |
79 | WACOM_TYPE_TOUCH, |
80 | }; |
81 | |
82 | struct _GdkX11DeviceManagerXI2 |
83 | { |
84 | GObject parent_object; |
85 | |
86 | GdkDisplay *display; |
87 | GHashTable *id_table; |
88 | |
89 | GList *devices; |
90 | |
91 | int opcode; |
92 | int major; |
93 | int minor; |
94 | }; |
95 | |
96 | struct _GdkX11DeviceManagerXI2Class |
97 | { |
98 | GObjectClass parent_class; |
99 | }; |
100 | |
101 | static void gdk_x11_device_manager_xi2_event_translator_init (GdkEventTranslatorIface *iface); |
102 | |
103 | G_DEFINE_TYPE_WITH_CODE (GdkX11DeviceManagerXI2, gdk_x11_device_manager_xi2, G_TYPE_OBJECT, |
104 | G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR, |
105 | gdk_x11_device_manager_xi2_event_translator_init)) |
106 | |
107 | static void gdk_x11_device_manager_xi2_constructed (GObject *object); |
108 | static void gdk_x11_device_manager_xi2_dispose (GObject *object); |
109 | static void gdk_x11_device_manager_xi2_set_property (GObject *object, |
110 | guint prop_id, |
111 | const GValue *value, |
112 | GParamSpec *pspec); |
113 | static void gdk_x11_device_manager_xi2_get_property (GObject *object, |
114 | guint prop_id, |
115 | GValue *value, |
116 | GParamSpec *pspec); |
117 | |
118 | static GdkEvent * gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator, |
119 | GdkDisplay *display, |
120 | const XEvent *xevent); |
121 | static GdkEventMask gdk_x11_device_manager_xi2_get_handled_events (GdkEventTranslator *translator); |
122 | static void gdk_x11_device_manager_xi2_select_surface_events (GdkEventTranslator *translator, |
123 | Window window, |
124 | GdkEventMask event_mask); |
125 | static GdkSurface * gdk_x11_device_manager_xi2_get_surface (GdkEventTranslator *translator, |
126 | const XEvent *xevent); |
127 | |
128 | enum { |
129 | PROP_0, |
130 | PROP_DISPLAY, |
131 | PROP_OPCODE, |
132 | PROP_MAJOR, |
133 | PROP_MINOR |
134 | }; |
135 | |
136 | static void |
137 | gdk_x11_device_manager_xi2_class_init (GdkX11DeviceManagerXI2Class *klass) |
138 | { |
139 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
140 | |
141 | object_class->constructed = gdk_x11_device_manager_xi2_constructed; |
142 | object_class->dispose = gdk_x11_device_manager_xi2_dispose; |
143 | object_class->set_property = gdk_x11_device_manager_xi2_set_property; |
144 | object_class->get_property = gdk_x11_device_manager_xi2_get_property; |
145 | |
146 | g_object_class_install_property (oclass: object_class, |
147 | property_id: PROP_DISPLAY, |
148 | pspec: g_param_spec_object (name: "display" , |
149 | nick: "Display" , |
150 | blurb: "Display for the device manager" , |
151 | GDK_TYPE_DISPLAY, |
152 | flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | |
153 | G_PARAM_STATIC_STRINGS)); |
154 | g_object_class_install_property (oclass: object_class, |
155 | property_id: PROP_OPCODE, |
156 | pspec: g_param_spec_int (name: "opcode" , |
157 | P_("Opcode" ), |
158 | P_("Opcode for XInput2 requests" ), |
159 | minimum: 0, G_MAXINT, default_value: 0, |
160 | flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | |
161 | G_PARAM_STATIC_STRINGS)); |
162 | g_object_class_install_property (oclass: object_class, |
163 | property_id: PROP_MAJOR, |
164 | pspec: g_param_spec_int (name: "major" , |
165 | P_("Major" ), |
166 | P_("Major version number" ), |
167 | minimum: 0, G_MAXINT, default_value: 0, |
168 | flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | |
169 | G_PARAM_STATIC_STRINGS)); |
170 | g_object_class_install_property (oclass: object_class, |
171 | property_id: PROP_MINOR, |
172 | pspec: g_param_spec_int (name: "minor" , |
173 | P_("Minor" ), |
174 | P_("Minor version number" ), |
175 | minimum: 0, G_MAXINT, default_value: 0, |
176 | flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | |
177 | G_PARAM_STATIC_STRINGS)); |
178 | } |
179 | |
180 | static void |
181 | gdk_x11_device_manager_xi2_init (GdkX11DeviceManagerXI2 *device_manager) |
182 | { |
183 | device_manager->id_table = g_hash_table_new_full (hash_func: g_direct_hash, |
184 | key_equal_func: g_direct_equal, |
185 | NULL, |
186 | value_destroy_func: (GDestroyNotify) g_object_unref); |
187 | } |
188 | |
189 | static void |
190 | _gdk_x11_device_manager_xi2_select_events (GdkX11DeviceManagerXI2 *device_manager, |
191 | Window xwindow, |
192 | XIEventMask *event_mask) |
193 | { |
194 | GdkDisplay *display; |
195 | Display *xdisplay; |
196 | |
197 | display = device_manager->display; |
198 | xdisplay = GDK_DISPLAY_XDISPLAY (display); |
199 | |
200 | XISelectEvents (dpy: xdisplay, win: xwindow, masks: event_mask, num_masks: 1); |
201 | } |
202 | |
203 | static void |
204 | translate_valuator_class (GdkDisplay *display, |
205 | GdkDevice *device, |
206 | Atom valuator_label, |
207 | double min, |
208 | double max, |
209 | double resolution) |
210 | { |
211 | static gboolean initialized = FALSE; |
212 | static Atom label_atoms [GDK_AXIS_LAST] = { 0 }; |
213 | GdkAxisUse use = GDK_AXIS_IGNORE; |
214 | int i; |
215 | |
216 | if (!initialized) |
217 | { |
218 | label_atoms [GDK_AXIS_X] = gdk_x11_get_xatom_by_name_for_display (display, atom_name: "Abs X" ); |
219 | label_atoms [GDK_AXIS_Y] = gdk_x11_get_xatom_by_name_for_display (display, atom_name: "Abs Y" ); |
220 | label_atoms [GDK_AXIS_PRESSURE] = gdk_x11_get_xatom_by_name_for_display (display, atom_name: "Abs Pressure" ); |
221 | label_atoms [GDK_AXIS_XTILT] = gdk_x11_get_xatom_by_name_for_display (display, atom_name: "Abs Tilt X" ); |
222 | label_atoms [GDK_AXIS_YTILT] = gdk_x11_get_xatom_by_name_for_display (display, atom_name: "Abs Tilt Y" ); |
223 | label_atoms [GDK_AXIS_WHEEL] = gdk_x11_get_xatom_by_name_for_display (display, atom_name: "Abs Wheel" ); |
224 | initialized = TRUE; |
225 | } |
226 | |
227 | for (i = GDK_AXIS_IGNORE; i < GDK_AXIS_LAST; i++) |
228 | { |
229 | if (label_atoms[i] == valuator_label) |
230 | { |
231 | use = i; |
232 | break; |
233 | } |
234 | } |
235 | |
236 | _gdk_device_add_axis (device, use, min_value: min, max_value: max, resolution); |
237 | GDK_DISPLAY_NOTE (display, INPUT, |
238 | { |
239 | const char *label; |
240 | |
241 | if (valuator_label != None) |
242 | label = gdk_x11_get_xatom_name_for_display (display, valuator_label); |
243 | else |
244 | label = NULL; |
245 | |
246 | g_message ("\n\taxis: %s %s" , label, use == GDK_AXIS_IGNORE ? "(ignored)" : "(used)" ); |
247 | }); |
248 | } |
249 | |
250 | static void |
251 | translate_device_classes (GdkDisplay *display, |
252 | GdkDevice *device, |
253 | XIAnyClassInfo **classes, |
254 | guint n_classes) |
255 | { |
256 | int i; |
257 | |
258 | g_object_freeze_notify (G_OBJECT (device)); |
259 | |
260 | for (i = 0; i < n_classes; i++) |
261 | { |
262 | XIAnyClassInfo *class_info = classes[i]; |
263 | |
264 | switch (class_info->type) |
265 | { |
266 | case XIKeyClass: |
267 | { |
268 | /* Not used */ |
269 | } |
270 | break; |
271 | case XIValuatorClass: |
272 | { |
273 | XIValuatorClassInfo *valuator_info = (XIValuatorClassInfo *) class_info; |
274 | translate_valuator_class (display, device, |
275 | valuator_label: valuator_info->label, |
276 | min: valuator_info->min, |
277 | max: valuator_info->max, |
278 | resolution: valuator_info->resolution); |
279 | } |
280 | break; |
281 | #ifdef XINPUT_2_2 |
282 | case XIScrollClass: |
283 | { |
284 | XIScrollClassInfo *scroll_info = (XIScrollClassInfo *) class_info; |
285 | GdkScrollDirection direction; |
286 | |
287 | if (scroll_info->scroll_type == XIScrollTypeVertical) |
288 | direction = GDK_SCROLL_DOWN; |
289 | else |
290 | direction = GDK_SCROLL_RIGHT; |
291 | |
292 | GDK_DISPLAY_NOTE (display, INPUT, |
293 | g_message ("\n\tscroll valuator %d: %s, increment %f" , |
294 | scroll_info->number, |
295 | scroll_info->scroll_type == XIScrollTypeVertical |
296 | ? "vertical" |
297 | : "horizontal" , |
298 | scroll_info->increment)); |
299 | |
300 | _gdk_x11_device_xi2_add_scroll_valuator (GDK_X11_DEVICE_XI2 (device), |
301 | n_valuator: scroll_info->number, |
302 | direction, |
303 | increment: scroll_info->increment); |
304 | } |
305 | break; |
306 | #endif /* XINPUT_2_2 */ |
307 | default: |
308 | /* Ignore */ |
309 | break; |
310 | } |
311 | } |
312 | |
313 | g_object_thaw_notify (G_OBJECT (device)); |
314 | } |
315 | |
316 | static gboolean |
317 | is_touch_device (XIAnyClassInfo **classes, |
318 | guint n_classes, |
319 | GdkInputSource *device_type, |
320 | int *num_touches) |
321 | { |
322 | #ifdef XINPUT_2_2 |
323 | guint i; |
324 | |
325 | for (i = 0; i < n_classes; i++) |
326 | { |
327 | XITouchClassInfo *class = (XITouchClassInfo *) classes[i]; |
328 | |
329 | if (class->type != XITouchClass) |
330 | continue; |
331 | |
332 | if (class->num_touches > 0) |
333 | { |
334 | if (class->mode == XIDirectTouch) |
335 | *device_type = GDK_SOURCE_TOUCHSCREEN; |
336 | else if (class->mode == XIDependentTouch) |
337 | *device_type = GDK_SOURCE_TOUCHPAD; |
338 | else |
339 | continue; |
340 | |
341 | *num_touches = class->num_touches; |
342 | |
343 | return TRUE; |
344 | } |
345 | } |
346 | #endif |
347 | |
348 | return FALSE; |
349 | } |
350 | |
351 | static gboolean |
352 | has_abs_axes (GdkDisplay *display, |
353 | XIAnyClassInfo **classes, |
354 | guint n_classes) |
355 | { |
356 | gboolean has_x = FALSE, has_y = FALSE; |
357 | Atom abs_x, abs_y; |
358 | guint i; |
359 | |
360 | abs_x = gdk_x11_get_xatom_by_name_for_display (display, atom_name: "Abs X" ); |
361 | abs_y = gdk_x11_get_xatom_by_name_for_display (display, atom_name: "Abs Y" ); |
362 | |
363 | for (i = 0; i < n_classes; i++) |
364 | { |
365 | XIValuatorClassInfo *class = (XIValuatorClassInfo *) classes[i]; |
366 | |
367 | if (class->type != XIValuatorClass) |
368 | continue; |
369 | if (class->mode != XIModeAbsolute) |
370 | continue; |
371 | |
372 | if (class->label == abs_x) |
373 | has_x = TRUE; |
374 | else if (class->label == abs_y) |
375 | has_y = TRUE; |
376 | |
377 | if (has_x && has_y) |
378 | break; |
379 | } |
380 | |
381 | return (has_x && has_y); |
382 | } |
383 | |
384 | static gboolean |
385 | get_device_ids (GdkDisplay *display, |
386 | XIDeviceInfo *info, |
387 | char **vendor_id, |
388 | char **product_id) |
389 | { |
390 | gulong nitems, bytes_after; |
391 | guint32 *data; |
392 | int rc, format; |
393 | Atom prop, type; |
394 | |
395 | gdk_x11_display_error_trap_push (display); |
396 | |
397 | prop = XInternAtom (GDK_DISPLAY_XDISPLAY (display), "Device Product ID" , True); |
398 | |
399 | if (prop == None) |
400 | { |
401 | gdk_x11_display_error_trap_pop_ignored (display); |
402 | return 0; |
403 | } |
404 | |
405 | rc = XIGetProperty (GDK_DISPLAY_XDISPLAY (display), |
406 | deviceid: info->deviceid, property: prop, |
407 | offset: 0, length: 2, False, XA_INTEGER, type_return: &type, format_return: &format, num_items_return: &nitems, bytes_after_return: &bytes_after, |
408 | data: (guchar **) &data); |
409 | gdk_x11_display_error_trap_pop_ignored (display); |
410 | |
411 | if (rc != Success || type != XA_INTEGER || format != 32 || nitems != 2) |
412 | return FALSE; |
413 | |
414 | if (vendor_id) |
415 | *vendor_id = g_strdup_printf (format: "%.4x" , data[0]); |
416 | if (product_id) |
417 | *product_id = g_strdup_printf (format: "%.4x" , data[1]); |
418 | |
419 | XFree (data); |
420 | |
421 | return TRUE; |
422 | } |
423 | |
424 | static gboolean |
425 | has_bool_prop (GdkDisplay *display, |
426 | XIDeviceInfo *info, |
427 | const char *prop_name) |
428 | { |
429 | gulong nitems, bytes_after; |
430 | guint32 *data; |
431 | int rc, format; |
432 | Atom type; |
433 | |
434 | gdk_x11_display_error_trap_push (display); |
435 | |
436 | rc = XIGetProperty (GDK_DISPLAY_XDISPLAY (display), |
437 | deviceid: info->deviceid, |
438 | property: gdk_x11_get_xatom_by_name_for_display (display, atom_name: prop_name), |
439 | offset: 0, length: 1, False, XA_INTEGER, type_return: &type, format_return: &format, num_items_return: &nitems, bytes_after_return: &bytes_after, |
440 | data: (guchar **) &data); |
441 | gdk_x11_display_error_trap_pop_ignored (display); |
442 | |
443 | if (rc != Success || type != XA_INTEGER || format != 8 || nitems != 1) |
444 | return FALSE; |
445 | |
446 | XFree (data); |
447 | |
448 | return TRUE; |
449 | } |
450 | |
451 | static gboolean |
452 | is_touchpad_device (GdkDisplay *display, |
453 | XIDeviceInfo *info) |
454 | { |
455 | /* |
456 | * Touchpads are heuristically recognized via XI properties that the various |
457 | * Xorg drivers expose: |
458 | * libinput: libinput Tapping Enabled |
459 | * synaptics: Synaptics Off |
460 | * cmt: Raw Touch Passthrough |
461 | */ |
462 | return has_bool_prop (display, info, prop_name: "libinput Tapping Enabled" ) || |
463 | has_bool_prop (display, info, prop_name: "Synaptics Off" ) || |
464 | has_bool_prop (display, info, prop_name: "Raw Touch Passthrough" ); |
465 | } |
466 | |
467 | static GdkDevice * |
468 | create_device (GdkX11DeviceManagerXI2 *device_manager, |
469 | GdkDisplay *display, |
470 | XIDeviceInfo *dev) |
471 | { |
472 | GdkInputSource input_source; |
473 | GdkInputSource touch_source; |
474 | GdkX11DeviceType type; |
475 | GdkDevice *device; |
476 | int num_touches = 0; |
477 | char *vendor_id = NULL, *product_id = NULL; |
478 | |
479 | if (dev->use == XIMasterKeyboard || dev->use == XISlaveKeyboard) |
480 | input_source = GDK_SOURCE_KEYBOARD; |
481 | else if (is_touchpad_device (display, info: dev)) |
482 | input_source = GDK_SOURCE_TOUCHPAD; |
483 | else if (dev->use == XISlavePointer && |
484 | is_touch_device (classes: dev->classes, n_classes: dev->num_classes, device_type: &touch_source, num_touches: &num_touches)) |
485 | input_source = touch_source; |
486 | else |
487 | { |
488 | char *tmp_name; |
489 | |
490 | tmp_name = g_ascii_strdown (str: dev->name, len: -1); |
491 | |
492 | if (strstr (haystack: tmp_name, needle: " pad" )) |
493 | input_source = GDK_SOURCE_TABLET_PAD; |
494 | else if (strstr (haystack: tmp_name, needle: "wacom" ) || |
495 | strstr (haystack: tmp_name, needle: "pen" ) || |
496 | strstr (haystack: tmp_name, needle: "eraser" )) |
497 | input_source = GDK_SOURCE_PEN; |
498 | else if (!strstr (haystack: tmp_name, needle: "mouse" ) && |
499 | !strstr (haystack: tmp_name, needle: "pointer" ) && |
500 | !strstr (haystack: tmp_name, needle: "qemu usb tablet" ) && |
501 | !strstr (haystack: tmp_name, needle: "spice vdagent tablet" ) && |
502 | !strstr (haystack: tmp_name, needle: "virtualbox usb tablet" ) && |
503 | has_abs_axes (display, classes: dev->classes, n_classes: dev->num_classes)) |
504 | input_source = GDK_SOURCE_TOUCHSCREEN; |
505 | else if (strstr (haystack: tmp_name, needle: "trackpoint" ) || |
506 | strstr (haystack: tmp_name, needle: "dualpoint stick" )) |
507 | input_source = GDK_SOURCE_TRACKPOINT; |
508 | else |
509 | input_source = GDK_SOURCE_MOUSE; |
510 | |
511 | g_free (mem: tmp_name); |
512 | } |
513 | |
514 | switch (dev->use) |
515 | { |
516 | case XIMasterKeyboard: |
517 | case XIMasterPointer: |
518 | type = GDK_X11_DEVICE_TYPE_LOGICAL; |
519 | break; |
520 | case XISlaveKeyboard: |
521 | case XISlavePointer: |
522 | type = GDK_X11_DEVICE_TYPE_PHYSICAL; |
523 | break; |
524 | case XIFloatingSlave: |
525 | default: |
526 | type = GDK_X11_DEVICE_TYPE_FLOATING; |
527 | break; |
528 | } |
529 | |
530 | GDK_DISPLAY_NOTE (display, INPUT, |
531 | ({ |
532 | const char *type_names[] = { "logical" , "physical" , "floating" }; |
533 | const char *source_names[] = { "mouse" , "pen" , "eraser" , "cursor" , "keyboard" , "direct touch" , "indirect touch" , "trackpoint" , "pad" }; |
534 | g_message ("input device:\n\tname: %s\n\ttype: %s\n\tsource: %s\n\thas cursor: %d\n\ttouches: %d" , |
535 | dev->name, |
536 | type_names[type], |
537 | source_names[input_source], |
538 | dev->use == XIMasterPointer, |
539 | num_touches); |
540 | })); |
541 | |
542 | if (dev->use != XIMasterKeyboard && |
543 | dev->use != XIMasterPointer) |
544 | get_device_ids (display, info: dev, vendor_id: &vendor_id, product_id: &product_id); |
545 | |
546 | device = g_object_new (GDK_TYPE_X11_DEVICE_XI2, |
547 | first_property_name: "name" , dev->name, |
548 | "source" , input_source, |
549 | "has-cursor" , (dev->use == XIMasterPointer), |
550 | "display" , display, |
551 | "device-id" , dev->deviceid, |
552 | "vendor-id" , vendor_id, |
553 | "product-id" , product_id, |
554 | "num-touches" , num_touches, |
555 | NULL); |
556 | gdk_x11_device_xi2_set_device_type (device: (GdkX11DeviceXI2 *) device, type); |
557 | |
558 | translate_device_classes (display, device, classes: dev->classes, n_classes: dev->num_classes); |
559 | g_free (mem: vendor_id); |
560 | g_free (mem: product_id); |
561 | |
562 | return device; |
563 | } |
564 | |
565 | static void |
566 | ensure_seat_for_device_pair (GdkX11DeviceManagerXI2 *device_manager, |
567 | GdkDevice *device1, |
568 | GdkDevice *device2) |
569 | { |
570 | GdkDevice *pointer, *keyboard; |
571 | GdkDisplay *display; |
572 | GdkSeat *seat; |
573 | |
574 | display = device_manager->display; |
575 | seat = gdk_device_get_seat (device: device1); |
576 | |
577 | if (!seat) |
578 | { |
579 | if (gdk_device_get_source (device: device1) == GDK_SOURCE_KEYBOARD) |
580 | { |
581 | keyboard = device1; |
582 | pointer = device2; |
583 | } |
584 | else |
585 | { |
586 | pointer = device1; |
587 | keyboard = device2; |
588 | } |
589 | |
590 | seat = gdk_seat_default_new_for_logical_pair (pointer, keyboard); |
591 | gdk_display_add_seat (display, seat); |
592 | g_object_unref (object: seat); |
593 | } |
594 | } |
595 | |
596 | static GdkDevice * |
597 | add_device (GdkX11DeviceManagerXI2 *device_manager, |
598 | XIDeviceInfo *dev, |
599 | gboolean emit_signal) |
600 | { |
601 | GdkDisplay *display; |
602 | GdkDevice *device; |
603 | |
604 | display = device_manager->display; |
605 | device = create_device (device_manager, display, dev); |
606 | |
607 | g_hash_table_replace (hash_table: device_manager->id_table, |
608 | GINT_TO_POINTER (dev->deviceid), |
609 | g_object_ref (device)); |
610 | |
611 | device_manager->devices = g_list_append (list: device_manager->devices, data: device); |
612 | |
613 | if (emit_signal) |
614 | { |
615 | if (dev->use == XISlavePointer || dev->use == XISlaveKeyboard) |
616 | { |
617 | GdkDevice *logical; |
618 | GdkSeat *seat; |
619 | |
620 | /* The device manager is already constructed, then |
621 | * keep the hierarchy coherent for the added device. |
622 | */ |
623 | logical = g_hash_table_lookup (hash_table: device_manager->id_table, |
624 | GINT_TO_POINTER (dev->attachment)); |
625 | |
626 | _gdk_device_set_associated_device (device, relative: logical); |
627 | _gdk_device_add_physical_device (device: logical, physical: device); |
628 | |
629 | seat = gdk_device_get_seat (device: logical); |
630 | gdk_seat_default_add_physical_device (GDK_SEAT_DEFAULT (seat), device); |
631 | } |
632 | else if (dev->use == XIMasterPointer || dev->use == XIMasterKeyboard) |
633 | { |
634 | GdkDevice *relative; |
635 | |
636 | relative = g_hash_table_lookup (hash_table: device_manager->id_table, |
637 | GINT_TO_POINTER (dev->attachment)); |
638 | |
639 | if (relative) |
640 | { |
641 | _gdk_device_set_associated_device (device, relative); |
642 | _gdk_device_set_associated_device (device: relative, relative: device); |
643 | ensure_seat_for_device_pair (device_manager, device1: device, device2: relative); |
644 | } |
645 | } |
646 | } |
647 | |
648 | return device; |
649 | } |
650 | |
651 | static void |
652 | detach_from_seat (GdkDevice *device) |
653 | { |
654 | GdkSeat *seat = gdk_device_get_seat (device); |
655 | GdkX11DeviceXI2 *device_xi2 = (GdkX11DeviceXI2 *) device; |
656 | |
657 | if (!seat) |
658 | return; |
659 | |
660 | if (gdk_x11_device_xi2_get_device_type (device: device_xi2) == GDK_X11_DEVICE_TYPE_LOGICAL) |
661 | gdk_display_remove_seat (display: gdk_device_get_display (device), seat); |
662 | else if (gdk_x11_device_xi2_get_device_type (device: device_xi2) == GDK_X11_DEVICE_TYPE_PHYSICAL) |
663 | gdk_seat_default_remove_physical_device (GDK_SEAT_DEFAULT (seat), device); |
664 | } |
665 | |
666 | static void |
667 | remove_device (GdkX11DeviceManagerXI2 *device_manager, |
668 | int device_id) |
669 | { |
670 | GdkDevice *device; |
671 | |
672 | device = g_hash_table_lookup (hash_table: device_manager->id_table, |
673 | GINT_TO_POINTER (device_id)); |
674 | |
675 | if (device) |
676 | { |
677 | detach_from_seat (device); |
678 | |
679 | g_hash_table_remove (hash_table: device_manager->id_table, |
680 | GINT_TO_POINTER (device_id)); |
681 | |
682 | device_manager->devices = g_list_remove (list: device_manager->devices, data: device); |
683 | g_object_run_dispose (G_OBJECT (device)); |
684 | g_object_unref (object: device); |
685 | } |
686 | } |
687 | |
688 | static void |
689 | relate_logical_devices (gpointer key, |
690 | gpointer value, |
691 | gpointer user_data) |
692 | { |
693 | GdkX11DeviceManagerXI2 *device_manager; |
694 | GdkDevice *device, *relative; |
695 | |
696 | device_manager = user_data; |
697 | device = g_hash_table_lookup (hash_table: device_manager->id_table, key); |
698 | relative = g_hash_table_lookup (hash_table: device_manager->id_table, key: value); |
699 | |
700 | _gdk_device_set_associated_device (device, relative); |
701 | _gdk_device_set_associated_device (device: relative, relative: device); |
702 | ensure_seat_for_device_pair (device_manager, device1: device, device2: relative); |
703 | } |
704 | |
705 | static void |
706 | relate_physical_devices (gpointer key, |
707 | gpointer value, |
708 | gpointer user_data) |
709 | { |
710 | GdkX11DeviceManagerXI2 *device_manager; |
711 | GdkDevice *physical, *logical; |
712 | GdkSeat *seat; |
713 | |
714 | device_manager = user_data; |
715 | physical = g_hash_table_lookup (hash_table: device_manager->id_table, key); |
716 | logical = g_hash_table_lookup (hash_table: device_manager->id_table, key: value); |
717 | |
718 | _gdk_device_set_associated_device (device: physical, relative: logical); |
719 | _gdk_device_add_physical_device (device: logical, physical); |
720 | |
721 | seat = gdk_device_get_seat (device: logical); |
722 | gdk_seat_default_add_physical_device (GDK_SEAT_DEFAULT (seat), device: physical); |
723 | } |
724 | |
725 | static void |
726 | gdk_x11_device_manager_xi2_constructed (GObject *object) |
727 | { |
728 | GdkX11DeviceManagerXI2 *device_manager; |
729 | GdkDisplay *display; |
730 | GHashTable *logical_devices, *physical_devices; |
731 | Display *xdisplay; |
732 | XIDeviceInfo *info, *dev; |
733 | int ndevices, i; |
734 | XIEventMask event_mask; |
735 | unsigned char mask[2] = { 0 }; |
736 | |
737 | G_OBJECT_CLASS (gdk_x11_device_manager_xi2_parent_class)->constructed (object); |
738 | |
739 | device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object); |
740 | display = device_manager->display; |
741 | xdisplay = GDK_DISPLAY_XDISPLAY (display); |
742 | |
743 | g_assert (device_manager->major == 2); |
744 | |
745 | logical_devices = g_hash_table_new (NULL, NULL); |
746 | physical_devices = g_hash_table_new (NULL, NULL); |
747 | |
748 | info = XIQueryDevice (dpy: xdisplay, XIAllDevices, ndevices_return: &ndevices); |
749 | |
750 | /* Initialize devices list */ |
751 | for (i = 0; i < ndevices; i++) |
752 | { |
753 | dev = &info[i]; |
754 | |
755 | if (!dev->enabled) |
756 | continue; |
757 | |
758 | add_device (device_manager, dev, FALSE); |
759 | |
760 | if (dev->use == XIMasterPointer || |
761 | dev->use == XIMasterKeyboard) |
762 | { |
763 | g_hash_table_insert (hash_table: logical_devices, |
764 | GINT_TO_POINTER (dev->deviceid), |
765 | GINT_TO_POINTER (dev->attachment)); |
766 | } |
767 | else if (dev->use == XISlavePointer || |
768 | dev->use == XISlaveKeyboard) |
769 | { |
770 | g_hash_table_insert (hash_table: physical_devices, |
771 | GINT_TO_POINTER (dev->deviceid), |
772 | GINT_TO_POINTER (dev->attachment)); |
773 | } |
774 | } |
775 | |
776 | XIFreeDeviceInfo (info); |
777 | |
778 | /* Stablish relationships between devices */ |
779 | g_hash_table_foreach (hash_table: logical_devices, func: relate_logical_devices, user_data: object); |
780 | g_hash_table_destroy (hash_table: logical_devices); |
781 | |
782 | g_hash_table_foreach (hash_table: physical_devices, func: relate_physical_devices, user_data: object); |
783 | g_hash_table_destroy (hash_table: physical_devices); |
784 | |
785 | /* Connect to hierarchy change events */ |
786 | XISetMask (mask, XI_HierarchyChanged); |
787 | XISetMask (mask, XI_DeviceChanged); |
788 | XISetMask (mask, XI_PropertyEvent); |
789 | |
790 | event_mask.deviceid = XIAllDevices; |
791 | event_mask.mask_len = sizeof (mask); |
792 | event_mask.mask = mask; |
793 | |
794 | _gdk_x11_device_manager_xi2_select_events (device_manager, |
795 | GDK_DISPLAY_XROOTWIN (display), |
796 | event_mask: &event_mask); |
797 | } |
798 | |
799 | static void |
800 | gdk_x11_device_manager_xi2_dispose (GObject *object) |
801 | { |
802 | GdkX11DeviceManagerXI2 *device_manager; |
803 | |
804 | device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object); |
805 | |
806 | g_list_free_full (list: device_manager->devices, free_func: g_object_unref); |
807 | device_manager->devices = NULL; |
808 | |
809 | if (device_manager->id_table) |
810 | { |
811 | g_hash_table_destroy (hash_table: device_manager->id_table); |
812 | device_manager->id_table = NULL; |
813 | } |
814 | |
815 | G_OBJECT_CLASS (gdk_x11_device_manager_xi2_parent_class)->dispose (object); |
816 | } |
817 | |
818 | static void |
819 | gdk_x11_device_manager_xi2_set_property (GObject *object, |
820 | guint prop_id, |
821 | const GValue *value, |
822 | GParamSpec *pspec) |
823 | { |
824 | GdkX11DeviceManagerXI2 *device_manager; |
825 | |
826 | device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object); |
827 | |
828 | switch (prop_id) |
829 | { |
830 | case PROP_DISPLAY: |
831 | device_manager->display = g_value_get_object (value); |
832 | break; |
833 | case PROP_OPCODE: |
834 | device_manager->opcode = g_value_get_int (value); |
835 | break; |
836 | case PROP_MAJOR: |
837 | device_manager->major = g_value_get_int (value); |
838 | break; |
839 | case PROP_MINOR: |
840 | device_manager->minor = g_value_get_int (value); |
841 | break; |
842 | default: |
843 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
844 | break; |
845 | } |
846 | } |
847 | |
848 | static void |
849 | gdk_x11_device_manager_xi2_get_property (GObject *object, |
850 | guint prop_id, |
851 | GValue *value, |
852 | GParamSpec *pspec) |
853 | { |
854 | GdkX11DeviceManagerXI2 *device_manager; |
855 | |
856 | device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object); |
857 | |
858 | switch (prop_id) |
859 | { |
860 | case PROP_DISPLAY: |
861 | g_value_set_object (value, v_object: device_manager->display); |
862 | break; |
863 | case PROP_OPCODE: |
864 | g_value_set_int (value, v_int: device_manager->opcode); |
865 | break; |
866 | case PROP_MAJOR: |
867 | g_value_set_int (value, v_int: device_manager->major); |
868 | break; |
869 | case PROP_MINOR: |
870 | g_value_set_int (value, v_int: device_manager->minor); |
871 | break; |
872 | default: |
873 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
874 | break; |
875 | } |
876 | } |
877 | |
878 | static void |
879 | gdk_x11_device_manager_xi2_event_translator_init (GdkEventTranslatorIface *iface) |
880 | { |
881 | iface->translate_event = gdk_x11_device_manager_xi2_translate_event; |
882 | iface->get_handled_events = gdk_x11_device_manager_xi2_get_handled_events; |
883 | iface->select_surface_events = gdk_x11_device_manager_xi2_select_surface_events; |
884 | iface->get_surface = gdk_x11_device_manager_xi2_get_surface; |
885 | } |
886 | |
887 | static void |
888 | handle_hierarchy_changed (GdkX11DeviceManagerXI2 *device_manager, |
889 | XIHierarchyEvent *ev) |
890 | { |
891 | GdkDisplay *display; |
892 | Display *xdisplay; |
893 | XIDeviceInfo *info; |
894 | int ndevices; |
895 | int i; |
896 | |
897 | display = device_manager->display; |
898 | xdisplay = GDK_DISPLAY_XDISPLAY (display); |
899 | |
900 | for (i = 0; i < ev->num_info; i++) |
901 | { |
902 | if (ev->info[i].flags & XIDeviceEnabled) |
903 | { |
904 | gdk_x11_display_error_trap_push (display); |
905 | info = XIQueryDevice (dpy: xdisplay, deviceid: ev->info[i].deviceid, ndevices_return: &ndevices); |
906 | gdk_x11_display_error_trap_pop_ignored (display); |
907 | if (info) |
908 | { |
909 | add_device (device_manager, dev: &info[0], TRUE); |
910 | XIFreeDeviceInfo (info); |
911 | } |
912 | } |
913 | else if (ev->info[i].flags & XIDeviceDisabled) |
914 | remove_device (device_manager, device_id: ev->info[i].deviceid); |
915 | else if (ev->info[i].flags & XISlaveAttached || |
916 | ev->info[i].flags & XISlaveDetached) |
917 | { |
918 | GdkDevice *logical = NULL, *physical; |
919 | GdkSeat *seat; |
920 | |
921 | physical = g_hash_table_lookup (hash_table: device_manager->id_table, |
922 | GINT_TO_POINTER (ev->info[i].deviceid)); |
923 | |
924 | if (!physical) |
925 | continue; |
926 | |
927 | seat = gdk_device_get_seat (device: physical); |
928 | gdk_seat_default_remove_physical_device (GDK_SEAT_DEFAULT (seat), device: physical); |
929 | |
930 | /* Add new logical device if it's an attachment event */ |
931 | if (ev->info[i].flags & XISlaveAttached) |
932 | { |
933 | gdk_x11_display_error_trap_push (display); |
934 | info = XIQueryDevice (dpy: xdisplay, deviceid: ev->info[i].deviceid, ndevices_return: &ndevices); |
935 | gdk_x11_display_error_trap_pop_ignored (display); |
936 | if (info) |
937 | { |
938 | logical = g_hash_table_lookup (hash_table: device_manager->id_table, |
939 | GINT_TO_POINTER (info->attachment)); |
940 | XIFreeDeviceInfo (info); |
941 | } |
942 | |
943 | if (logical != NULL) |
944 | { |
945 | _gdk_device_set_associated_device (device: physical, relative: logical); |
946 | _gdk_device_add_physical_device (device: logical, physical); |
947 | |
948 | seat = gdk_device_get_seat (device: logical); |
949 | gdk_seat_default_add_physical_device (GDK_SEAT_DEFAULT (seat), device: physical); |
950 | } |
951 | } |
952 | } |
953 | } |
954 | } |
955 | |
956 | static void |
957 | handle_device_changed (GdkX11DeviceManagerXI2 *device_manager, |
958 | XIDeviceChangedEvent *ev) |
959 | { |
960 | GdkDisplay *display; |
961 | GdkDevice *device, *source_device; |
962 | |
963 | display = device_manager->display; |
964 | device = g_hash_table_lookup (hash_table: device_manager->id_table, |
965 | GUINT_TO_POINTER (ev->deviceid)); |
966 | source_device = g_hash_table_lookup (hash_table: device_manager->id_table, |
967 | GUINT_TO_POINTER (ev->sourceid)); |
968 | |
969 | if (device) |
970 | { |
971 | _gdk_device_reset_axes (device); |
972 | _gdk_device_xi2_unset_scroll_valuators (device: (GdkX11DeviceXI2 *) device); |
973 | gdk_x11_device_xi2_store_axes (GDK_X11_DEVICE_XI2 (device), NULL, n_axes: 0); |
974 | translate_device_classes (display, device, classes: ev->classes, n_classes: ev->num_classes); |
975 | |
976 | g_signal_emit_by_name (G_OBJECT (device), detailed_signal: "changed" ); |
977 | } |
978 | |
979 | if (source_device) |
980 | _gdk_device_xi2_reset_scroll_valuators (GDK_X11_DEVICE_XI2 (source_device)); |
981 | } |
982 | |
983 | static gboolean |
984 | device_get_tool_serial_and_id (GdkDevice *device, |
985 | guint *serial_id, |
986 | guint *id) |
987 | { |
988 | GdkDisplay *display; |
989 | gulong nitems, bytes_after; |
990 | guint32 *data; |
991 | int rc, format; |
992 | Atom type; |
993 | |
994 | display = gdk_device_get_display (device); |
995 | |
996 | gdk_x11_display_error_trap_push (display); |
997 | |
998 | rc = XIGetProperty (GDK_DISPLAY_XDISPLAY (display), |
999 | deviceid: gdk_x11_device_get_id (device), |
1000 | property: gdk_x11_get_xatom_by_name_for_display (display, atom_name: "Wacom Serial IDs" ), |
1001 | offset: 0, length: 5, False, XA_INTEGER, type_return: &type, format_return: &format, num_items_return: &nitems, bytes_after_return: &bytes_after, |
1002 | data: (guchar **) &data); |
1003 | gdk_x11_display_error_trap_pop_ignored (display); |
1004 | |
1005 | if (rc != Success) |
1006 | return FALSE; |
1007 | |
1008 | if (type == XA_INTEGER && format == 32) |
1009 | { |
1010 | if (nitems >= 4) |
1011 | *serial_id = data[3]; |
1012 | if (nitems >= 5) |
1013 | *id = data[4]; |
1014 | } |
1015 | |
1016 | XFree (data); |
1017 | |
1018 | return TRUE; |
1019 | } |
1020 | |
1021 | static GdkDeviceToolType |
1022 | device_get_tool_type (GdkDevice *device) |
1023 | { |
1024 | GdkDisplay *display; |
1025 | gulong nitems, bytes_after; |
1026 | guint32 *data; |
1027 | int rc, format; |
1028 | Atom type; |
1029 | Atom device_type; |
1030 | Atom types[N_WACOM_TYPE_ATOMS]; |
1031 | GdkDeviceToolType tool_type = GDK_DEVICE_TOOL_TYPE_UNKNOWN; |
1032 | |
1033 | display = gdk_device_get_display (device); |
1034 | gdk_x11_display_error_trap_push (display); |
1035 | |
1036 | rc = XIGetProperty (GDK_DISPLAY_XDISPLAY (display), |
1037 | deviceid: gdk_x11_device_get_id (device), |
1038 | property: gdk_x11_get_xatom_by_name_for_display (display, atom_name: "Wacom Tool Type" ), |
1039 | offset: 0, length: 1, False, XA_ATOM, type_return: &type, format_return: &format, num_items_return: &nitems, bytes_after_return: &bytes_after, |
1040 | data: (guchar **) &data); |
1041 | gdk_x11_display_error_trap_pop_ignored (display); |
1042 | |
1043 | if (rc != Success) |
1044 | return GDK_DEVICE_TOOL_TYPE_UNKNOWN; |
1045 | |
1046 | if (type != XA_ATOM || format != 32 || nitems != 1) |
1047 | { |
1048 | XFree (data); |
1049 | return GDK_DEVICE_TOOL_TYPE_UNKNOWN; |
1050 | } |
1051 | |
1052 | device_type = *data; |
1053 | XFree (data); |
1054 | |
1055 | if (device_type == 0) |
1056 | return GDK_DEVICE_TOOL_TYPE_UNKNOWN; |
1057 | |
1058 | gdk_x11_display_error_trap_push (display); |
1059 | rc = XInternAtoms (GDK_DISPLAY_XDISPLAY (display), |
1060 | (char **) wacom_type_atoms, |
1061 | N_WACOM_TYPE_ATOMS, |
1062 | False, |
1063 | types); |
1064 | gdk_x11_display_error_trap_pop_ignored (display); |
1065 | |
1066 | if (rc == 0) |
1067 | return GDK_DEVICE_TOOL_TYPE_UNKNOWN; |
1068 | |
1069 | if (device_type == types[WACOM_TYPE_STYLUS]) |
1070 | tool_type = GDK_DEVICE_TOOL_TYPE_PEN; |
1071 | else if (device_type == types[WACOM_TYPE_CURSOR]) |
1072 | tool_type = GDK_DEVICE_TOOL_TYPE_MOUSE; |
1073 | else if (device_type == types[WACOM_TYPE_ERASER]) |
1074 | tool_type = GDK_DEVICE_TOOL_TYPE_ERASER; |
1075 | else if (device_type == types[WACOM_TYPE_TOUCH]) |
1076 | tool_type = GDK_DEVICE_TOOL_TYPE_UNKNOWN; |
1077 | |
1078 | return tool_type; |
1079 | } |
1080 | |
1081 | static void |
1082 | handle_property_change (GdkX11DeviceManagerXI2 *device_manager, |
1083 | XIPropertyEvent *ev) |
1084 | { |
1085 | GdkDevice *device; |
1086 | |
1087 | device = g_hash_table_lookup (hash_table: device_manager->id_table, |
1088 | GUINT_TO_POINTER (ev->deviceid)); |
1089 | |
1090 | if (device != NULL && |
1091 | ev->property == gdk_x11_get_xatom_by_name_for_display (display: gdk_device_get_display (device), atom_name: "Wacom Serial IDs" )) |
1092 | { |
1093 | GdkDeviceTool *tool = NULL; |
1094 | guint serial_id = 0, tool_id = 0; |
1095 | GdkSeat *seat; |
1096 | |
1097 | if (ev->what != XIPropertyDeleted && |
1098 | device_get_tool_serial_and_id (device, serial_id: &serial_id, id: &tool_id)) |
1099 | { |
1100 | GdkDeviceToolType tool_type; |
1101 | |
1102 | seat = gdk_device_get_seat (device); |
1103 | tool_type = device_get_tool_type (device); |
1104 | |
1105 | if (tool_type != GDK_DEVICE_TOOL_TYPE_UNKNOWN) |
1106 | { |
1107 | tool = gdk_seat_get_tool (seat, serial: serial_id, hw_id: tool_id, type: tool_type); |
1108 | |
1109 | if (!tool && serial_id > 0) |
1110 | { |
1111 | tool = gdk_device_tool_new (serial: serial_id, hw_id: tool_id, type: tool_type, tool_axes: 0); |
1112 | gdk_seat_default_add_tool (GDK_SEAT_DEFAULT (seat), tool); |
1113 | } |
1114 | } |
1115 | } |
1116 | |
1117 | gdk_device_update_tool (device, tool); |
1118 | } |
1119 | } |
1120 | |
1121 | static GdkCrossingMode |
1122 | translate_crossing_mode (int mode) |
1123 | { |
1124 | switch (mode) |
1125 | { |
1126 | case XINotifyNormal: |
1127 | return GDK_CROSSING_NORMAL; |
1128 | case XINotifyGrab: |
1129 | case XINotifyPassiveGrab: |
1130 | return GDK_CROSSING_GRAB; |
1131 | case XINotifyUngrab: |
1132 | case XINotifyPassiveUngrab: |
1133 | return GDK_CROSSING_UNGRAB; |
1134 | case XINotifyWhileGrabbed: |
1135 | /* Fall through, unexpected in pointer crossing events */ |
1136 | default: |
1137 | g_assert_not_reached (); |
1138 | return GDK_CROSSING_NORMAL; |
1139 | } |
1140 | } |
1141 | |
1142 | static GdkNotifyType |
1143 | translate_notify_type (int detail) |
1144 | { |
1145 | switch (detail) |
1146 | { |
1147 | case NotifyInferior: |
1148 | return GDK_NOTIFY_INFERIOR; |
1149 | case NotifyAncestor: |
1150 | return GDK_NOTIFY_ANCESTOR; |
1151 | case NotifyVirtual: |
1152 | return GDK_NOTIFY_VIRTUAL; |
1153 | case NotifyNonlinear: |
1154 | return GDK_NOTIFY_NONLINEAR; |
1155 | case NotifyNonlinearVirtual: |
1156 | return GDK_NOTIFY_NONLINEAR_VIRTUAL; |
1157 | default: |
1158 | g_assert_not_reached (); |
1159 | return GDK_NOTIFY_UNKNOWN; |
1160 | } |
1161 | } |
1162 | |
1163 | static void |
1164 | set_user_time (GdkEvent *event) |
1165 | { |
1166 | GdkSurface *surface; |
1167 | guint32 time; |
1168 | |
1169 | surface = gdk_event_get_surface (event); |
1170 | g_return_if_fail (GDK_IS_SURFACE (surface)); |
1171 | |
1172 | time = gdk_event_get_time (event); |
1173 | |
1174 | /* If an event doesn't have a valid timestamp, we shouldn't use it |
1175 | * to update the latest user interaction time. |
1176 | */ |
1177 | if (time != GDK_CURRENT_TIME) |
1178 | gdk_x11_surface_set_user_time (surface, timestamp: time); |
1179 | } |
1180 | |
1181 | static double * |
1182 | translate_axes (GdkDevice *device, |
1183 | double x, |
1184 | double y, |
1185 | GdkSurface *surface, |
1186 | XIValuatorState *valuators) |
1187 | { |
1188 | guint n_axes, i; |
1189 | double *axes; |
1190 | double *vals; |
1191 | |
1192 | n_axes = gdk_device_get_n_axes (device); |
1193 | axes = g_new0 (double, GDK_AXIS_LAST); |
1194 | vals = valuators->values; |
1195 | |
1196 | for (i = 0; i < MIN (valuators->mask_len * 8, n_axes); i++) |
1197 | { |
1198 | GdkAxisUse use; |
1199 | double val; |
1200 | |
1201 | if (!XIMaskIsSet (valuators->mask, i)) |
1202 | continue; |
1203 | |
1204 | use = gdk_device_get_axis_use (device, index_: i); |
1205 | val = *vals++; |
1206 | |
1207 | switch ((guint) use) |
1208 | { |
1209 | case GDK_AXIS_X: |
1210 | case GDK_AXIS_Y: |
1211 | { |
1212 | if (use == GDK_AXIS_X) |
1213 | axes[use] = x; |
1214 | else |
1215 | axes[use] = y; |
1216 | } |
1217 | break; |
1218 | default: |
1219 | _gdk_device_translate_axis (device, index: i, value: val, axis_value: &axes[use]); |
1220 | break; |
1221 | } |
1222 | } |
1223 | |
1224 | gdk_x11_device_xi2_store_axes (GDK_X11_DEVICE_XI2 (device), axes, n_axes); |
1225 | |
1226 | return axes; |
1227 | } |
1228 | |
1229 | static gboolean |
1230 | get_event_surface (GdkEventTranslator *translator, |
1231 | XIEvent *ev, |
1232 | GdkSurface **surface_p) |
1233 | { |
1234 | GdkDisplay *display; |
1235 | GdkSurface *surface = NULL; |
1236 | gboolean should_have_window = TRUE; |
1237 | |
1238 | display = GDK_X11_DEVICE_MANAGER_XI2 (translator)->display; |
1239 | |
1240 | switch (ev->evtype) |
1241 | { |
1242 | case XI_KeyPress: |
1243 | case XI_KeyRelease: |
1244 | case XI_ButtonPress: |
1245 | case XI_ButtonRelease: |
1246 | case XI_Motion: |
1247 | #ifdef XINPUT_2_2 |
1248 | case XI_TouchUpdate: |
1249 | case XI_TouchBegin: |
1250 | case XI_TouchEnd: |
1251 | #endif /* XINPUT_2_2 */ |
1252 | { |
1253 | XIDeviceEvent *xev = (XIDeviceEvent *) ev; |
1254 | |
1255 | surface = gdk_x11_surface_lookup_for_display (display, window: xev->event); |
1256 | |
1257 | /* Apply keyboard grabs to non-native windows */ |
1258 | if (ev->evtype == XI_KeyPress || ev->evtype == XI_KeyRelease) |
1259 | { |
1260 | GdkDeviceGrabInfo *info; |
1261 | GdkDevice *device; |
1262 | gulong serial; |
1263 | |
1264 | device = g_hash_table_lookup (GDK_X11_DEVICE_MANAGER_XI2 (translator)->id_table, |
1265 | GUINT_TO_POINTER (((XIDeviceEvent *) ev)->deviceid)); |
1266 | |
1267 | serial = _gdk_display_get_next_serial (display); |
1268 | info = _gdk_display_has_device_grab (display, device, serial); |
1269 | |
1270 | if (info && !info->owner_events) |
1271 | { |
1272 | /* Report key event against grab surface */ |
1273 | surface = info->surface; |
1274 | } |
1275 | } |
1276 | } |
1277 | break; |
1278 | #ifdef XINPUT_2_4 |
1279 | case XI_GesturePinchBegin: |
1280 | case XI_GesturePinchUpdate: |
1281 | case XI_GesturePinchEnd: |
1282 | { |
1283 | XIGesturePinchEvent *xev = (XIGesturePinchEvent *) ev; |
1284 | |
1285 | surface = gdk_x11_surface_lookup_for_display (display, xev->event); |
1286 | } |
1287 | break; |
1288 | case XI_GestureSwipeBegin: |
1289 | case XI_GestureSwipeUpdate: |
1290 | case XI_GestureSwipeEnd: |
1291 | { |
1292 | XIGestureSwipeEvent *xev = (XIGestureSwipeEvent *) ev; |
1293 | |
1294 | surface = gdk_x11_surface_lookup_for_display (display, xev->event); |
1295 | } |
1296 | break; |
1297 | #endif /* XINPUT_2_4 */ |
1298 | case XI_Enter: |
1299 | case XI_Leave: |
1300 | case XI_FocusIn: |
1301 | case XI_FocusOut: |
1302 | { |
1303 | XIEnterEvent *xev = (XIEnterEvent *) ev; |
1304 | |
1305 | surface = gdk_x11_surface_lookup_for_display (display, window: xev->event); |
1306 | } |
1307 | break; |
1308 | default: |
1309 | should_have_window = FALSE; |
1310 | break; |
1311 | } |
1312 | |
1313 | *surface_p = surface; |
1314 | |
1315 | if (should_have_window && !surface) |
1316 | return FALSE; |
1317 | |
1318 | return TRUE; |
1319 | } |
1320 | |
1321 | static gboolean |
1322 | scroll_valuators_changed (GdkX11DeviceXI2 *device, |
1323 | XIValuatorState *valuators, |
1324 | double *dx, |
1325 | double *dy) |
1326 | { |
1327 | gboolean has_scroll_valuators = FALSE; |
1328 | GdkScrollDirection direction; |
1329 | guint n_axes, i, n_val; |
1330 | double *vals; |
1331 | |
1332 | n_axes = gdk_device_get_n_axes (GDK_DEVICE (device)); |
1333 | vals = valuators->values; |
1334 | *dx = *dy = 0; |
1335 | n_val = 0; |
1336 | |
1337 | for (i = 0; i < MIN (valuators->mask_len * 8, n_axes); i++) |
1338 | { |
1339 | double delta; |
1340 | |
1341 | if (!XIMaskIsSet (valuators->mask, i)) |
1342 | continue; |
1343 | |
1344 | if (_gdk_x11_device_xi2_get_scroll_delta (device, n_valuator: i, valuator_value: vals[n_val], |
1345 | direction_ret: &direction, delta_ret: &delta)) |
1346 | { |
1347 | has_scroll_valuators = TRUE; |
1348 | |
1349 | if (direction == GDK_SCROLL_UP || |
1350 | direction == GDK_SCROLL_DOWN) |
1351 | *dy = delta; |
1352 | else |
1353 | *dx = delta; |
1354 | } |
1355 | |
1356 | n_val++; |
1357 | } |
1358 | |
1359 | return has_scroll_valuators; |
1360 | } |
1361 | |
1362 | /* We only care about focus events that indicate that _this_ |
1363 | * surface (not an ancestor or child) got or lost the focus |
1364 | */ |
1365 | static void |
1366 | _gdk_device_manager_xi2_handle_focus (GdkSurface *surface, |
1367 | Window original, |
1368 | GdkDevice *device, |
1369 | GdkDevice *source_device, |
1370 | gboolean focus_in, |
1371 | int detail, |
1372 | int mode) |
1373 | { |
1374 | GdkToplevelX11 *toplevel; |
1375 | GdkX11Screen *x11_screen; |
1376 | gboolean had_focus; |
1377 | |
1378 | g_return_if_fail (GDK_IS_SURFACE (surface)); |
1379 | g_return_if_fail (GDK_IS_DEVICE (device)); |
1380 | g_return_if_fail (source_device == NULL || GDK_IS_DEVICE (source_device)); |
1381 | |
1382 | GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS, |
1383 | g_message ("focus out:\t\twindow: %ld, detail: %s, mode: %s" , |
1384 | GDK_SURFACE_XID (surface), |
1385 | notify_details[detail], |
1386 | notify_modes[mode])); |
1387 | |
1388 | toplevel = _gdk_x11_surface_get_toplevel (window: surface); |
1389 | |
1390 | if (!toplevel) |
1391 | return; |
1392 | |
1393 | if (toplevel->focus_window == original) |
1394 | return; |
1395 | |
1396 | had_focus = HAS_FOCUS (toplevel); |
1397 | x11_screen = GDK_X11_SCREEN (GDK_SURFACE_SCREEN (surface)); |
1398 | |
1399 | switch (detail) |
1400 | { |
1401 | case NotifyAncestor: |
1402 | case NotifyVirtual: |
1403 | /* When the focus moves from an ancestor of the window to |
1404 | * the window or a descendent of the window, *and* the |
1405 | * pointer is inside the window, then we were previously |
1406 | * receiving keystroke events in the has_pointer_focus |
1407 | * case and are now receiving them in the |
1408 | * has_focus_window case. |
1409 | */ |
1410 | if (toplevel->has_pointer && |
1411 | !x11_screen->wmspec_check_window && |
1412 | mode != NotifyGrab && |
1413 | mode != XINotifyPassiveGrab && |
1414 | mode != XINotifyPassiveUngrab && |
1415 | mode != NotifyUngrab) |
1416 | toplevel->has_pointer_focus = (focus_in) ? FALSE : TRUE; |
1417 | G_GNUC_FALLTHROUGH; |
1418 | |
1419 | case NotifyNonlinear: |
1420 | case NotifyNonlinearVirtual: |
1421 | if (mode != NotifyGrab && |
1422 | mode != XINotifyPassiveGrab && |
1423 | mode != XINotifyPassiveUngrab && |
1424 | mode != NotifyUngrab) |
1425 | toplevel->has_focus_window = (focus_in) ? TRUE : FALSE; |
1426 | /* We pretend that the focus moves to the grab |
1427 | * window, so we pay attention to NotifyGrab |
1428 | * NotifyUngrab, and ignore NotifyWhileGrabbed |
1429 | */ |
1430 | if (mode != NotifyWhileGrabbed) |
1431 | toplevel->has_focus = (focus_in) ? TRUE : FALSE; |
1432 | break; |
1433 | case NotifyPointer: |
1434 | /* The X server sends NotifyPointer/NotifyGrab, |
1435 | * but the pointer focus is ignored while a |
1436 | * grab is in effect |
1437 | */ |
1438 | if (!x11_screen->wmspec_check_window && |
1439 | mode != NotifyGrab && |
1440 | mode != XINotifyPassiveGrab && |
1441 | mode != XINotifyPassiveUngrab && |
1442 | mode != NotifyUngrab) |
1443 | toplevel->has_pointer_focus = (focus_in) ? TRUE : FALSE; |
1444 | break; |
1445 | case NotifyInferior: |
1446 | case NotifyPointerRoot: |
1447 | case NotifyDetailNone: |
1448 | default: |
1449 | break; |
1450 | } |
1451 | |
1452 | if (HAS_FOCUS (toplevel) != had_focus) |
1453 | { |
1454 | GdkEvent *event; |
1455 | |
1456 | event = gdk_focus_event_new (surface, device, focus_in); |
1457 | gdk_display_put_event (display: gdk_surface_get_display (surface), event); |
1458 | gdk_event_unref (event); |
1459 | } |
1460 | } |
1461 | |
1462 | static GdkEvent * |
1463 | gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator, |
1464 | GdkDisplay *display, |
1465 | const XEvent *xevent) |
1466 | { |
1467 | GdkX11DeviceManagerXI2 *device_manager; |
1468 | const XGenericEventCookie *cookie; |
1469 | GdkDevice *device, *source_device; |
1470 | GdkSurface *surface; |
1471 | GdkX11Surface *impl; |
1472 | int scale; |
1473 | XIEvent *ev; |
1474 | GdkEvent *event; |
1475 | |
1476 | event = NULL; |
1477 | |
1478 | device_manager = (GdkX11DeviceManagerXI2 *) translator; |
1479 | cookie = &xevent->xcookie; |
1480 | |
1481 | if (xevent->type != GenericEvent || |
1482 | cookie->extension != device_manager->opcode) |
1483 | return event; |
1484 | |
1485 | ev = (XIEvent *) cookie->data; |
1486 | |
1487 | if (!ev) |
1488 | return NULL; |
1489 | |
1490 | if (!get_event_surface (translator, ev, surface_p: &surface)) |
1491 | return NULL; |
1492 | |
1493 | if (surface && GDK_SURFACE_DESTROYED (surface)) |
1494 | return NULL; |
1495 | |
1496 | scale = 1; |
1497 | if (surface) |
1498 | { |
1499 | impl = GDK_X11_SURFACE (surface); |
1500 | scale = impl->surface_scale; |
1501 | } |
1502 | |
1503 | if (ev->evtype == XI_Motion || |
1504 | ev->evtype == XI_ButtonRelease) |
1505 | { |
1506 | if (_gdk_x11_moveresize_handle_event (event: xevent)) |
1507 | return NULL; |
1508 | } |
1509 | |
1510 | switch (ev->evtype) |
1511 | { |
1512 | case XI_HierarchyChanged: |
1513 | handle_hierarchy_changed (device_manager, |
1514 | ev: (XIHierarchyEvent *) ev); |
1515 | break; |
1516 | case XI_DeviceChanged: |
1517 | handle_device_changed (device_manager, |
1518 | ev: (XIDeviceChangedEvent *) ev); |
1519 | break; |
1520 | case XI_PropertyEvent: |
1521 | handle_property_change (device_manager, |
1522 | ev: (XIPropertyEvent *) ev); |
1523 | break; |
1524 | case XI_KeyPress: |
1525 | case XI_KeyRelease: |
1526 | { |
1527 | XIDeviceEvent *xev = (XIDeviceEvent *) ev; |
1528 | GdkKeymap *keymap = gdk_display_get_keymap (display); |
1529 | GdkModifierType consumed, state, orig_state; |
1530 | int layout, level; |
1531 | guint keyval; |
1532 | GdkTranslatedKey translated; |
1533 | GdkTranslatedKey no_lock; |
1534 | |
1535 | GDK_DISPLAY_NOTE (display, EVENTS, |
1536 | g_message ("key %s:\twindow %ld\n" |
1537 | "\tdevice:%u\n" |
1538 | "\tsource device:%u\n" |
1539 | "\tkey number: %u\n" , |
1540 | (ev->evtype == XI_KeyPress) ? "press" : "release" , |
1541 | xev->event, |
1542 | xev->deviceid, |
1543 | xev->sourceid, |
1544 | xev->detail)); |
1545 | |
1546 | state = _gdk_x11_device_xi2_translate_state (mods_state: &xev->mods, buttons_state: &xev->buttons, group_state: &xev->group); |
1547 | |
1548 | device = g_hash_table_lookup (hash_table: device_manager->id_table, |
1549 | GUINT_TO_POINTER (xev->deviceid)); |
1550 | |
1551 | source_device = g_hash_table_lookup (hash_table: device_manager->id_table, |
1552 | GUINT_TO_POINTER (xev->sourceid)); |
1553 | |
1554 | keyval = GDK_KEY_VoidSymbol; |
1555 | |
1556 | gdk_keymap_translate_keyboard_state (keymap, |
1557 | hardware_keycode: xev->detail, |
1558 | state, |
1559 | group: xev->group.effective, |
1560 | keyval: &keyval, |
1561 | effective_group: &layout, level: &level, consumed_modifiers: &consumed); |
1562 | orig_state = state; |
1563 | state &= ~consumed; |
1564 | _gdk_x11_keymap_add_virt_mods (keymap, modifiers: &state); |
1565 | state |= orig_state; |
1566 | |
1567 | translated.keyval = keyval; |
1568 | translated.consumed = consumed; |
1569 | translated.layout = layout; |
1570 | translated.level = level; |
1571 | |
1572 | if (orig_state & GDK_LOCK_MASK) |
1573 | { |
1574 | orig_state &= ~GDK_LOCK_MASK; |
1575 | |
1576 | gdk_keymap_translate_keyboard_state (keymap, |
1577 | hardware_keycode: xev->detail, |
1578 | state: orig_state, |
1579 | group: xev->group.effective, |
1580 | keyval: &keyval, |
1581 | effective_group: &layout, level: &level, consumed_modifiers: &consumed); |
1582 | |
1583 | no_lock.keyval = keyval; |
1584 | no_lock.consumed = consumed; |
1585 | no_lock.layout = layout; |
1586 | no_lock.level = level; |
1587 | } |
1588 | else |
1589 | { |
1590 | no_lock = translated; |
1591 | } |
1592 | event = gdk_key_event_new (type: xev->evtype == XI_KeyPress |
1593 | ? GDK_KEY_PRESS |
1594 | : GDK_KEY_RELEASE, |
1595 | surface, |
1596 | device, |
1597 | time: xev->time, |
1598 | keycode: xev->detail, |
1599 | modifiers: state, |
1600 | is_modifier: gdk_x11_keymap_key_is_modifier (keymap, keycode: xev->detail), |
1601 | translated: &translated, |
1602 | no_lock: &no_lock); |
1603 | |
1604 | if (ev->evtype == XI_KeyPress) |
1605 | set_user_time (event); |
1606 | |
1607 | /* FIXME: emulate autorepeat on key |
1608 | * release? XI2 seems attached to Xkb. |
1609 | */ |
1610 | } |
1611 | |
1612 | break; |
1613 | case XI_ButtonPress: |
1614 | case XI_ButtonRelease: |
1615 | { |
1616 | XIDeviceEvent *xev = (XIDeviceEvent *) ev; |
1617 | |
1618 | GDK_DISPLAY_NOTE (display, EVENTS, |
1619 | g_message ("button %s:\twindow %ld\n" |
1620 | "\tdevice:%u\n" |
1621 | "\tsource device:%u\n" |
1622 | "\tbutton number: %u\n" |
1623 | "\tx,y: %.2f %.2f" , |
1624 | (ev->evtype == XI_ButtonPress) ? "press" : "release" , |
1625 | xev->event, |
1626 | xev->deviceid, |
1627 | xev->sourceid, |
1628 | xev->detail, |
1629 | xev->event_x, xev->event_y)); |
1630 | |
1631 | #ifdef XINPUT_2_2 |
1632 | if (xev->flags & XIPointerEmulated) |
1633 | return FALSE; |
1634 | #endif |
1635 | |
1636 | if (ev->evtype == XI_ButtonRelease && |
1637 | (xev->detail >= 4 && xev->detail <= 7)) |
1638 | return FALSE; |
1639 | else if (ev->evtype == XI_ButtonPress && |
1640 | (xev->detail >= 4 && xev->detail <= 7)) |
1641 | { |
1642 | GdkScrollDirection direction; |
1643 | |
1644 | /* Button presses of button 4-7 are scroll events */ |
1645 | |
1646 | if (xev->detail == 4) |
1647 | direction = GDK_SCROLL_UP; |
1648 | else if (xev->detail == 5) |
1649 | direction = GDK_SCROLL_DOWN; |
1650 | else if (xev->detail == 6) |
1651 | direction = GDK_SCROLL_LEFT; |
1652 | else |
1653 | direction = GDK_SCROLL_RIGHT; |
1654 | |
1655 | device = g_hash_table_lookup (hash_table: device_manager->id_table, |
1656 | GUINT_TO_POINTER (xev->deviceid)); |
1657 | |
1658 | source_device = g_hash_table_lookup (hash_table: device_manager->id_table, |
1659 | GUINT_TO_POINTER (xev->sourceid)); |
1660 | |
1661 | event = gdk_scroll_event_new_discrete (surface, |
1662 | device: source_device, |
1663 | NULL, |
1664 | time: xev->time, |
1665 | state: _gdk_x11_device_xi2_translate_state (mods_state: &xev->mods, buttons_state: &xev->buttons, group_state: &xev->group), |
1666 | direction, |
1667 | FALSE); |
1668 | |
1669 | } |
1670 | else |
1671 | { |
1672 | double x, y; |
1673 | double *axes; |
1674 | |
1675 | device = g_hash_table_lookup (hash_table: device_manager->id_table, |
1676 | GUINT_TO_POINTER (xev->deviceid)); |
1677 | |
1678 | source_device = g_hash_table_lookup (hash_table: device_manager->id_table, |
1679 | GUINT_TO_POINTER (xev->sourceid)); |
1680 | |
1681 | axes = translate_axes (device, |
1682 | x: (double) xev->event_x / scale, |
1683 | y: (double) xev->event_y / scale, |
1684 | surface, |
1685 | valuators: &xev->valuators); |
1686 | |
1687 | x = (double) xev->event_x / scale; |
1688 | y = (double) xev->event_y / scale; |
1689 | |
1690 | event = gdk_button_event_new (type: ev->evtype == XI_ButtonPress |
1691 | ? GDK_BUTTON_PRESS |
1692 | : GDK_BUTTON_RELEASE, |
1693 | surface, |
1694 | device, |
1695 | tool: source_device->last_tool, |
1696 | time: xev->time, |
1697 | state: _gdk_x11_device_xi2_translate_state (mods_state: &xev->mods, buttons_state: &xev->buttons, group_state: &xev->group), |
1698 | button: xev->detail, |
1699 | x, y, |
1700 | axes); |
1701 | } |
1702 | |
1703 | if (ev->evtype == XI_ButtonPress) |
1704 | set_user_time (event); |
1705 | |
1706 | break; |
1707 | } |
1708 | |
1709 | case XI_Motion: |
1710 | { |
1711 | XIDeviceEvent *xev = (XIDeviceEvent *) ev; |
1712 | double delta_x, delta_y; |
1713 | |
1714 | double x, y; |
1715 | double *axes; |
1716 | |
1717 | #ifdef XINPUT_2_2 |
1718 | if (xev->flags & XIPointerEmulated) |
1719 | return FALSE; |
1720 | #endif |
1721 | |
1722 | source_device = g_hash_table_lookup (hash_table: device_manager->id_table, |
1723 | GUINT_TO_POINTER (xev->sourceid)); |
1724 | device = g_hash_table_lookup (hash_table: device_manager->id_table, |
1725 | GUINT_TO_POINTER (xev->deviceid)); |
1726 | |
1727 | /* When scrolling, X might send events twice here; once with both the |
1728 | * device and the source device set to the physical device, and once |
1729 | * with the device set to the logical device. |
1730 | * |
1731 | * Since we are only interested in the latter, and |
1732 | * scroll_valuators_changed() updates the valuator cache for the |
1733 | * source device, we need to explicitly ignore the first event in |
1734 | * order to get the correct delta for the second. |
1735 | */ |
1736 | if (gdk_x11_device_xi2_get_device_type (device: (GdkX11DeviceXI2 *) device) != GDK_X11_DEVICE_TYPE_PHYSICAL && |
1737 | scroll_valuators_changed (GDK_X11_DEVICE_XI2 (source_device), |
1738 | valuators: &xev->valuators, dx: &delta_x, dy: &delta_y)) |
1739 | { |
1740 | GdkModifierType state; |
1741 | |
1742 | GDK_DISPLAY_NOTE (display, EVENTS, |
1743 | g_message ("smooth scroll: \n\tdevice: %u\n\tsource device: %u\n\twindow %ld\n\tdeltas: %f %f" , |
1744 | xev->deviceid, xev->sourceid, |
1745 | xev->event, delta_x, delta_y)); |
1746 | |
1747 | state = _gdk_x11_device_xi2_translate_state (mods_state: &xev->mods, buttons_state: &xev->buttons, group_state: &xev->group); |
1748 | |
1749 | if (gdk_device_get_source (device: source_device) != GDK_SOURCE_TOUCHPAD && |
1750 | ((delta_x == 0.0 && ABS (delta_y) == 1.0) || |
1751 | (ABS (delta_x) == 1.0 && delta_y == 0.0))) |
1752 | { |
1753 | GdkScrollDirection direction; |
1754 | |
1755 | if (delta_x > 0) |
1756 | direction = GDK_SCROLL_RIGHT; |
1757 | else if (delta_x < 0) |
1758 | direction = GDK_SCROLL_LEFT; |
1759 | else if (delta_y > 0) |
1760 | direction = GDK_SCROLL_DOWN; |
1761 | else |
1762 | direction = GDK_SCROLL_UP; |
1763 | |
1764 | event = gdk_scroll_event_new_discrete (surface, |
1765 | device, |
1766 | NULL, |
1767 | time: xev->time, |
1768 | state, |
1769 | direction, |
1770 | FALSE); |
1771 | } |
1772 | else |
1773 | { |
1774 | event = gdk_scroll_event_new (surface, |
1775 | device, |
1776 | NULL, |
1777 | time: xev->time, |
1778 | state, |
1779 | delta_x, |
1780 | delta_y, |
1781 | is_stop: delta_x == 0.0 && delta_y == 0.0); |
1782 | } |
1783 | break; |
1784 | } |
1785 | |
1786 | axes = translate_axes (device, |
1787 | x: (double) xev->event_x / scale, |
1788 | y: (double) xev->event_y / scale, |
1789 | surface, |
1790 | valuators: &xev->valuators); |
1791 | |
1792 | x = (double) xev->event_x / scale; |
1793 | y = (double) xev->event_y / scale; |
1794 | |
1795 | event = gdk_motion_event_new (surface, |
1796 | device, |
1797 | tool: source_device->last_tool, |
1798 | time: xev->time, |
1799 | state: _gdk_x11_device_xi2_translate_state (mods_state: &xev->mods, buttons_state: &xev->buttons, group_state: &xev->group), |
1800 | x, y, |
1801 | axes); |
1802 | |
1803 | } |
1804 | break; |
1805 | |
1806 | #ifdef XINPUT_2_2 |
1807 | case XI_TouchBegin: |
1808 | case XI_TouchEnd: |
1809 | { |
1810 | XIDeviceEvent *xev = (XIDeviceEvent *) ev; |
1811 | GdkModifierType state; |
1812 | |
1813 | double x, y; |
1814 | double *axes; |
1815 | |
1816 | GDK_DISPLAY_NOTE (display, EVENTS, |
1817 | g_message ("touch %s:\twindow %ld\n\ttouch id: %u\n\tpointer emulating: %s" , |
1818 | ev->evtype == XI_TouchBegin ? "begin" : "end" , |
1819 | xev->event, |
1820 | xev->detail, |
1821 | xev->flags & XITouchEmulatingPointer ? "true" : "false" )); |
1822 | |
1823 | device = g_hash_table_lookup (hash_table: device_manager->id_table, |
1824 | GUINT_TO_POINTER (xev->deviceid)); |
1825 | |
1826 | source_device = g_hash_table_lookup (hash_table: device_manager->id_table, |
1827 | GUINT_TO_POINTER (xev->sourceid)); |
1828 | |
1829 | state = _gdk_x11_device_xi2_translate_state (mods_state: &xev->mods, buttons_state: &xev->buttons, group_state: &xev->group); |
1830 | if (ev->evtype == XI_TouchBegin) |
1831 | state |= GDK_BUTTON1_MASK; |
1832 | |
1833 | axes = translate_axes (device, |
1834 | x: (double) xev->event_x / scale, |
1835 | y: (double) xev->event_y / scale, |
1836 | surface, |
1837 | valuators: &xev->valuators); |
1838 | |
1839 | x = (double) xev->event_x / scale; |
1840 | y = (double) xev->event_y / scale; |
1841 | |
1842 | event = gdk_touch_event_new (type: ev->evtype == XI_TouchBegin |
1843 | ? GDK_TOUCH_BEGIN |
1844 | : GDK_TOUCH_END, |
1845 | GUINT_TO_POINTER (xev->detail), |
1846 | surface, |
1847 | device, |
1848 | time: xev->time, |
1849 | state, |
1850 | x, y, |
1851 | axes, |
1852 | emulating: xev->flags & XITouchEmulatingPointer); |
1853 | |
1854 | if (ev->evtype == XI_TouchBegin) |
1855 | set_user_time (event); |
1856 | } |
1857 | break; |
1858 | |
1859 | case XI_TouchUpdate: |
1860 | { |
1861 | XIDeviceEvent *xev = (XIDeviceEvent *) ev; |
1862 | GdkModifierType state; |
1863 | |
1864 | double x, y; |
1865 | double *axes; |
1866 | |
1867 | GDK_DISPLAY_NOTE (display, EVENTS, |
1868 | g_message ("touch update:\twindow %ld\n\ttouch id: %u\n\tpointer emulating: %s" , |
1869 | xev->event, |
1870 | xev->detail, |
1871 | xev->flags & XITouchEmulatingPointer ? "true" : "false" )); |
1872 | |
1873 | device = g_hash_table_lookup (hash_table: device_manager->id_table, |
1874 | GINT_TO_POINTER (xev->deviceid)); |
1875 | |
1876 | source_device = g_hash_table_lookup (hash_table: device_manager->id_table, |
1877 | GUINT_TO_POINTER (xev->sourceid)); |
1878 | |
1879 | state = _gdk_x11_device_xi2_translate_state (mods_state: &xev->mods, buttons_state: &xev->buttons, group_state: &xev->group); |
1880 | state |= GDK_BUTTON1_MASK; |
1881 | |
1882 | axes = translate_axes (device, |
1883 | x: (double) xev->event_x / scale, |
1884 | y: (double) xev->event_y / scale, |
1885 | surface, |
1886 | valuators: &xev->valuators); |
1887 | |
1888 | x = (double) xev->event_x / scale; |
1889 | y = (double) xev->event_y / scale; |
1890 | |
1891 | event = gdk_touch_event_new (type: GDK_TOUCH_UPDATE, |
1892 | GUINT_TO_POINTER (xev->detail), |
1893 | surface, |
1894 | device, |
1895 | time: xev->time, |
1896 | state, |
1897 | x, y, |
1898 | axes, |
1899 | emulating: xev->flags & XITouchEmulatingPointer); |
1900 | } |
1901 | break; |
1902 | #endif /* XINPUT_2_2 */ |
1903 | |
1904 | #ifdef XINPUT_2_4 |
1905 | case XI_GesturePinchBegin: |
1906 | case XI_GesturePinchUpdate: |
1907 | case XI_GesturePinchEnd: |
1908 | { |
1909 | XIGesturePinchEvent *xev = (XIGesturePinchEvent *) ev; |
1910 | GdkModifierType state; |
1911 | GdkTouchpadGesturePhase phase; |
1912 | double x, y; |
1913 | |
1914 | #ifdef G_ENABLE_DEBUG |
1915 | const char *event_name = "" ; |
1916 | switch (xev->evtype) |
1917 | { |
1918 | case XI_GesturePinchBegin: |
1919 | event_name = "begin" ; |
1920 | break; |
1921 | case XI_GesturePinchUpdate: |
1922 | event_name = "update" ; |
1923 | break; |
1924 | case XI_GesturePinchEnd: |
1925 | event_name = "end" ; |
1926 | break; |
1927 | default: |
1928 | break; |
1929 | } |
1930 | #endif |
1931 | |
1932 | GDK_NOTE (EVENTS, |
1933 | g_message ("pinch gesture %s:\twindow %ld\n\tfinger_count: %u%s" , |
1934 | event_name, |
1935 | xev->event, |
1936 | xev->detail, |
1937 | xev->flags & XIGesturePinchEventCancelled ? "\n\tcancelled" : "" )); |
1938 | |
1939 | device = g_hash_table_lookup (device_manager->id_table, |
1940 | GINT_TO_POINTER (xev->deviceid)); |
1941 | |
1942 | state = _gdk_x11_device_xi2_translate_state (&xev->mods, NULL, &xev->group); |
1943 | phase = _gdk_x11_device_xi2_gesture_type_to_phase (xev->evtype, xev->flags); |
1944 | |
1945 | x = (double) xev->event_x / scale; |
1946 | y = (double) xev->event_y / scale; |
1947 | |
1948 | event = gdk_touchpad_event_new_pinch (surface, |
1949 | NULL, /* FIXME make up sequences */ |
1950 | device, |
1951 | xev->time, |
1952 | state, |
1953 | phase, |
1954 | x, y, |
1955 | xev->detail, |
1956 | xev->delta_x, |
1957 | xev->delta_y, |
1958 | xev->scale, |
1959 | xev->delta_angle * G_PI / 180); |
1960 | |
1961 | if (ev->evtype == XI_GesturePinchBegin) |
1962 | set_user_time (event); |
1963 | } |
1964 | break; |
1965 | |
1966 | case XI_GestureSwipeBegin: |
1967 | case XI_GestureSwipeUpdate: |
1968 | case XI_GestureSwipeEnd: |
1969 | { |
1970 | XIGestureSwipeEvent *xev = (XIGestureSwipeEvent *) ev; |
1971 | GdkModifierType state; |
1972 | GdkTouchpadGesturePhase phase; |
1973 | double x, y; |
1974 | |
1975 | #ifdef G_ENABLE_DEBUG |
1976 | const char *event_name = "" ; |
1977 | switch (xev->evtype) |
1978 | { |
1979 | case XI_GestureSwipeBegin: |
1980 | event_name = "begin" ; |
1981 | break; |
1982 | case XI_GestureSwipeUpdate: |
1983 | event_name = "update" ; |
1984 | break; |
1985 | case XI_GestureSwipeEnd: |
1986 | event_name = "end" ; |
1987 | break; |
1988 | default: |
1989 | break; |
1990 | } |
1991 | #endif |
1992 | |
1993 | GDK_NOTE (EVENTS, |
1994 | g_message ("swipe gesture %s:\twindow %ld\n\tfinger_count: %u%s" , |
1995 | event_name, |
1996 | xev->event, |
1997 | xev->detail, |
1998 | xev->flags & XIGestureSwipeEventCancelled ? "\n\tcancelled" : "" )); |
1999 | |
2000 | device = g_hash_table_lookup (device_manager->id_table, |
2001 | GINT_TO_POINTER (xev->deviceid)); |
2002 | |
2003 | state = _gdk_x11_device_xi2_translate_state (&xev->mods, NULL, &xev->group); |
2004 | phase = _gdk_x11_device_xi2_gesture_type_to_phase (xev->evtype, xev->flags); |
2005 | |
2006 | x = (double) xev->event_x / scale; |
2007 | y = (double) xev->event_y / scale; |
2008 | |
2009 | event = gdk_touchpad_event_new_swipe (surface, |
2010 | NULL, /* FIXME make up sequences */ |
2011 | device, |
2012 | xev->time, |
2013 | state, |
2014 | phase, |
2015 | x, y, |
2016 | xev->detail, |
2017 | xev->delta_x, |
2018 | xev->delta_y); |
2019 | |
2020 | if (ev->evtype == XI_GestureSwipeBegin) |
2021 | set_user_time (event); |
2022 | } |
2023 | break; |
2024 | #endif /* XINPUT_2_4 */ |
2025 | |
2026 | case XI_Enter: |
2027 | case XI_Leave: |
2028 | { |
2029 | XIEnterEvent *xev = (XIEnterEvent *) ev; |
2030 | GdkModifierType state; |
2031 | |
2032 | GDK_DISPLAY_NOTE (display, EVENTS, |
2033 | g_message ("%s notify:\twindow %ld\n\tsubwindow:%ld\n" |
2034 | "\tdevice: %u\n\tsource device: %u\n" |
2035 | "\tnotify type: %u\n\tcrossing mode: %u" , |
2036 | (ev->evtype == XI_Enter) ? "enter" : "leave" , |
2037 | xev->event, xev->child, |
2038 | xev->deviceid, xev->sourceid, |
2039 | xev->detail, xev->mode)); |
2040 | |
2041 | device = g_hash_table_lookup (hash_table: device_manager->id_table, |
2042 | GINT_TO_POINTER (xev->deviceid)); |
2043 | |
2044 | source_device = g_hash_table_lookup (hash_table: device_manager->id_table, |
2045 | GUINT_TO_POINTER (xev->sourceid)); |
2046 | |
2047 | state = _gdk_x11_device_xi2_translate_state (mods_state: &xev->mods, buttons_state: &xev->buttons, group_state: &xev->group); |
2048 | |
2049 | /* Ignore normal crossing events while there is an implicit grab. |
2050 | * We will receive a crossing event with one of the other details if |
2051 | * the implicit grab were finished (eg. releasing the button outside |
2052 | * the window triggers a XINotifyUngrab leave). |
2053 | */ |
2054 | if (xev->mode == XINotifyNormal && |
2055 | (state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK | |
2056 | GDK_BUTTON4_MASK | GDK_BUTTON5_MASK))) |
2057 | break; |
2058 | |
2059 | if (ev->evtype == XI_Enter && |
2060 | xev->detail != XINotifyInferior && xev->mode != XINotifyPassiveUngrab && |
2061 | GDK_IS_TOPLEVEL (ptr: surface)) |
2062 | { |
2063 | if (gdk_x11_device_xi2_get_device_type (device: (GdkX11DeviceXI2 *) device) != GDK_X11_DEVICE_TYPE_LOGICAL) |
2064 | _gdk_device_xi2_reset_scroll_valuators (GDK_X11_DEVICE_XI2 (source_device)); |
2065 | else |
2066 | { |
2067 | GList *physical_devices, *l; |
2068 | |
2069 | physical_devices = gdk_device_list_physical_devices (device: source_device); |
2070 | |
2071 | for (l = physical_devices; l; l = l->next) |
2072 | _gdk_device_xi2_reset_scroll_valuators (GDK_X11_DEVICE_XI2 (l->data)); |
2073 | |
2074 | g_list_free (list: physical_devices); |
2075 | } |
2076 | } |
2077 | |
2078 | event = gdk_crossing_event_new (type: ev->evtype == XI_Enter |
2079 | ? GDK_ENTER_NOTIFY |
2080 | : GDK_LEAVE_NOTIFY, |
2081 | surface, |
2082 | device, |
2083 | time: xev->time, |
2084 | state, |
2085 | x: (double) xev->event_x / scale, |
2086 | y: (double) xev->event_y / scale, |
2087 | mode: translate_crossing_mode (mode: xev->mode), |
2088 | notify: translate_notify_type (detail: xev->detail)); |
2089 | } |
2090 | break; |
2091 | case XI_FocusIn: |
2092 | case XI_FocusOut: |
2093 | { |
2094 | if (surface) |
2095 | { |
2096 | XIEnterEvent *xev = (XIEnterEvent *) ev; |
2097 | |
2098 | device = g_hash_table_lookup (hash_table: device_manager->id_table, |
2099 | GINT_TO_POINTER (xev->deviceid)); |
2100 | |
2101 | source_device = g_hash_table_lookup (hash_table: device_manager->id_table, |
2102 | GUINT_TO_POINTER (xev->sourceid)); |
2103 | |
2104 | _gdk_device_manager_xi2_handle_focus (surface, |
2105 | original: xev->event, |
2106 | device, |
2107 | source_device, |
2108 | focus_in: (ev->evtype == XI_FocusIn) ? TRUE : FALSE, |
2109 | detail: xev->detail, |
2110 | mode: xev->mode); |
2111 | } |
2112 | } |
2113 | break; |
2114 | default: |
2115 | break; |
2116 | } |
2117 | |
2118 | return event; |
2119 | } |
2120 | |
2121 | static GdkEventMask |
2122 | gdk_x11_device_manager_xi2_get_handled_events (GdkEventTranslator *translator) |
2123 | { |
2124 | return (GDK_KEY_PRESS_MASK | |
2125 | GDK_KEY_RELEASE_MASK | |
2126 | GDK_BUTTON_PRESS_MASK | |
2127 | GDK_BUTTON_RELEASE_MASK | |
2128 | GDK_SCROLL_MASK | |
2129 | GDK_ENTER_NOTIFY_MASK | |
2130 | GDK_LEAVE_NOTIFY_MASK | |
2131 | GDK_POINTER_MOTION_MASK | |
2132 | GDK_BUTTON1_MOTION_MASK | |
2133 | GDK_BUTTON2_MOTION_MASK | |
2134 | GDK_BUTTON3_MOTION_MASK | |
2135 | GDK_BUTTON_MOTION_MASK | |
2136 | GDK_FOCUS_CHANGE_MASK | |
2137 | GDK_TOUCH_MASK | |
2138 | GDK_TOUCHPAD_GESTURE_MASK); |
2139 | } |
2140 | |
2141 | static void |
2142 | gdk_x11_device_manager_xi2_select_surface_events (GdkEventTranslator *translator, |
2143 | Window window, |
2144 | GdkEventMask evmask) |
2145 | { |
2146 | XIEventMask event_mask; |
2147 | |
2148 | event_mask.deviceid = XIAllMasterDevices; |
2149 | event_mask.mask = _gdk_x11_device_xi2_translate_event_mask (GDK_X11_DEVICE_MANAGER_XI2 (translator), |
2150 | event_mask: evmask, |
2151 | len: &event_mask.mask_len); |
2152 | |
2153 | _gdk_x11_device_manager_xi2_select_events (GDK_X11_DEVICE_MANAGER_XI2 (translator), xwindow: window, event_mask: &event_mask); |
2154 | g_free (mem: event_mask.mask); |
2155 | } |
2156 | |
2157 | static GdkSurface * |
2158 | gdk_x11_device_manager_xi2_get_surface (GdkEventTranslator *translator, |
2159 | const XEvent *xevent) |
2160 | { |
2161 | GdkX11DeviceManagerXI2 *device_manager; |
2162 | XIEvent *ev; |
2163 | GdkSurface *surface = NULL; |
2164 | |
2165 | device_manager = (GdkX11DeviceManagerXI2 *) translator; |
2166 | |
2167 | if (xevent->type != GenericEvent || |
2168 | xevent->xcookie.extension != device_manager->opcode) |
2169 | return NULL; |
2170 | |
2171 | ev = (XIEvent *) xevent->xcookie.data; |
2172 | if (!ev) |
2173 | return NULL; |
2174 | |
2175 | get_event_surface (translator, ev, surface_p: &surface); |
2176 | return surface; |
2177 | } |
2178 | |
2179 | GdkDevice * |
2180 | _gdk_x11_device_manager_xi2_lookup (GdkX11DeviceManagerXI2 *device_manager_xi2, |
2181 | int device_id) |
2182 | { |
2183 | return g_hash_table_lookup (hash_table: device_manager_xi2->id_table, |
2184 | GINT_TO_POINTER (device_id)); |
2185 | } |
2186 | |