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 "gdkx11device-xi2.h"
21 #include "gdkdeviceprivate.h"
22
23 #include "gdkintl.h"
24 #include "gdkasync.h"
25 #include "gdkprivate-x11.h"
26
27 #include <stdlib.h>
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30 #include <X11/extensions/XInput2.h>
31
32 #include <math.h>
33
34 /* for the use of round() */
35 #include "fallback-c89.c"
36
37 typedef struct _ScrollValuator ScrollValuator;
38
39 struct _ScrollValuator
40 {
41 guint n_valuator : 4;
42 guint direction : 4;
43 guint last_value_valid : 1;
44 gdouble last_value;
45 gdouble increment;
46 };
47
48 struct _GdkX11DeviceXI2
49 {
50 GdkDevice parent_instance;
51
52 gint device_id;
53 GArray *scroll_valuators;
54 gdouble *last_axes;
55 };
56
57 struct _GdkX11DeviceXI2Class
58 {
59 GdkDeviceClass parent_class;
60 };
61
62 G_DEFINE_TYPE (GdkX11DeviceXI2, gdk_x11_device_xi2, GDK_TYPE_DEVICE)
63
64 static void gdk_x11_device_xi2_finalize (GObject *object);
65 static void gdk_x11_device_xi2_get_property (GObject *object,
66 guint prop_id,
67 GValue *value,
68 GParamSpec *pspec);
69 static void gdk_x11_device_xi2_set_property (GObject *object,
70 guint prop_id,
71 const GValue *value,
72 GParamSpec *pspec);
73
74 static void gdk_x11_device_xi2_get_state (GdkDevice *device,
75 GdkWindow *window,
76 gdouble *axes,
77 GdkModifierType *mask);
78 static void gdk_x11_device_xi2_set_window_cursor (GdkDevice *device,
79 GdkWindow *window,
80 GdkCursor *cursor);
81 static void gdk_x11_device_xi2_warp (GdkDevice *device,
82 GdkScreen *screen,
83 gdouble x,
84 gdouble y);
85 static void gdk_x11_device_xi2_query_state (GdkDevice *device,
86 GdkWindow *window,
87 GdkWindow **root_window,
88 GdkWindow **child_window,
89 gdouble *root_x,
90 gdouble *root_y,
91 gdouble *win_x,
92 gdouble *win_y,
93 GdkModifierType *mask);
94
95 static GdkGrabStatus gdk_x11_device_xi2_grab (GdkDevice *device,
96 GdkWindow *window,
97 gboolean owner_events,
98 GdkEventMask event_mask,
99 GdkWindow *confine_to,
100 GdkCursor *cursor,
101 guint32 time_);
102 static void gdk_x11_device_xi2_ungrab (GdkDevice *device,
103 guint32 time_);
104
105 static GdkWindow * gdk_x11_device_xi2_window_at_position (GdkDevice *device,
106 gdouble *win_x,
107 gdouble *win_y,
108 GdkModifierType *mask,
109 gboolean get_toplevel);
110 static void gdk_x11_device_xi2_select_window_events (GdkDevice *device,
111 GdkWindow *window,
112 GdkEventMask event_mask);
113
114
115 enum {
116 PROP_0,
117 PROP_DEVICE_ID
118 };
119
120 static void
gdk_x11_device_xi2_class_init(GdkX11DeviceXI2Class * klass)121 gdk_x11_device_xi2_class_init (GdkX11DeviceXI2Class *klass)
122 {
123 GObjectClass *object_class = G_OBJECT_CLASS (klass);
124 GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
125
126 object_class->finalize = gdk_x11_device_xi2_finalize;
127 object_class->get_property = gdk_x11_device_xi2_get_property;
128 object_class->set_property = gdk_x11_device_xi2_set_property;
129
130 device_class->get_state = gdk_x11_device_xi2_get_state;
131 device_class->set_window_cursor = gdk_x11_device_xi2_set_window_cursor;
132 device_class->warp = gdk_x11_device_xi2_warp;
133 device_class->query_state = gdk_x11_device_xi2_query_state;
134 device_class->grab = gdk_x11_device_xi2_grab;
135 device_class->ungrab = gdk_x11_device_xi2_ungrab;
136 device_class->window_at_position = gdk_x11_device_xi2_window_at_position;
137 device_class->select_window_events = gdk_x11_device_xi2_select_window_events;
138
139 g_object_class_install_property (object_class,
140 PROP_DEVICE_ID,
141 g_param_spec_int ("device-id",
142 P_("Device ID"),
143 P_("Device identifier"),
144 0, G_MAXINT, 0,
145 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
146 }
147
148 static void
gdk_x11_device_xi2_init(GdkX11DeviceXI2 * device)149 gdk_x11_device_xi2_init (GdkX11DeviceXI2 *device)
150 {
151 device->scroll_valuators = g_array_new (FALSE, FALSE, sizeof (ScrollValuator));
152 }
153
154 static void
gdk_x11_device_xi2_finalize(GObject * object)155 gdk_x11_device_xi2_finalize (GObject *object)
156 {
157 GdkX11DeviceXI2 *device = GDK_X11_DEVICE_XI2 (object);
158
159 g_array_free (device->scroll_valuators, TRUE);
160 g_free (device->last_axes);
161
162 G_OBJECT_CLASS (gdk_x11_device_xi2_parent_class)->finalize (object);
163 }
164
165 static void
gdk_x11_device_xi2_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)166 gdk_x11_device_xi2_get_property (GObject *object,
167 guint prop_id,
168 GValue *value,
169 GParamSpec *pspec)
170 {
171 GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (object);
172
173 switch (prop_id)
174 {
175 case PROP_DEVICE_ID:
176 g_value_set_int (value, device_xi2->device_id);
177 break;
178 default:
179 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
180 break;
181 }
182 }
183
184 static void
gdk_x11_device_xi2_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)185 gdk_x11_device_xi2_set_property (GObject *object,
186 guint prop_id,
187 const GValue *value,
188 GParamSpec *pspec)
189 {
190 GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (object);
191
192 switch (prop_id)
193 {
194 case PROP_DEVICE_ID:
195 device_xi2->device_id = g_value_get_int (value);
196 break;
197 default:
198 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
199 break;
200 }
201 }
202
203 static void
gdk_x11_device_xi2_get_state(GdkDevice * device,GdkWindow * window,gdouble * axes,GdkModifierType * mask)204 gdk_x11_device_xi2_get_state (GdkDevice *device,
205 GdkWindow *window,
206 gdouble *axes,
207 GdkModifierType *mask)
208 {
209 GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
210
211 if (axes)
212 {
213 GdkDisplay *display;
214 XIDeviceInfo *info;
215 gint i, j, ndevices;
216
217 display = gdk_device_get_display (device);
218
219 gdk_x11_display_error_trap_push (display);
220 info = XIQueryDevice (GDK_DISPLAY_XDISPLAY (display),
221 device_xi2->device_id, &ndevices);
222 gdk_x11_display_error_trap_pop_ignored (display);
223
224 for (i = 0, j = 0; info && i < info->num_classes; i++)
225 {
226 XIAnyClassInfo *class_info = info->classes[i];
227 GdkAxisUse use;
228 gdouble value;
229
230 if (class_info->type != XIValuatorClass)
231 continue;
232
233 value = ((XIValuatorClassInfo *) class_info)->value;
234 use = gdk_device_get_axis_use (device, j);
235
236 switch (use)
237 {
238 case GDK_AXIS_X:
239 case GDK_AXIS_Y:
240 case GDK_AXIS_IGNORE:
241 if (gdk_device_get_mode (device) == GDK_MODE_WINDOW)
242 _gdk_device_translate_window_coord (device, window, j, value, &axes[j]);
243 else
244 {
245 gint root_x, root_y;
246
247 /* FIXME: Maybe root coords chaching should happen here */
248 gdk_window_get_origin (window, &root_x, &root_y);
249 _gdk_device_translate_screen_coord (device, window,
250 root_x, root_y,
251 j, value,
252 &axes[j]);
253 }
254 break;
255 default:
256 _gdk_device_translate_axis (device, j, value, &axes[j]);
257 break;
258 }
259
260 j++;
261 }
262
263 if (info)
264 XIFreeDeviceInfo (info);
265 }
266
267 if (mask)
268 gdk_x11_device_xi2_query_state (device, window,
269 NULL, NULL,
270 NULL, NULL,
271 NULL, NULL,
272 mask);
273 }
274
275 static void
gdk_x11_device_xi2_set_window_cursor(GdkDevice * device,GdkWindow * window,GdkCursor * cursor)276 gdk_x11_device_xi2_set_window_cursor (GdkDevice *device,
277 GdkWindow *window,
278 GdkCursor *cursor)
279 {
280 GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
281
282 /* Non-master devices don't have a cursor */
283 if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER)
284 return;
285
286 if (cursor)
287 XIDefineCursor (GDK_WINDOW_XDISPLAY (window),
288 device_xi2->device_id,
289 GDK_WINDOW_XID (window),
290 gdk_x11_cursor_get_xcursor (cursor));
291 else
292 XIUndefineCursor (GDK_WINDOW_XDISPLAY (window),
293 device_xi2->device_id,
294 GDK_WINDOW_XID (window));
295 }
296
297 static void
gdk_x11_device_xi2_warp(GdkDevice * device,GdkScreen * screen,gdouble x,gdouble y)298 gdk_x11_device_xi2_warp (GdkDevice *device,
299 GdkScreen *screen,
300 gdouble x,
301 gdouble y)
302 {
303 GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
304 Window dest;
305
306 dest = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
307
308 XIWarpPointer (GDK_SCREEN_XDISPLAY (screen),
309 device_xi2->device_id,
310 None, dest,
311 0, 0, 0, 0,
312 round (x * GDK_X11_SCREEN(screen)->window_scale),
313 round (y * GDK_X11_SCREEN(screen)->window_scale));
314 }
315
316 static void
gdk_x11_device_xi2_query_state(GdkDevice * device,GdkWindow * window,GdkWindow ** root_window,GdkWindow ** child_window,gdouble * root_x,gdouble * root_y,gdouble * win_x,gdouble * win_y,GdkModifierType * mask)317 gdk_x11_device_xi2_query_state (GdkDevice *device,
318 GdkWindow *window,
319 GdkWindow **root_window,
320 GdkWindow **child_window,
321 gdouble *root_x,
322 gdouble *root_y,
323 gdouble *win_x,
324 gdouble *win_y,
325 GdkModifierType *mask)
326 {
327 GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
328 GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
329 GdkDisplay *display;
330 GdkScreen *default_screen;
331 Window xroot_window, xchild_window;
332 gdouble xroot_x, xroot_y, xwin_x, xwin_y;
333 XIButtonState button_state;
334 XIModifierState mod_state;
335 XIGroupState group_state;
336
337 display = gdk_window_get_display (window);
338 default_screen = gdk_display_get_default_screen (display);
339
340 if (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_SLAVE)
341 {
342 GdkDevice *master = gdk_device_get_associated_device (device);
343
344 if (master)
345 _gdk_device_query_state (master, window, root_window, child_window,
346 root_x, root_y, win_x, win_y, mask);
347 return;
348 }
349
350 if (!GDK_X11_DISPLAY (display)->trusted_client ||
351 !XIQueryPointer (GDK_WINDOW_XDISPLAY (window),
352 device_xi2->device_id,
353 GDK_WINDOW_XID (window),
354 &xroot_window,
355 &xchild_window,
356 &xroot_x, &xroot_y,
357 &xwin_x, &xwin_y,
358 &button_state,
359 &mod_state,
360 &group_state))
361 {
362 XSetWindowAttributes attributes;
363 Display *xdisplay;
364 Window xwindow, w;
365
366 /* FIXME: untrusted clients not multidevice-safe */
367 xdisplay = GDK_SCREEN_XDISPLAY (default_screen);
368 xwindow = GDK_SCREEN_XROOTWIN (default_screen);
369
370 w = XCreateWindow (xdisplay, xwindow, 0, 0, 1, 1, 0,
371 CopyFromParent, InputOnly, CopyFromParent,
372 0, &attributes);
373 XIQueryPointer (xdisplay, device_xi2->device_id,
374 w,
375 &xroot_window,
376 &xchild_window,
377 &xroot_x, &xroot_y,
378 &xwin_x, &xwin_y,
379 &button_state,
380 &mod_state,
381 &group_state);
382 XDestroyWindow (xdisplay, w);
383 }
384
385 if (root_window)
386 *root_window = gdk_x11_window_lookup_for_display (display, xroot_window);
387
388 if (child_window)
389 *child_window = gdk_x11_window_lookup_for_display (display, xchild_window);
390
391 if (root_x)
392 *root_x = xroot_x / impl->window_scale;
393
394 if (root_y)
395 *root_y = xroot_y / impl->window_scale;
396
397 if (win_x)
398 *win_x = xwin_x / impl->window_scale;
399
400 if (win_y)
401 *win_y = xwin_y / impl->window_scale;
402
403 if (mask)
404 *mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state, &group_state);
405
406 free (button_state.mask);
407 }
408
409 static GdkGrabStatus
gdk_x11_device_xi2_grab(GdkDevice * device,GdkWindow * window,gboolean owner_events,GdkEventMask event_mask,GdkWindow * confine_to,GdkCursor * cursor,guint32 time_)410 gdk_x11_device_xi2_grab (GdkDevice *device,
411 GdkWindow *window,
412 gboolean owner_events,
413 GdkEventMask event_mask,
414 GdkWindow *confine_to,
415 GdkCursor *cursor,
416 guint32 time_)
417 {
418 GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
419 GdkX11DeviceManagerXI2 *device_manager_xi2;
420 GdkDisplay *display;
421 XIEventMask mask;
422 Window xwindow;
423 Cursor xcursor;
424 gint status;
425
426 display = gdk_device_get_display (device);
427 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
428 device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (gdk_display_get_device_manager (display));
429 G_GNUC_END_IGNORE_DEPRECATIONS;
430
431 /* FIXME: confine_to is actually unused */
432
433 xwindow = GDK_WINDOW_XID (window);
434
435 if (!cursor)
436 xcursor = None;
437 else
438 {
439 _gdk_x11_cursor_update_theme (cursor);
440 xcursor = gdk_x11_cursor_get_xcursor (cursor);
441 }
442
443 mask.deviceid = device_xi2->device_id;
444 mask.mask = _gdk_x11_device_xi2_translate_event_mask (device_manager_xi2,
445 event_mask,
446 &mask.mask_len);
447
448 #ifdef G_ENABLE_DEBUG
449 if (GDK_DEBUG_CHECK (NOGRABS))
450 status = GrabSuccess;
451 else
452 #endif
453 status = XIGrabDevice (GDK_DISPLAY_XDISPLAY (display),
454 device_xi2->device_id,
455 xwindow,
456 time_,
457 xcursor,
458 GrabModeAsync, GrabModeAsync,
459 owner_events,
460 &mask);
461
462 g_free (mask.mask);
463
464 _gdk_x11_display_update_grab_info (display, device, status);
465
466 return _gdk_x11_convert_grab_status (status);
467 }
468
469 static void
gdk_x11_device_xi2_ungrab(GdkDevice * device,guint32 time_)470 gdk_x11_device_xi2_ungrab (GdkDevice *device,
471 guint32 time_)
472 {
473 GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
474 GdkDisplay *display;
475 gulong serial;
476
477 display = gdk_device_get_display (device);
478 serial = NextRequest (GDK_DISPLAY_XDISPLAY (display));
479
480 XIUngrabDevice (GDK_DISPLAY_XDISPLAY (display), device_xi2->device_id, time_);
481
482 _gdk_x11_display_update_grab_info_ungrab (display, device, time_, serial);
483 }
484
485 static GdkWindow *
gdk_x11_device_xi2_window_at_position(GdkDevice * device,gdouble * win_x,gdouble * win_y,GdkModifierType * mask,gboolean get_toplevel)486 gdk_x11_device_xi2_window_at_position (GdkDevice *device,
487 gdouble *win_x,
488 gdouble *win_y,
489 GdkModifierType *mask,
490 gboolean get_toplevel)
491 {
492 GdkWindowImplX11 *impl;
493 GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
494 GdkDisplay *display;
495 GdkScreen *screen;
496 Display *xdisplay;
497 GdkWindow *window;
498 Window xwindow, root, child, last = None;
499 gdouble xroot_x, xroot_y, xwin_x, xwin_y;
500 XIButtonState button_state = { 0 };
501 XIModifierState mod_state;
502 XIGroupState group_state;
503 Bool retval;
504
505 display = gdk_device_get_display (device);
506 screen = gdk_display_get_default_screen (display);
507
508 gdk_x11_display_error_trap_push (display);
509
510 /* This function really only works if the mouse pointer is held still
511 * during its operation. If it moves from one leaf window to another
512 * than we'll end up with inaccurate values for win_x, win_y
513 * and the result.
514 */
515 gdk_x11_display_grab (display);
516
517 xdisplay = GDK_SCREEN_XDISPLAY (screen);
518 xwindow = GDK_SCREEN_XROOTWIN (screen);
519
520 if (G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
521 {
522 XIQueryPointer (xdisplay,
523 device_xi2->device_id,
524 xwindow,
525 &root, &child,
526 &xroot_x, &xroot_y,
527 &xwin_x, &xwin_y,
528 &button_state,
529 &mod_state,
530 &group_state);
531
532 if (root == xwindow)
533 xwindow = child;
534 else
535 xwindow = root;
536 }
537 else
538 {
539 gint width, height;
540 GList *toplevels, *list;
541 Window pointer_window;
542
543 /* FIXME: untrusted clients case not multidevice-safe */
544 pointer_window = None;
545
546 screen = gdk_display_get_default_screen (display);
547 toplevels = gdk_screen_get_toplevel_windows (screen);
548 for (list = toplevels; list != NULL; list = list->next)
549 {
550 window = GDK_WINDOW (list->data);
551 xwindow = GDK_WINDOW_XID (window);
552
553 /* Free previous button mask, if any */
554 g_free (button_state.mask);
555
556 retval = XIQueryPointer (xdisplay,
557 device_xi2->device_id,
558 xwindow,
559 &root, &child,
560 &xroot_x, &xroot_y,
561 &xwin_x, &xwin_y,
562 &button_state,
563 &mod_state,
564 &group_state);
565 if (!retval)
566 continue;
567
568 if (child != None)
569 {
570 pointer_window = child;
571 break;
572 }
573 gdk_window_get_geometry (window, NULL, NULL, &width, &height);
574 if (xwin_x >= 0 && xwin_y >= 0 && xwin_x < width && xwin_y < height)
575 {
576 /* A childless toplevel, or below another window? */
577 XSetWindowAttributes attributes;
578 Window w;
579
580 free (button_state.mask);
581
582 w = XCreateWindow (xdisplay, xwindow, (int)xwin_x, (int)xwin_y, 1, 1, 0,
583 CopyFromParent, InputOnly, CopyFromParent,
584 0, &attributes);
585 XMapWindow (xdisplay, w);
586 XIQueryPointer (xdisplay,
587 device_xi2->device_id,
588 xwindow,
589 &root, &child,
590 &xroot_x, &xroot_y,
591 &xwin_x, &xwin_y,
592 &button_state,
593 &mod_state,
594 &group_state);
595 XDestroyWindow (xdisplay, w);
596 if (child == w)
597 {
598 pointer_window = xwindow;
599 break;
600 }
601 }
602
603 g_list_free (toplevels);
604 if (pointer_window != None)
605 break;
606 }
607
608 xwindow = pointer_window;
609 }
610
611 while (xwindow)
612 {
613 last = xwindow;
614 free (button_state.mask);
615
616 retval = XIQueryPointer (xdisplay,
617 device_xi2->device_id,
618 xwindow,
619 &root, &xwindow,
620 &xroot_x, &xroot_y,
621 &xwin_x, &xwin_y,
622 &button_state,
623 &mod_state,
624 &group_state);
625 if (!retval)
626 break;
627
628 if (get_toplevel && last != root &&
629 (window = gdk_x11_window_lookup_for_display (display, last)) != NULL &&
630 GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
631 {
632 xwindow = last;
633 break;
634 }
635 }
636
637 gdk_x11_display_ungrab (display);
638
639 if (gdk_x11_display_error_trap_pop (display) == 0)
640 {
641 window = gdk_x11_window_lookup_for_display (display, last);
642 impl = NULL;
643 if (window)
644 impl = GDK_WINDOW_IMPL_X11 (window->impl);
645
646 if (mask)
647 *mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state, &group_state);
648
649 free (button_state.mask);
650 }
651 else
652 {
653 window = NULL;
654
655 if (mask)
656 *mask = 0;
657 }
658
659 if (win_x)
660 *win_x = (window) ? (xwin_x / impl->window_scale) : -1;
661
662 if (win_y)
663 *win_y = (window) ? (xwin_y / impl->window_scale) : -1;
664
665
666 return window;
667 }
668
669 static void
gdk_x11_device_xi2_select_window_events(GdkDevice * device,GdkWindow * window,GdkEventMask event_mask)670 gdk_x11_device_xi2_select_window_events (GdkDevice *device,
671 GdkWindow *window,
672 GdkEventMask event_mask)
673 {
674 GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
675 GdkX11DeviceManagerXI2 *device_manager_xi2;
676 GdkDisplay *display;
677 XIEventMask evmask;
678
679 display = gdk_device_get_display (device);
680 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
681 device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (gdk_display_get_device_manager (display));
682 G_GNUC_END_IGNORE_DEPRECATIONS;
683
684 evmask.deviceid = device_xi2->device_id;
685 evmask.mask = _gdk_x11_device_xi2_translate_event_mask (device_manager_xi2,
686 event_mask,
687 &evmask.mask_len);
688
689 XISelectEvents (GDK_WINDOW_XDISPLAY (window),
690 GDK_WINDOW_XID (window),
691 &evmask, 1);
692
693 g_free (evmask.mask);
694 }
695
696 guchar *
_gdk_x11_device_xi2_translate_event_mask(GdkX11DeviceManagerXI2 * device_manager_xi2,GdkEventMask event_mask,gint * len)697 _gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *device_manager_xi2,
698 GdkEventMask event_mask,
699 gint *len)
700 {
701 guchar *mask;
702 gint minor;
703
704 g_object_get (device_manager_xi2, "minor", &minor, NULL);
705
706 *len = XIMaskLen (XI_LASTEVENT);
707 mask = g_new0 (guchar, *len);
708
709 if (event_mask & GDK_POINTER_MOTION_MASK ||
710 event_mask & GDK_POINTER_MOTION_HINT_MASK)
711 XISetMask (mask, XI_Motion);
712
713 if (event_mask & GDK_BUTTON_MOTION_MASK ||
714 event_mask & GDK_BUTTON1_MOTION_MASK ||
715 event_mask & GDK_BUTTON2_MOTION_MASK ||
716 event_mask & GDK_BUTTON3_MOTION_MASK)
717 {
718 XISetMask (mask, XI_ButtonPress);
719 XISetMask (mask, XI_ButtonRelease);
720 XISetMask (mask, XI_Motion);
721 }
722
723 if (event_mask & GDK_SCROLL_MASK)
724 {
725 XISetMask (mask, XI_ButtonPress);
726 XISetMask (mask, XI_ButtonRelease);
727 }
728
729 if (event_mask & GDK_BUTTON_PRESS_MASK)
730 XISetMask (mask, XI_ButtonPress);
731
732 if (event_mask & GDK_BUTTON_RELEASE_MASK)
733 XISetMask (mask, XI_ButtonRelease);
734
735 if (event_mask & GDK_KEY_PRESS_MASK)
736 XISetMask (mask, XI_KeyPress);
737
738 if (event_mask & GDK_KEY_RELEASE_MASK)
739 XISetMask (mask, XI_KeyRelease);
740
741 if (event_mask & GDK_ENTER_NOTIFY_MASK)
742 XISetMask (mask, XI_Enter);
743
744 if (event_mask & GDK_LEAVE_NOTIFY_MASK)
745 XISetMask (mask, XI_Leave);
746
747 if (event_mask & GDK_FOCUS_CHANGE_MASK)
748 {
749 XISetMask (mask, XI_FocusIn);
750 XISetMask (mask, XI_FocusOut);
751 }
752
753 #ifdef XINPUT_2_2
754 /* XInput 2.2 includes multitouch support */
755 if (minor >= 2 &&
756 event_mask & GDK_TOUCH_MASK)
757 {
758 XISetMask (mask, XI_TouchBegin);
759 XISetMask (mask, XI_TouchUpdate);
760 XISetMask (mask, XI_TouchEnd);
761 }
762 #endif /* XINPUT_2_2 */
763
764 #ifdef XINPUT_2_4
765 /* XInput 2.4 includes multitouch support */
766 if (minor >= 4 &&
767 event_mask & GDK_TOUCHPAD_GESTURE_MASK)
768 {
769 XISetMask (mask, XI_GesturePinchBegin);
770 XISetMask (mask, XI_GesturePinchUpdate);
771 XISetMask (mask, XI_GesturePinchEnd);
772 XISetMask (mask, XI_GestureSwipeBegin);
773 XISetMask (mask, XI_GestureSwipeUpdate);
774 XISetMask (mask, XI_GestureSwipeEnd);
775 }
776 #endif
777
778 return mask;
779 }
780
781 guint
_gdk_x11_device_xi2_translate_state(XIModifierState * mods_state,XIButtonState * buttons_state,XIGroupState * group_state)782 _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
783 XIButtonState *buttons_state,
784 XIGroupState *group_state)
785 {
786 guint state = 0;
787
788 if (mods_state)
789 state = mods_state->effective;
790
791 if (buttons_state)
792 {
793 gint len, i;
794
795 /* We're only interested in the first 3 buttons */
796 len = MIN (3, buttons_state->mask_len * 8);
797
798 for (i = 1; i <= len; i++)
799 {
800 if (!XIMaskIsSet (buttons_state->mask, i))
801 continue;
802
803 switch (i)
804 {
805 case 1:
806 state |= GDK_BUTTON1_MASK;
807 break;
808 case 2:
809 state |= GDK_BUTTON2_MASK;
810 break;
811 case 3:
812 state |= GDK_BUTTON3_MASK;
813 break;
814 default:
815 break;
816 }
817 }
818 }
819
820 if (group_state)
821 state |= (group_state->effective) << 13;
822
823 return state;
824 }
825
826 #ifdef XINPUT_2_4
827 guint
_gdk_x11_device_xi2_gesture_type_to_phase(int evtype,int flags)828 _gdk_x11_device_xi2_gesture_type_to_phase (int evtype, int flags)
829 {
830 switch (evtype)
831 {
832 case XI_GesturePinchBegin:
833 case XI_GestureSwipeBegin:
834 return GDK_TOUCHPAD_GESTURE_PHASE_BEGIN;
835
836 case XI_GesturePinchUpdate:
837 case XI_GestureSwipeUpdate:
838 return GDK_TOUCHPAD_GESTURE_PHASE_UPDATE;
839
840 case XI_GesturePinchEnd:
841 if (flags & XIGesturePinchEventCancelled)
842 return GDK_TOUCHPAD_GESTURE_PHASE_CANCEL;
843 return GDK_TOUCHPAD_GESTURE_PHASE_END;
844
845 case XI_GestureSwipeEnd:
846 if (flags & XIGestureSwipeEventCancelled)
847 return GDK_TOUCHPAD_GESTURE_PHASE_CANCEL;
848 return GDK_TOUCHPAD_GESTURE_PHASE_END;
849 default:
850 g_assert_not_reached ();
851 return GDK_TOUCHPAD_GESTURE_PHASE_END;
852 }
853 }
854 #endif /* XINPUT_2_4 */
855
856 void
_gdk_x11_device_xi2_add_scroll_valuator(GdkX11DeviceXI2 * device,guint n_valuator,GdkScrollDirection direction,gdouble increment)857 _gdk_x11_device_xi2_add_scroll_valuator (GdkX11DeviceXI2 *device,
858 guint n_valuator,
859 GdkScrollDirection direction,
860 gdouble increment)
861 {
862 ScrollValuator scroll;
863
864 g_return_if_fail (GDK_IS_X11_DEVICE_XI2 (device));
865 g_return_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)));
866
867 scroll.n_valuator = n_valuator;
868 scroll.direction = direction;
869 scroll.last_value_valid = FALSE;
870 scroll.increment = increment;
871
872 g_array_append_val (device->scroll_valuators, scroll);
873 }
874
875 gboolean
_gdk_x11_device_xi2_get_scroll_delta(GdkX11DeviceXI2 * device,guint n_valuator,gdouble valuator_value,GdkScrollDirection * direction_ret,gdouble * delta_ret)876 _gdk_x11_device_xi2_get_scroll_delta (GdkX11DeviceXI2 *device,
877 guint n_valuator,
878 gdouble valuator_value,
879 GdkScrollDirection *direction_ret,
880 gdouble *delta_ret)
881 {
882 guint i;
883
884 g_return_val_if_fail (GDK_IS_X11_DEVICE_XI2 (device), FALSE);
885 g_return_val_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)), FALSE);
886
887 for (i = 0; i < device->scroll_valuators->len; i++)
888 {
889 ScrollValuator *scroll;
890
891 scroll = &g_array_index (device->scroll_valuators, ScrollValuator, i);
892
893 if (scroll->n_valuator == n_valuator)
894 {
895 if (direction_ret)
896 *direction_ret = scroll->direction;
897
898 if (delta_ret)
899 *delta_ret = 0;
900
901 if (scroll->last_value_valid)
902 {
903 if (delta_ret)
904 *delta_ret = (valuator_value - scroll->last_value) / scroll->increment;
905
906 scroll->last_value = valuator_value;
907 }
908 else
909 {
910 scroll->last_value = valuator_value;
911 scroll->last_value_valid = TRUE;
912 }
913
914 return TRUE;
915 }
916 }
917
918 return FALSE;
919 }
920
921 void
_gdk_device_xi2_reset_scroll_valuators(GdkX11DeviceXI2 * device)922 _gdk_device_xi2_reset_scroll_valuators (GdkX11DeviceXI2 *device)
923 {
924 guint i;
925
926 for (i = 0; i < device->scroll_valuators->len; i++)
927 {
928 ScrollValuator *scroll;
929
930 scroll = &g_array_index (device->scroll_valuators, ScrollValuator, i);
931 scroll->last_value_valid = FALSE;
932 }
933 }
934
935 void
_gdk_device_xi2_unset_scroll_valuators(GdkX11DeviceXI2 * device)936 _gdk_device_xi2_unset_scroll_valuators (GdkX11DeviceXI2 *device)
937 {
938 if (device->scroll_valuators->len > 0)
939 g_array_remove_range (device->scroll_valuators, 0,
940 device->scroll_valuators->len);
941 }
942
943 gint
_gdk_x11_device_xi2_get_id(GdkX11DeviceXI2 * device)944 _gdk_x11_device_xi2_get_id (GdkX11DeviceXI2 *device)
945 {
946 g_return_val_if_fail (GDK_IS_X11_DEVICE_XI2 (device), 0);
947
948 return device->device_id;
949 }
950
951 gdouble
gdk_x11_device_xi2_get_last_axis_value(GdkX11DeviceXI2 * device,gint n_axis)952 gdk_x11_device_xi2_get_last_axis_value (GdkX11DeviceXI2 *device,
953 gint n_axis)
954 {
955 if (n_axis >= gdk_device_get_n_axes (GDK_DEVICE (device)))
956 return 0;
957
958 if (!device->last_axes)
959 return 0;
960
961 return device->last_axes[n_axis];
962 }
963
964 void
gdk_x11_device_xi2_store_axes(GdkX11DeviceXI2 * device,gdouble * axes,gint n_axes)965 gdk_x11_device_xi2_store_axes (GdkX11DeviceXI2 *device,
966 gdouble *axes,
967 gint n_axes)
968 {
969 g_free (device->last_axes);
970
971 if (axes && n_axes)
972 device->last_axes = g_memdup (axes, sizeof (gdouble) * n_axes);
973 else
974 device->last_axes = NULL;
975 }
976