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