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 #include "gdkdevice-xi2-private.h"
23 
24 #include "gdkintl.h"
25 #include "gdkasync.h"
26 #include "gdkprivate-x11.h"
27 #include "gdkdisplay-x11.h"
28 
29 #include "gdk-private.h"
30 
31 #include <stdlib.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xutil.h>
34 #include <X11/extensions/XInput2.h>
35 
36 #include <math.h>
37 
38 typedef struct _ScrollValuator ScrollValuator;
39 
40 struct _ScrollValuator
41 {
42   guint n_valuator       : 4;
43   guint direction        : 4;
44   guint last_value_valid : 1;
45   double last_value;
46   double increment;
47 };
48 
49 struct _GdkX11DeviceXI2
50 {
51   GdkDevice parent_instance;
52 
53   int device_id;
54   GArray *scroll_valuators;
55   double *last_axes;
56   GdkX11DeviceType device_type;
57 };
58 
59 struct _GdkX11DeviceXI2Class
60 {
61   GdkDeviceClass parent_class;
62 };
63 
64 G_DEFINE_TYPE (GdkX11DeviceXI2, gdk_x11_device_xi2, GDK_TYPE_DEVICE)
65 
66 
67 static void gdk_x11_device_xi2_finalize     (GObject      *object);
68 static void gdk_x11_device_xi2_get_property (GObject      *object,
69                                              guint         prop_id,
70                                              GValue       *value,
71                                              GParamSpec   *pspec);
72 static void gdk_x11_device_xi2_set_property (GObject      *object,
73                                              guint         prop_id,
74                                              const GValue *value,
75                                              GParamSpec   *pspec);
76 
77 static void gdk_x11_device_xi2_set_surface_cursor (GdkDevice *device,
78                                                   GdkSurface *surface,
79                                                   GdkCursor *cursor);
80 
81 static GdkGrabStatus gdk_x11_device_xi2_grab   (GdkDevice     *device,
82                                                 GdkSurface     *surface,
83                                                 gboolean       owner_events,
84                                                 GdkEventMask   event_mask,
85                                                 GdkSurface     *confine_to,
86                                                 GdkCursor     *cursor,
87                                                 guint32        time_);
88 static void          gdk_x11_device_xi2_ungrab (GdkDevice     *device,
89                                                 guint32        time_);
90 
91 static GdkSurface * gdk_x11_device_xi2_surface_at_position (GdkDevice       *device,
92                                                             double          *win_x,
93                                                             double          *win_y,
94                                                             GdkModifierType *mask);
95 
96 
97 enum {
98   PROP_0,
99   PROP_DEVICE_ID
100 };
101 
102 static void
gdk_x11_device_xi2_class_init(GdkX11DeviceXI2Class * klass)103 gdk_x11_device_xi2_class_init (GdkX11DeviceXI2Class *klass)
104 {
105   GObjectClass *object_class = G_OBJECT_CLASS (klass);
106   GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
107 
108   object_class->finalize = gdk_x11_device_xi2_finalize;
109   object_class->get_property = gdk_x11_device_xi2_get_property;
110   object_class->set_property = gdk_x11_device_xi2_set_property;
111 
112   device_class->set_surface_cursor = gdk_x11_device_xi2_set_surface_cursor;
113   device_class->grab = gdk_x11_device_xi2_grab;
114   device_class->ungrab = gdk_x11_device_xi2_ungrab;
115   device_class->surface_at_position = gdk_x11_device_xi2_surface_at_position;
116 
117   g_object_class_install_property (object_class,
118                                    PROP_DEVICE_ID,
119                                    g_param_spec_int ("device-id",
120                                                      P_("Device ID"),
121                                                      P_("Device identifier"),
122                                                      0, G_MAXINT, 0,
123                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
124                                                      G_PARAM_STATIC_STRINGS));
125 }
126 
127 static void
gdk_x11_device_xi2_init(GdkX11DeviceXI2 * device)128 gdk_x11_device_xi2_init (GdkX11DeviceXI2 *device)
129 {
130   device->scroll_valuators = g_array_new (FALSE, FALSE, sizeof (ScrollValuator));
131 }
132 
133 static void
gdk_x11_device_xi2_finalize(GObject * object)134 gdk_x11_device_xi2_finalize (GObject *object)
135 {
136   GdkX11DeviceXI2 *device = GDK_X11_DEVICE_XI2 (object);
137 
138   g_array_free (device->scroll_valuators, TRUE);
139   g_free (device->last_axes);
140 
141   G_OBJECT_CLASS (gdk_x11_device_xi2_parent_class)->finalize (object);
142 }
143 
144 static void
gdk_x11_device_xi2_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)145 gdk_x11_device_xi2_get_property (GObject    *object,
146                                  guint       prop_id,
147                                  GValue     *value,
148                                  GParamSpec *pspec)
149 {
150   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (object);
151 
152   switch (prop_id)
153     {
154     case PROP_DEVICE_ID:
155       g_value_set_int (value, device_xi2->device_id);
156       break;
157     default:
158       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
159       break;
160     }
161 }
162 
163 static void
gdk_x11_device_xi2_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)164 gdk_x11_device_xi2_set_property (GObject      *object,
165                                  guint         prop_id,
166                                  const 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       device_xi2->device_id = g_value_get_int (value);
175       break;
176     default:
177       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
178       break;
179     }
180 }
181 
182 static void
gdk_x11_device_xi2_set_surface_cursor(GdkDevice * device,GdkSurface * surface,GdkCursor * cursor)183 gdk_x11_device_xi2_set_surface_cursor (GdkDevice *device,
184                                       GdkSurface *surface,
185                                       GdkCursor *cursor)
186 {
187   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
188 
189   /* Non-logical devices don't have a cursor */
190   if (device_xi2->device_type != GDK_X11_DEVICE_TYPE_LOGICAL)
191     return;
192 
193   if (cursor)
194     XIDefineCursor (GDK_SURFACE_XDISPLAY (surface),
195                     device_xi2->device_id,
196                     GDK_SURFACE_XID (surface),
197                     gdk_x11_display_get_xcursor (GDK_SURFACE_DISPLAY (surface), cursor));
198   else
199     XIUndefineCursor (GDK_SURFACE_XDISPLAY (surface),
200                       device_xi2->device_id,
201                       GDK_SURFACE_XID (surface));
202 }
203 
204 void
gdk_x11_device_xi2_query_state(GdkDevice * device,GdkSurface * surface,double * win_x,double * win_y,GdkModifierType * mask)205 gdk_x11_device_xi2_query_state (GdkDevice        *device,
206                                 GdkSurface        *surface,
207                                 double           *win_x,
208                                 double           *win_y,
209                                 GdkModifierType  *mask)
210 {
211   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
212   GdkDisplay *display;
213   GdkX11Screen *default_screen;
214   Window xroot_window, xchild_window, xwindow;
215   double xroot_x, xroot_y, xwin_x, xwin_y;
216   XIButtonState button_state;
217   XIModifierState mod_state;
218   XIGroupState group_state;
219   int scale;
220 
221   display = gdk_device_get_display (device);
222   default_screen = GDK_X11_DISPLAY (display)->screen;
223   if (surface == NULL)
224     {
225       xwindow = GDK_DISPLAY_XROOTWIN (display);
226       scale = default_screen->surface_scale;
227     }
228   else
229     {
230       xwindow = GDK_SURFACE_XID (surface);
231       scale = GDK_X11_SURFACE (surface)->surface_scale;
232     }
233 
234   if (!GDK_X11_DISPLAY (display)->trusted_client ||
235       !XIQueryPointer (GDK_DISPLAY_XDISPLAY (display),
236                        device_xi2->device_id,
237                        xwindow,
238                        &xroot_window,
239                        &xchild_window,
240                        &xroot_x, &xroot_y,
241                        &xwin_x, &xwin_y,
242                        &button_state,
243                        &mod_state,
244                        &group_state))
245     {
246       XSetWindowAttributes attributes;
247       Display *xdisplay;
248       Window w;
249 
250       /* FIXME: untrusted clients not multidevice-safe */
251       xdisplay = GDK_SCREEN_XDISPLAY (default_screen);
252       xwindow = GDK_SCREEN_XROOTWIN (default_screen);
253 
254       w = XCreateWindow (xdisplay, xwindow, 0, 0, 1, 1, 0,
255                          CopyFromParent, InputOnly, CopyFromParent,
256                          0, &attributes);
257       XIQueryPointer (xdisplay, device_xi2->device_id,
258                       w,
259                       &xroot_window,
260                       &xchild_window,
261                       &xroot_x, &xroot_y,
262                       &xwin_x, &xwin_y,
263                       &button_state,
264                       &mod_state,
265                       &group_state);
266       XDestroyWindow (xdisplay, w);
267     }
268 
269   if (win_x)
270     *win_x = xwin_x / scale;
271 
272   if (win_y)
273     *win_y = xwin_y / scale;
274 
275   if (mask)
276     *mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state, &group_state);
277 
278   free (button_state.mask);
279 }
280 
281 static GdkGrabStatus
gdk_x11_device_xi2_grab(GdkDevice * device,GdkSurface * surface,gboolean owner_events,GdkEventMask event_mask,GdkSurface * confine_to,GdkCursor * cursor,guint32 time_)282 gdk_x11_device_xi2_grab (GdkDevice    *device,
283                          GdkSurface    *surface,
284                          gboolean      owner_events,
285                          GdkEventMask  event_mask,
286                          GdkSurface    *confine_to,
287                          GdkCursor    *cursor,
288                          guint32       time_)
289 {
290   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
291   GdkX11DeviceManagerXI2 *device_manager_xi2;
292   GdkDisplay *display;
293   XIEventMask mask;
294   Window xwindow;
295   Cursor xcursor;
296   int status;
297 
298   display = gdk_device_get_display (device);
299   device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (GDK_X11_DISPLAY (display)->device_manager);
300 
301   /* FIXME: confine_to is actually unused */
302 
303   xwindow = GDK_SURFACE_XID (surface);
304 
305   if (!cursor)
306     xcursor = None;
307   else
308     {
309       xcursor = gdk_x11_display_get_xcursor (display, cursor);
310     }
311 
312   mask.deviceid = device_xi2->device_id;
313   mask.mask = _gdk_x11_device_xi2_translate_event_mask (device_manager_xi2,
314                                                         event_mask,
315                                                         &mask.mask_len);
316 
317 #ifdef G_ENABLE_DEBUG
318   if (GDK_DISPLAY_DEBUG_CHECK (display, NOGRABS))
319     status = GrabSuccess;
320   else
321 #endif
322     status = XIGrabDevice (GDK_DISPLAY_XDISPLAY (display),
323                            device_xi2->device_id,
324                            xwindow,
325                            time_,
326                            xcursor,
327                            GrabModeAsync, GrabModeAsync,
328                            owner_events,
329                            &mask);
330 
331   g_free (mask.mask);
332 
333   _gdk_x11_display_update_grab_info (display, device, status);
334 
335   return _gdk_x11_convert_grab_status (status);
336 }
337 
338 static void
gdk_x11_device_xi2_ungrab(GdkDevice * device,guint32 time_)339 gdk_x11_device_xi2_ungrab (GdkDevice *device,
340                            guint32    time_)
341 {
342   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
343   GdkDisplay *display;
344   gulong serial;
345 
346   display = gdk_device_get_display (device);
347   serial = NextRequest (GDK_DISPLAY_XDISPLAY (display));
348 
349   XIUngrabDevice (GDK_DISPLAY_XDISPLAY (display), device_xi2->device_id, time_);
350 
351   _gdk_x11_display_update_grab_info_ungrab (display, device, time_, serial);
352 }
353 
354 static GdkSurface *
gdk_x11_device_xi2_surface_at_position(GdkDevice * device,double * win_x,double * win_y,GdkModifierType * mask)355 gdk_x11_device_xi2_surface_at_position (GdkDevice       *device,
356                                         double          *win_x,
357                                         double          *win_y,
358                                         GdkModifierType *mask)
359 {
360   GdkX11Surface *impl;
361   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
362   GdkDisplay *display;
363   GdkX11Screen *screen;
364   Display *xdisplay;
365   GdkSurface *surface;
366   Window xwindow, root, child, last = None;
367   double xroot_x, xroot_y, xwin_x, xwin_y;
368   XIButtonState button_state = { 0 };
369   XIModifierState mod_state;
370   XIGroupState group_state;
371   Bool retval;
372 
373   display = gdk_device_get_display (device);
374   screen = GDK_X11_DISPLAY (display)->screen;
375 
376   gdk_x11_display_error_trap_push (display);
377 
378   /* This function really only works if the mouse pointer is held still
379    * during its operation. If it moves from one leaf window to another
380    * than we'll end up with inaccurate values for win_x, win_y
381    * and the result.
382    */
383   gdk_x11_display_grab (display);
384 
385   xdisplay = GDK_SCREEN_XDISPLAY (screen);
386   xwindow = GDK_SCREEN_XROOTWIN (screen);
387 
388   if (G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
389     {
390       XIQueryPointer (xdisplay,
391                       device_xi2->device_id,
392                       xwindow,
393                       &root, &child,
394                       &xroot_x, &xroot_y,
395                       &xwin_x, &xwin_y,
396                       &button_state,
397                       &mod_state,
398                       &group_state);
399 
400       if (root == xwindow)
401         xwindow = child;
402       else
403         xwindow = root;
404     }
405   else
406     {
407       int width, height;
408       GList *toplevels, *list;
409       Window pointer_window;
410 
411       /* FIXME: untrusted clients case not multidevice-safe */
412       pointer_window = None;
413 
414       toplevels = gdk_x11_display_get_toplevel_windows (display);
415       for (list = toplevels; list != NULL; list = list->next)
416         {
417           surface = GDK_SURFACE (list->data);
418           xwindow = GDK_SURFACE_XID (surface);
419 
420           /* Free previous button mask, if any */
421           g_free (button_state.mask);
422 
423           retval = XIQueryPointer (xdisplay,
424                                    device_xi2->device_id,
425                                    xwindow,
426                                    &root, &child,
427                                    &xroot_x, &xroot_y,
428                                    &xwin_x, &xwin_y,
429                                    &button_state,
430                                    &mod_state,
431                                    &group_state);
432           if (!retval)
433             continue;
434 
435           if (child != None)
436             {
437               pointer_window = child;
438               break;
439             }
440           gdk_surface_get_geometry (surface, NULL, NULL, &width, &height);
441           if (xwin_x >= 0 && xwin_y >= 0 && xwin_x < width && xwin_y < height)
442             {
443               /* A childless toplevel, or below another window? */
444               XSetWindowAttributes attributes;
445               Window w;
446 
447               free (button_state.mask);
448 
449               w = XCreateWindow (xdisplay, xwindow, (int)xwin_x, (int)xwin_y, 1, 1, 0,
450                                  CopyFromParent, InputOnly, CopyFromParent,
451                                  0, &attributes);
452               XMapWindow (xdisplay, w);
453               XIQueryPointer (xdisplay,
454                               device_xi2->device_id,
455                               xwindow,
456                               &root, &child,
457                               &xroot_x, &xroot_y,
458                               &xwin_x, &xwin_y,
459                               &button_state,
460                               &mod_state,
461                               &group_state);
462               XDestroyWindow (xdisplay, w);
463               if (child == w)
464                 {
465                   pointer_window = xwindow;
466                   break;
467                 }
468             }
469 
470           if (pointer_window != None)
471             break;
472         }
473 
474       xwindow = pointer_window;
475     }
476 
477   while (xwindow)
478     {
479       last = xwindow;
480       free (button_state.mask);
481 
482       retval = XIQueryPointer (xdisplay,
483                                device_xi2->device_id,
484                                xwindow,
485                                &root, &xwindow,
486                                &xroot_x, &xroot_y,
487                                &xwin_x, &xwin_y,
488                                &button_state,
489                                &mod_state,
490                                &group_state);
491       if (!retval)
492         break;
493 
494       if (last != root &&
495           (surface = gdk_x11_surface_lookup_for_display (display, last)) != NULL)
496         {
497           xwindow = last;
498           break;
499         }
500     }
501 
502   gdk_x11_display_ungrab (display);
503 
504   if (gdk_x11_display_error_trap_pop (display) == 0)
505     {
506       surface = gdk_x11_surface_lookup_for_display (display, last);
507       impl = NULL;
508       if (surface)
509         impl = GDK_X11_SURFACE (surface);
510 
511       if (mask)
512         *mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state, &group_state);
513 
514       free (button_state.mask);
515     }
516   else
517     {
518       surface = NULL;
519 
520       if (mask)
521         *mask = 0;
522     }
523 
524   if (win_x)
525     *win_x = (surface) ? (xwin_x / impl->surface_scale) : -1;
526 
527   if (win_y)
528     *win_y = (surface) ? (xwin_y / impl->surface_scale) : -1;
529 
530 
531   return surface;
532 }
533 
534 guchar *
_gdk_x11_device_xi2_translate_event_mask(GdkX11DeviceManagerXI2 * device_manager_xi2,GdkEventMask event_mask,int * len)535 _gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *device_manager_xi2,
536                                           GdkEventMask            event_mask,
537                                           int                    *len)
538 {
539   guchar *mask;
540   int minor;
541 
542   g_object_get (device_manager_xi2, "minor", &minor, NULL);
543 
544   *len = XIMaskLen (XI_LASTEVENT);
545   mask = g_new0 (guchar, *len);
546 
547   if (event_mask & GDK_POINTER_MOTION_MASK)
548     XISetMask (mask, XI_Motion);
549 
550   if (event_mask & GDK_BUTTON_MOTION_MASK ||
551       event_mask & GDK_BUTTON1_MOTION_MASK ||
552       event_mask & GDK_BUTTON2_MOTION_MASK ||
553       event_mask & GDK_BUTTON3_MOTION_MASK)
554     {
555       XISetMask (mask, XI_ButtonPress);
556       XISetMask (mask, XI_ButtonRelease);
557       XISetMask (mask, XI_Motion);
558     }
559 
560   if (event_mask & GDK_SCROLL_MASK)
561     {
562       XISetMask (mask, XI_ButtonPress);
563       XISetMask (mask, XI_ButtonRelease);
564     }
565 
566   if (event_mask & GDK_BUTTON_PRESS_MASK)
567     XISetMask (mask, XI_ButtonPress);
568 
569   if (event_mask & GDK_BUTTON_RELEASE_MASK)
570     XISetMask (mask, XI_ButtonRelease);
571 
572   if (event_mask & GDK_KEY_PRESS_MASK)
573     XISetMask (mask, XI_KeyPress);
574 
575   if (event_mask & GDK_KEY_RELEASE_MASK)
576     XISetMask (mask, XI_KeyRelease);
577 
578   if (event_mask & GDK_ENTER_NOTIFY_MASK)
579     XISetMask (mask, XI_Enter);
580 
581   if (event_mask & GDK_LEAVE_NOTIFY_MASK)
582     XISetMask (mask, XI_Leave);
583 
584   if (event_mask & GDK_FOCUS_CHANGE_MASK)
585     {
586       XISetMask (mask, XI_FocusIn);
587       XISetMask (mask, XI_FocusOut);
588     }
589 
590 #ifdef XINPUT_2_2
591   /* XInput 2.2 includes multitouch support */
592   if (minor >= 2 &&
593       event_mask & GDK_TOUCH_MASK)
594     {
595       XISetMask (mask, XI_TouchBegin);
596       XISetMask (mask, XI_TouchUpdate);
597       XISetMask (mask, XI_TouchEnd);
598     }
599 #endif /* XINPUT_2_2 */
600 
601   return mask;
602 }
603 
604 guint
_gdk_x11_device_xi2_translate_state(XIModifierState * mods_state,XIButtonState * buttons_state,XIGroupState * group_state)605 _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
606                                      XIButtonState   *buttons_state,
607                                      XIGroupState    *group_state)
608 {
609   guint state = 0;
610 
611   if (mods_state)
612     state = mods_state->effective;
613 
614   if (buttons_state)
615     {
616       int len, i;
617 
618       /* We're only interested in the first 3 buttons */
619       len = MIN (3, buttons_state->mask_len * 8);
620 
621       for (i = 1; i <= len; i++)
622         {
623           if (!XIMaskIsSet (buttons_state->mask, i))
624             continue;
625 
626           switch (i)
627             {
628             case 1:
629               state |= GDK_BUTTON1_MASK;
630               break;
631             case 2:
632               state |= GDK_BUTTON2_MASK;
633               break;
634             case 3:
635               state |= GDK_BUTTON3_MASK;
636               break;
637             default:
638               break;
639             }
640         }
641     }
642 
643   if (group_state)
644     state |= (group_state->effective) << 13;
645 
646   return state;
647 }
648 
649 void
_gdk_x11_device_xi2_add_scroll_valuator(GdkX11DeviceXI2 * device,guint n_valuator,GdkScrollDirection direction,double increment)650 _gdk_x11_device_xi2_add_scroll_valuator (GdkX11DeviceXI2    *device,
651                                          guint               n_valuator,
652                                          GdkScrollDirection  direction,
653                                          double              increment)
654 {
655   ScrollValuator scroll;
656 
657   g_return_if_fail (GDK_IS_X11_DEVICE_XI2 (device));
658   g_return_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)));
659 
660   scroll.n_valuator = n_valuator;
661   scroll.direction = direction;
662   scroll.last_value_valid = FALSE;
663   scroll.increment = increment;
664 
665   g_array_append_val (device->scroll_valuators, scroll);
666 }
667 
668 gboolean
_gdk_x11_device_xi2_get_scroll_delta(GdkX11DeviceXI2 * device,guint n_valuator,double valuator_value,GdkScrollDirection * direction_ret,double * delta_ret)669 _gdk_x11_device_xi2_get_scroll_delta (GdkX11DeviceXI2    *device,
670                                       guint               n_valuator,
671                                       double              valuator_value,
672                                       GdkScrollDirection *direction_ret,
673                                       double             *delta_ret)
674 {
675   guint i;
676 
677   g_return_val_if_fail (GDK_IS_X11_DEVICE_XI2 (device), FALSE);
678   g_return_val_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)), FALSE);
679 
680   for (i = 0; i < device->scroll_valuators->len; i++)
681     {
682       ScrollValuator *scroll;
683 
684       scroll = &g_array_index (device->scroll_valuators, ScrollValuator, i);
685 
686       if (scroll->n_valuator == n_valuator)
687         {
688           if (direction_ret)
689             *direction_ret = scroll->direction;
690 
691           if (delta_ret)
692             *delta_ret = 0;
693 
694           if (scroll->last_value_valid)
695             {
696               if (delta_ret)
697                 *delta_ret = (valuator_value - scroll->last_value) / scroll->increment;
698 
699               scroll->last_value = valuator_value;
700             }
701           else
702             {
703               scroll->last_value = valuator_value;
704               scroll->last_value_valid = TRUE;
705             }
706 
707           return TRUE;
708         }
709     }
710 
711   return FALSE;
712 }
713 
714 void
_gdk_device_xi2_reset_scroll_valuators(GdkX11DeviceXI2 * device)715 _gdk_device_xi2_reset_scroll_valuators (GdkX11DeviceXI2 *device)
716 {
717   guint i;
718 
719   for (i = 0; i < device->scroll_valuators->len; i++)
720     {
721       ScrollValuator *scroll;
722 
723       scroll = &g_array_index (device->scroll_valuators, ScrollValuator, i);
724       scroll->last_value_valid = FALSE;
725     }
726 }
727 
728 void
_gdk_device_xi2_unset_scroll_valuators(GdkX11DeviceXI2 * device)729 _gdk_device_xi2_unset_scroll_valuators (GdkX11DeviceXI2 *device)
730 {
731   if (device->scroll_valuators->len > 0)
732     g_array_remove_range (device->scroll_valuators, 0,
733                           device->scroll_valuators->len);
734 }
735 
736 int
_gdk_x11_device_xi2_get_id(GdkX11DeviceXI2 * device)737 _gdk_x11_device_xi2_get_id (GdkX11DeviceXI2 *device)
738 {
739   g_return_val_if_fail (GDK_IS_X11_DEVICE_XI2 (device), 0);
740 
741   return device->device_id;
742 }
743 
744 double
gdk_x11_device_xi2_get_last_axis_value(GdkX11DeviceXI2 * device,int n_axis)745 gdk_x11_device_xi2_get_last_axis_value (GdkX11DeviceXI2 *device,
746                                         int              n_axis)
747 {
748   if (n_axis >= gdk_device_get_n_axes (GDK_DEVICE (device)))
749     return 0;
750 
751   if (!device->last_axes)
752     return 0;
753 
754   return device->last_axes[n_axis];
755 }
756 
757 void
gdk_x11_device_xi2_store_axes(GdkX11DeviceXI2 * device,double * axes,int n_axes)758 gdk_x11_device_xi2_store_axes (GdkX11DeviceXI2 *device,
759                                double          *axes,
760                                int              n_axes)
761 {
762   g_free (device->last_axes);
763 
764   if (axes && n_axes)
765     device->last_axes = g_memdup2 (axes, sizeof (double) * n_axes);
766   else
767     device->last_axes = NULL;
768 }
769 
770 GdkX11DeviceType
gdk_x11_device_xi2_get_device_type(GdkX11DeviceXI2 * device)771 gdk_x11_device_xi2_get_device_type (GdkX11DeviceXI2 *device)
772 {
773   return device->device_type;
774 }
775 
776 void
gdk_x11_device_xi2_set_device_type(GdkX11DeviceXI2 * device,GdkX11DeviceType type)777 gdk_x11_device_xi2_set_device_type (GdkX11DeviceXI2  *device,
778                                     GdkX11DeviceType  type)
779 {
780   device->device_type = type;
781 }
782