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