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