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 <math.h>
21 
22 #include "gdkdeviceprivate.h"
23 #include "gdkdevicetool.h"
24 #include "gdkdisplayprivate.h"
25 #include "gdkinternals.h"
26 #include "gdkintl.h"
27 #include "gdkkeysprivate.h"
28 
29 /**
30  * GdkDevice:
31  *
32  * The `GdkDevice` object represents an input device, such
33  * as a keyboard, a mouse, or a touchpad.
34  *
35  * See the [class@Gdk.Seat] documentation for more information
36  * about the various kinds of devices, and their relationships.
37  */
38 
39 typedef struct _GdkAxisInfo GdkAxisInfo;
40 
41 struct _GdkAxisInfo
42 {
43   GdkAxisUse use;
44   double min_axis;
45   double max_axis;
46   double min_value;
47   double max_value;
48   double resolution;
49 };
50 
51 enum {
52   CHANGED,
53   TOOL_CHANGED,
54   LAST_SIGNAL
55 };
56 
57 static guint signals [LAST_SIGNAL] = { 0 };
58 
59 
60 static void gdk_device_finalize     (GObject      *object);
61 static void gdk_device_dispose      (GObject      *object);
62 static void gdk_device_set_property (GObject      *object,
63                                      guint         prop_id,
64                                      const GValue *value,
65                                      GParamSpec   *pspec);
66 static void gdk_device_get_property (GObject      *object,
67                                      guint         prop_id,
68                                      GValue       *value,
69                                      GParamSpec   *pspec);
70 
71 
72 G_DEFINE_ABSTRACT_TYPE (GdkDevice, gdk_device, G_TYPE_OBJECT)
73 
74 enum {
75   PROP_0,
76   PROP_DISPLAY,
77   PROP_NAME,
78   PROP_SOURCE,
79   PROP_HAS_CURSOR,
80   PROP_N_AXES,
81   PROP_VENDOR_ID,
82   PROP_PRODUCT_ID,
83   PROP_SEAT,
84   PROP_NUM_TOUCHES,
85   PROP_TOOL,
86   PROP_DIRECTION,
87   PROP_HAS_BIDI_LAYOUTS,
88   PROP_CAPS_LOCK_STATE,
89   PROP_NUM_LOCK_STATE,
90   PROP_SCROLL_LOCK_STATE,
91   PROP_MODIFIER_STATE,
92   LAST_PROP
93 };
94 
95 static GParamSpec *device_props[LAST_PROP] = { NULL, };
96 
97 static void
gdk_device_class_init(GdkDeviceClass * klass)98 gdk_device_class_init (GdkDeviceClass *klass)
99 {
100   GObjectClass *object_class = G_OBJECT_CLASS (klass);
101 
102   object_class->finalize = gdk_device_finalize;
103   object_class->dispose = gdk_device_dispose;
104   object_class->set_property = gdk_device_set_property;
105   object_class->get_property = gdk_device_get_property;
106 
107   /**
108    * GdkDevice:display: (attributes org.gtk.Property.get=gdk_device_get_display)
109    *
110    * The `GdkDisplay` the `GdkDevice` pertains to.
111    */
112   device_props[PROP_DISPLAY] =
113       g_param_spec_object ("display",
114                            P_("Device Display"),
115                            P_("Display which the device belongs to"),
116                            GDK_TYPE_DISPLAY,
117                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
118 
119   /**
120    * GdkDevice:name: (attributes org.gtk.Property.get=gdk_device_get_name)
121    *
122    * The device name.
123    */
124   device_props[PROP_NAME] =
125       g_param_spec_string ("name",
126                            P_("Device name"),
127                            P_("Device name"),
128                            NULL,
129                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
130                            G_PARAM_STATIC_STRINGS);
131 
132   /**
133    * GdkDevice:source: (attributes org.gtk.Property.get=gdk_device_get_source)
134    *
135    * Source type for the device.
136    */
137   device_props[PROP_SOURCE] =
138       g_param_spec_enum ("source",
139                          P_("Input source"),
140                          P_("Source type for the device"),
141                          GDK_TYPE_INPUT_SOURCE,
142                          GDK_SOURCE_MOUSE,
143                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
144                          G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
145 
146   /**
147    * GdkDevice:has-cursor: (attributes org.gtk.Property.get=gdk_device_get_has_cursor)
148    *
149    * Whether the device is represented by a cursor on the screen.
150    */
151   device_props[PROP_HAS_CURSOR] =
152       g_param_spec_boolean ("has-cursor",
153                             P_("Whether the device has a cursor"),
154                             P_("Whether there is a visible cursor following device motion"),
155                             FALSE,
156                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
157                             G_PARAM_STATIC_STRINGS);
158 
159   /**
160    * GdkDevice:n-axes:
161    *
162    * Number of axes in the device.
163    */
164   device_props[PROP_N_AXES] =
165       g_param_spec_uint ("n-axes",
166                          P_("Number of axes in the device"),
167                          P_("Number of axes in the device"),
168                          0, G_MAXUINT,
169                          0,
170                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
171 
172   /**
173    * GdkDevice:vendor-id: (attributes org.gtk.Property.get=gdk_device_get_vendor_id)
174    *
175    * Vendor ID of this device.
176    *
177    * See [method@Gdk.Device.get_vendor_id].
178    */
179   device_props[PROP_VENDOR_ID] =
180       g_param_spec_string ("vendor-id",
181                            P_("Vendor ID"),
182                            P_("Vendor ID"),
183                            NULL,
184                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
185                            G_PARAM_STATIC_STRINGS);
186 
187   /**
188    * GdkDevice:product-id: (attributes org.gtk.Property.get=gdk_device_get_product_id)
189    *
190    * Product ID of this device.
191    *
192    * See [method@Gdk.Device.get_product_id].
193    */
194   device_props[PROP_PRODUCT_ID] =
195       g_param_spec_string ("product-id",
196                            P_("Product ID"),
197                            P_("Product ID"),
198                            NULL,
199                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
200                            G_PARAM_STATIC_STRINGS);
201 
202   /**
203    * GdkDevice:seat: (attributes org.gtk.Property.get=gdk_device_get_seat)
204    *
205    * `GdkSeat` of this device.
206    */
207   device_props[PROP_SEAT] =
208       g_param_spec_object ("seat",
209                            P_("Seat"),
210                            P_("Seat"),
211                            GDK_TYPE_SEAT,
212                            G_PARAM_READWRITE |
213                            G_PARAM_STATIC_STRINGS);
214 
215   /**
216    * GdkDevice:num-touches: (attributes org.gtk.Property.get=gdk_device_get_num_touches)
217    *
218    * The maximal number of concurrent touches on a touch device.
219    *
220    * Will be 0 if the device is not a touch device or if the number
221    * of touches is unknown.
222    */
223   device_props[PROP_NUM_TOUCHES] =
224       g_param_spec_uint ("num-touches",
225                          P_("Number of concurrent touches"),
226                          P_("Number of concurrent touches"),
227                          0, G_MAXUINT,
228                          0,
229                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
230                          G_PARAM_STATIC_STRINGS);
231 
232   /**
233    * GdkDevice:tool: (attributes org.gtk.Property.get=gdk_device_get_device_tool)
234    *
235    * The `GdkDeviceTool` that is currently used with this device.
236    */
237   device_props[PROP_TOOL] =
238     g_param_spec_object ("tool",
239                          P_("Tool"),
240                          P_("The tool that is currently used with this device"),
241                          GDK_TYPE_DEVICE_TOOL,
242                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
243 
244   /**
245    * GdkDevice:direction: (attributes org.gtk.Property.get=gdk_device_get_direction)
246    *
247    * The direction of the current layout.
248    *
249    * This is only relevant for keyboard devices.
250    */
251   device_props[PROP_DIRECTION] =
252       g_param_spec_enum ("direction",
253                          P_("Direction"),
254                          P_("The direction of the current layout of the keyboard"),
255                          PANGO_TYPE_DIRECTION, PANGO_DIRECTION_NEUTRAL,
256                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
257 
258   /**
259    * GdkDevice:has-bidi-layouts: (attributes org.gtk.Property.get=gdk_device_has_bidi_layouts)
260    *
261    * Whether the device has both right-to-left and left-to-right layouts.
262    *
263    * This is only relevant for keyboard devices.
264    */
265   device_props[PROP_HAS_BIDI_LAYOUTS] =
266       g_param_spec_boolean ("has-bidi-layouts",
267                             P_("Has bidi layouts"),
268                             P_("Whether the keyboard has bidi layouts"),
269                             FALSE,
270                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
271 
272   /**
273    * GdkDevice:caps-lock-state: (attributes org.gtk.Property.get=gdk_device_get_caps_lock_state)
274    *
275    * Whether Caps Lock is on.
276    *
277    * This is only relevant for keyboard devices.
278    */
279   device_props[PROP_CAPS_LOCK_STATE] =
280       g_param_spec_boolean ("caps-lock-state",
281                             P_("Caps lock state"),
282                             P_("Whether the keyboard caps lock is on"),
283                             FALSE,
284                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
285 
286   /**
287    * GdkDevice:num-lock-state: (attributes org.gtk.Property.get=gdk_device_get_num_lock_state)
288    *
289    * Whether Num Lock is on.
290    *
291    * This is only relevant for keyboard devices.
292    */
293   device_props[PROP_NUM_LOCK_STATE] =
294       g_param_spec_boolean ("num-lock-state",
295                             P_("Num lock state"),
296                             P_("Whether the keyboard num lock is on"),
297                             FALSE,
298                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
299 
300   /**
301    * GdkDevice:scroll-lock-state: (attributes org.gtk.Property.get=gdk_device_get_scroll_lock_state)
302    *
303    * Whether Scroll Lock is on.
304    *
305    * This is only relevant for keyboard devices.
306    */
307   device_props[PROP_SCROLL_LOCK_STATE] =
308       g_param_spec_boolean ("scroll-lock-state",
309                             P_("Scroll lock state"),
310                             P_("Whether the keyboard scroll lock is on"),
311                             FALSE,
312                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
313 
314   /**
315    * GdkDevice:modifier-state: (attributes org.gtk.Property.get=gdk_device_get_modifier_state)
316    *
317    * The current modifier state of the device.
318    *
319    * This is only relevant for keyboard devices.
320    */
321   device_props[PROP_MODIFIER_STATE] =
322       g_param_spec_flags ("modifier-state",
323                           P_("Modifier state"),
324                           P_("The modifier state of the keyboard"),
325                           GDK_TYPE_MODIFIER_TYPE, 0,
326                           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
327 
328   g_object_class_install_properties (object_class, LAST_PROP, device_props);
329 
330   /**
331    * GdkDevice::changed:
332    * @device: the `GdkDevice`
333    *
334    * Emitted either when the the number of either axes or keys changes.
335    *
336    * On X11 this will normally happen when the physical device
337    * routing events through the logical device changes (for
338    * example, user switches from the USB mouse to a tablet); in
339    * that case the logical device will change to reflect the axes
340    * and keys on the new physical device.
341    */
342   signals[CHANGED] =
343     g_signal_new (g_intern_static_string ("changed"),
344                   G_TYPE_FROM_CLASS (object_class),
345                   G_SIGNAL_RUN_LAST,
346                   0, NULL, NULL,
347                   NULL,
348                   G_TYPE_NONE, 0);
349 
350   /**
351    * GdkDevice::tool-changed:
352    * @device: the `GdkDevice`
353    * @tool: The new current tool
354    *
355    * Emitted on pen/eraser devices whenever tools enter or leave proximity.
356    */
357   signals[TOOL_CHANGED] =
358     g_signal_new (g_intern_static_string ("tool-changed"),
359                   G_TYPE_FROM_CLASS (object_class),
360                   G_SIGNAL_RUN_LAST,
361                   0, NULL, NULL,
362                   NULL,
363                   G_TYPE_NONE, 1, GDK_TYPE_DEVICE_TOOL);
364 }
365 
366 static void
gdk_device_init(GdkDevice * device)367 gdk_device_init (GdkDevice *device)
368 {
369   device->axes = g_array_new (FALSE, TRUE, sizeof (GdkAxisInfo));
370 }
371 
372 static void
gdk_device_finalize(GObject * object)373 gdk_device_finalize (GObject *object)
374 {
375   GdkDevice *device = GDK_DEVICE (object);
376 
377   if (device->axes)
378     {
379       g_array_free (device->axes, TRUE);
380       device->axes = NULL;
381     }
382 
383   g_clear_pointer (&device->name, g_free);
384   g_clear_pointer (&device->vendor_id, g_free);
385   g_clear_pointer (&device->product_id, g_free);
386 
387   G_OBJECT_CLASS (gdk_device_parent_class)->finalize (object);
388 }
389 
390 static void
gdk_device_dispose(GObject * object)391 gdk_device_dispose (GObject *object)
392 {
393   GdkDevice *device = GDK_DEVICE (object);
394   GdkDevice *associated = device->associated;
395 
396   if (associated)
397     _gdk_device_remove_physical_device (associated, device);
398 
399   if (associated)
400     {
401       device->associated = NULL;
402 
403       if (associated->associated == device)
404         _gdk_device_set_associated_device (associated, NULL);
405 
406       g_object_unref (associated);
407     }
408 
409   g_clear_object (&device->last_tool);
410 
411   G_OBJECT_CLASS (gdk_device_parent_class)->dispose (object);
412 }
413 
414 static void
gdk_device_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)415 gdk_device_set_property (GObject      *object,
416                          guint         prop_id,
417                          const GValue *value,
418                          GParamSpec   *pspec)
419 {
420   GdkDevice *device = GDK_DEVICE (object);
421 
422   switch (prop_id)
423     {
424     case PROP_DISPLAY:
425       device->display = g_value_get_object (value);
426       break;
427     case PROP_NAME:
428       g_free (device->name);
429 
430       device->name = g_value_dup_string (value);
431       break;
432     case PROP_SOURCE:
433       device->source = g_value_get_enum (value);
434       break;
435     case PROP_HAS_CURSOR:
436       device->has_cursor = g_value_get_boolean (value);
437       break;
438     case PROP_VENDOR_ID:
439       device->vendor_id = g_value_dup_string (value);
440       break;
441     case PROP_PRODUCT_ID:
442       device->product_id = g_value_dup_string (value);
443       break;
444     case PROP_SEAT:
445       device->seat = g_value_get_object (value);
446       break;
447     case PROP_NUM_TOUCHES:
448       device->num_touches = g_value_get_uint (value);
449       break;
450     default:
451       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
452       break;
453     }
454 }
455 
456 static void
gdk_device_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)457 gdk_device_get_property (GObject    *object,
458                          guint       prop_id,
459                          GValue     *value,
460                          GParamSpec *pspec)
461 {
462   GdkDevice *device = GDK_DEVICE (object);
463 
464   switch (prop_id)
465     {
466     case PROP_DISPLAY:
467       g_value_set_object (value, device->display);
468       break;
469     case PROP_NAME:
470       g_value_set_string (value, device->name);
471       break;
472     case PROP_SOURCE:
473       g_value_set_enum (value, device->source);
474       break;
475     case PROP_HAS_CURSOR:
476       g_value_set_boolean (value, device->has_cursor);
477       break;
478     case PROP_N_AXES:
479       g_value_set_uint (value, device->axes->len);
480       break;
481     case PROP_VENDOR_ID:
482       g_value_set_string (value, device->vendor_id);
483       break;
484     case PROP_PRODUCT_ID:
485       g_value_set_string (value, device->product_id);
486       break;
487     case PROP_SEAT:
488       g_value_set_object (value, device->seat);
489       break;
490     case PROP_NUM_TOUCHES:
491       g_value_set_uint (value, device->num_touches);
492       break;
493     case PROP_TOOL:
494       g_value_set_object (value, device->last_tool);
495       break;
496     case PROP_DIRECTION:
497       g_value_set_enum (value, gdk_device_get_direction (device));
498       break;
499     case PROP_HAS_BIDI_LAYOUTS:
500       g_value_set_boolean (value, gdk_device_has_bidi_layouts (device));
501       break;
502     case PROP_CAPS_LOCK_STATE:
503       g_value_set_boolean (value, gdk_device_get_caps_lock_state (device));
504       break;
505     case PROP_NUM_LOCK_STATE:
506       g_value_set_boolean (value, gdk_device_get_num_lock_state (device));
507       break;
508     case PROP_SCROLL_LOCK_STATE:
509       g_value_set_boolean (value, gdk_device_get_scroll_lock_state (device));
510       break;
511     case PROP_MODIFIER_STATE:
512       g_value_set_flags (value, gdk_device_get_modifier_state (device));
513       break;
514     default:
515       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
516       break;
517     }
518 }
519 
520 /**
521  * gdk_device_get_surface_at_position:
522  * @device: pointer `GdkDevice` to query info to
523  * @win_x: (out) (optional): return location for the X coordinate
524  *   of the device location relative to the surface origin
525  * @win_y: (out) (optional): return location for the Y coordinate
526  *   of the device location relative to the surface origin
527  *
528  * Obtains the surface underneath @device, returning the location of the
529  * device in @win_x and @win_y.
530  *
531  * Returns %NULL if the surface tree under @device is not known to GDK
532  * (for example, belongs to another application).
533  *
534  * Returns: (nullable) (transfer none): the `GdkSurface` under the
535  *   device position
536  */
537 GdkSurface *
gdk_device_get_surface_at_position(GdkDevice * device,double * win_x,double * win_y)538 gdk_device_get_surface_at_position (GdkDevice *device,
539                                     double    *win_x,
540                                     double    *win_y)
541 {
542   double tmp_x, tmp_y;
543   GdkSurface *surface;
544 
545   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
546   g_return_val_if_fail (device->source != GDK_SOURCE_KEYBOARD, NULL);
547 
548   surface = _gdk_device_surface_at_position (device, &tmp_x, &tmp_y, NULL);
549 
550   if (win_x)
551     *win_x = tmp_x;
552   if (win_y)
553     *win_y = tmp_y;
554 
555   return surface;
556 }
557 
558 /**
559  * gdk_device_get_name:
560  * @device: a GdkDevice`
561  *
562  * The name of the device, suitable for showing in a user interface.
563  *
564  * Returns: a name
565  */
566 const char *
gdk_device_get_name(GdkDevice * device)567 gdk_device_get_name (GdkDevice *device)
568 {
569   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
570 
571   return device->name;
572 }
573 
574 /**
575  * gdk_device_get_has_cursor: (attributes org.gtk.Method.get_property=has-cursor)
576  * @device: a `GdkDevice`
577  *
578  * Determines whether the pointer follows device motion.
579  *
580  * This is not meaningful for keyboard devices, which
581  * don't have a pointer.
582  *
583  * Returns: %TRUE if the pointer follows device motion
584  */
585 gboolean
gdk_device_get_has_cursor(GdkDevice * device)586 gdk_device_get_has_cursor (GdkDevice *device)
587 {
588   g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
589 
590   return device->has_cursor;
591 }
592 
593 /**
594  * gdk_device_get_source: (attributes org.gtk.Method.get_property=source)
595  * @device: a `GdkDevice`
596  *
597  * Determines the type of the device.
598  *
599  * Returns: a `GdkInputSource`
600  */
601 GdkInputSource
gdk_device_get_source(GdkDevice * device)602 gdk_device_get_source (GdkDevice *device)
603 {
604   g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
605 
606   return device->source;
607 }
608 
609 /**
610  * gdk_device_get_axis_use:
611  * @device: a pointer `GdkDevice`
612  * @index_: the index of the axi.
613  *
614  * Returns the axis use for @index_.
615  *
616  * Returns: a `GdkAxisUse` specifying how the axis is used.
617  */
618 GdkAxisUse
gdk_device_get_axis_use(GdkDevice * device,guint index_)619 gdk_device_get_axis_use (GdkDevice *device,
620                          guint      index_)
621 {
622   GdkAxisInfo *info;
623 
624   g_return_val_if_fail (GDK_IS_DEVICE (device), GDK_AXIS_IGNORE);
625   g_return_val_if_fail (device->source != GDK_SOURCE_KEYBOARD, GDK_AXIS_IGNORE);
626   g_return_val_if_fail (index_ < device->axes->len, GDK_AXIS_IGNORE);
627 
628   info = &g_array_index (device->axes, GdkAxisInfo, index_);
629 
630   return info->use;
631 }
632 
633 /**
634  * gdk_device_get_display: (attributes org.gtk.Method.get_property=display)
635  * @device: a `GdkDevice`
636  *
637  * Returns the `GdkDisplay` to which @device pertains.
638  *
639  * Returns: (transfer none): a `GdkDisplay`
640  */
641 GdkDisplay *
gdk_device_get_display(GdkDevice * device)642 gdk_device_get_display (GdkDevice *device)
643 {
644   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
645 
646   return device->display;
647 }
648 
649 void
_gdk_device_set_associated_device(GdkDevice * device,GdkDevice * associated)650 _gdk_device_set_associated_device (GdkDevice *device,
651                                    GdkDevice *associated)
652 {
653   g_return_if_fail (GDK_IS_DEVICE (device));
654   g_return_if_fail (associated == NULL || GDK_IS_DEVICE (associated));
655 
656   g_set_object (&device->associated, associated);
657 }
658 
659 /*
660  * gdk_device_list_physical_devices:
661  * @device: a logical `GdkDevice`
662  *
663  * Returns the list of physical devices attached to the given logical
664  * `GdkDevice`.
665  *
666  * Returns: (nullable) (transfer container) (element-type GdkDevice):
667  *   the list of physical devices attached to a logical `GdkDevice`
668  */
669 GList *
gdk_device_list_physical_devices(GdkDevice * device)670 gdk_device_list_physical_devices (GdkDevice *device)
671 {
672   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
673 
674   return g_list_copy (device->physical_devices);
675 }
676 
677 void
_gdk_device_add_physical_device(GdkDevice * device,GdkDevice * physical)678 _gdk_device_add_physical_device (GdkDevice *device,
679                                  GdkDevice *physical)
680 {
681   if (!g_list_find (device->physical_devices, physical))
682     device->physical_devices = g_list_prepend (device->physical_devices, physical);
683 }
684 
685 void
_gdk_device_remove_physical_device(GdkDevice * device,GdkDevice * physical)686 _gdk_device_remove_physical_device (GdkDevice *device,
687                                     GdkDevice *physical)
688 {
689   GList *elem;
690 
691   elem = g_list_find (device->physical_devices, physical);
692   if (elem == NULL)
693     return;
694 
695   device->physical_devices = g_list_delete_link (device->physical_devices, elem);
696 }
697 
698 /*
699  * gdk_device_get_n_axes:
700  * @device: a pointer `GdkDevice`
701  *
702  * Returns the number of axes the device currently has.
703  *
704  * Returns: the number of axes.
705  */
706 int
gdk_device_get_n_axes(GdkDevice * device)707 gdk_device_get_n_axes (GdkDevice *device)
708 {
709   g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
710   g_return_val_if_fail (device->source != GDK_SOURCE_KEYBOARD, 0);
711 
712   return device->axes->len;
713 }
714 
715 /*
716  * gdk_device_get_axis: (skip)
717  * @device: a `GdkDevice`
718  * @axes: (array): pointer to an array of axes
719  * @use: the use to look for
720  * @value: (out): location to store the found value
721  *
722  * Interprets an array of `double` as axis values and get the value
723  * for a given axis use.
724  *
725  * Returns: %TRUE if the given axis use was found, otherwise %FALSE
726  */
727 gboolean
gdk_device_get_axis(GdkDevice * device,double * axes,GdkAxisUse use,double * value)728 gdk_device_get_axis (GdkDevice  *device,
729                      double     *axes,
730                      GdkAxisUse  use,
731                      double     *value)
732 {
733   int i;
734 
735   g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
736   g_return_val_if_fail (device->source != GDK_SOURCE_KEYBOARD, FALSE);
737 
738   if (axes == NULL)
739     return FALSE;
740 
741   g_return_val_if_fail (device->axes != NULL, FALSE);
742 
743   for (i = 0; i < device->axes->len; i++)
744     {
745       GdkAxisInfo axis_info;
746 
747       axis_info = g_array_index (device->axes, GdkAxisInfo, i);
748 
749       if (axis_info.use != use)
750         continue;
751 
752       if (value)
753         *value = axes[i];
754 
755       return TRUE;
756     }
757 
758   return FALSE;
759 }
760 
761 static GdkEventMask
get_native_grab_event_mask(GdkEventMask grab_mask)762 get_native_grab_event_mask (GdkEventMask grab_mask)
763 {
764   /* Similar to the above but for pointer events only */
765   return
766     GDK_POINTER_MOTION_MASK |
767     GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
768     GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
769     GDK_SCROLL_MASK |
770     (grab_mask &
771      ~(GDK_BUTTON_MOTION_MASK |
772        GDK_BUTTON1_MOTION_MASK |
773        GDK_BUTTON2_MOTION_MASK |
774        GDK_BUTTON3_MOTION_MASK));
775 }
776 
777 GdkGrabStatus
gdk_device_grab(GdkDevice * device,GdkSurface * surface,gboolean owner_events,GdkEventMask event_mask,GdkCursor * cursor,guint32 time_)778 gdk_device_grab (GdkDevice        *device,
779                  GdkSurface       *surface,
780                  gboolean          owner_events,
781                  GdkEventMask      event_mask,
782                  GdkCursor        *cursor,
783                  guint32           time_)
784 {
785   GdkGrabStatus res;
786 
787   g_return_val_if_fail (GDK_IS_DEVICE (device), GDK_GRAB_FAILED);
788   g_return_val_if_fail (GDK_IS_SURFACE (surface), GDK_GRAB_FAILED);
789   g_return_val_if_fail (gdk_surface_get_display (surface) == gdk_device_get_display (device), GDK_GRAB_FAILED);
790 
791   if (GDK_SURFACE_DESTROYED (surface))
792     return GDK_GRAB_NOT_VIEWABLE;
793 
794   res = GDK_DEVICE_GET_CLASS (device)->grab (device,
795                                              surface,
796                                              owner_events,
797                                              get_native_grab_event_mask (event_mask),
798                                              NULL,
799                                              cursor,
800                                              time_);
801 
802   if (res == GDK_GRAB_SUCCESS)
803     {
804       GdkDisplay *display;
805       gulong serial;
806 
807       display = gdk_surface_get_display (surface);
808       serial = _gdk_display_get_next_serial (display);
809 
810       _gdk_display_add_device_grab (display,
811                                     device,
812                                     surface,
813                                     owner_events,
814                                     event_mask,
815                                     serial,
816                                     time_,
817                                     FALSE);
818     }
819 
820   return res;
821 }
822 
823 void
gdk_device_ungrab(GdkDevice * device,guint32 time_)824 gdk_device_ungrab (GdkDevice  *device,
825                    guint32     time_)
826 {
827   g_return_if_fail (GDK_IS_DEVICE (device));
828 
829   GDK_DEVICE_GET_CLASS (device)->ungrab (device, time_);
830 }
831 
832 /* Private API */
833 void
_gdk_device_reset_axes(GdkDevice * device)834 _gdk_device_reset_axes (GdkDevice *device)
835 {
836   int i;
837 
838   for (i = device->axes->len - 1; i >= 0; i--)
839     g_array_remove_index (device->axes, i);
840 
841   g_object_notify_by_pspec (G_OBJECT (device), device_props[PROP_N_AXES]);
842 }
843 
844 guint
_gdk_device_add_axis(GdkDevice * device,GdkAxisUse use,double min_value,double max_value,double resolution)845 _gdk_device_add_axis (GdkDevice   *device,
846                       GdkAxisUse   use,
847                       double       min_value,
848                       double       max_value,
849                       double       resolution)
850 {
851   GdkAxisInfo axis_info;
852   guint pos;
853 
854   axis_info.use = use;
855   axis_info.min_value = min_value;
856   axis_info.max_value = max_value;
857   axis_info.resolution = resolution;
858 
859   switch ((guint) use)
860     {
861     case GDK_AXIS_X:
862     case GDK_AXIS_Y:
863       axis_info.min_axis = 0;
864       axis_info.max_axis = 0;
865       break;
866     case GDK_AXIS_XTILT:
867     case GDK_AXIS_YTILT:
868       axis_info.min_axis = -1;
869       axis_info.max_axis = 1;
870       break;
871     default:
872       axis_info.min_axis = 0;
873       axis_info.max_axis = 1;
874       break;
875     }
876 
877   device->axes = g_array_append_val (device->axes, axis_info);
878   pos = device->axes->len - 1;
879 
880   g_object_notify_by_pspec (G_OBJECT (device), device_props[PROP_N_AXES]);
881 
882   return pos;
883 }
884 
885 void
_gdk_device_get_axis_info(GdkDevice * device,guint index_,GdkAxisUse * use,double * min_value,double * max_value,double * resolution)886 _gdk_device_get_axis_info (GdkDevice   *device,
887                            guint        index_,
888                            GdkAxisUse   *use,
889                            double       *min_value,
890                            double       *max_value,
891                            double       *resolution)
892 {
893   GdkAxisInfo *info;
894 
895   g_return_if_fail (GDK_IS_DEVICE (device));
896   g_return_if_fail (index_ < device->axes->len);
897 
898   info = &g_array_index (device->axes, GdkAxisInfo, index_);
899 
900   *use = info->use;
901   *min_value = info->min_value;
902   *max_value = info->max_value;
903   *resolution = info->resolution;
904 }
905 
906 static GdkAxisInfo *
find_axis_info(GArray * array,GdkAxisUse use)907 find_axis_info (GArray     *array,
908                 GdkAxisUse  use)
909 {
910   GdkAxisInfo *info;
911   int i;
912 
913   for (i = 0; i < GDK_AXIS_LAST; i++)
914     {
915       info = &g_array_index (array, GdkAxisInfo, i);
916 
917       if (info->use == use)
918         return info;
919     }
920 
921   return NULL;
922 }
923 
924 gboolean
_gdk_device_translate_surface_coord(GdkDevice * device,GdkSurface * surface,guint index_,double value,double * axis_value)925 _gdk_device_translate_surface_coord (GdkDevice *device,
926                                      GdkSurface *surface,
927                                      guint      index_,
928                                      double     value,
929                                      double    *axis_value)
930 {
931   GdkAxisInfo axis_info;
932   GdkAxisInfo *axis_info_x, *axis_info_y;
933   double device_width, device_height;
934   double x_offset, y_offset;
935   double x_scale, y_scale;
936   double x_min, y_min;
937   double x_resolution, y_resolution;
938   double device_aspect;
939   int surface_width, surface_height;
940 
941   if (index_ >= device->axes->len)
942     return FALSE;
943 
944   axis_info = g_array_index (device->axes, GdkAxisInfo, index_);
945 
946   if (axis_info.use != GDK_AXIS_X &&
947       axis_info.use != GDK_AXIS_Y)
948     return FALSE;
949 
950   if (axis_info.use == GDK_AXIS_X)
951     {
952       axis_info_x = &axis_info;
953       axis_info_y = find_axis_info (device->axes, GDK_AXIS_Y);
954       if (axis_info_y == NULL)
955         return FALSE;
956     }
957   else
958     {
959       axis_info_x = find_axis_info (device->axes, GDK_AXIS_X);
960       axis_info_y = &axis_info;
961       if (axis_info_x == NULL)
962         return FALSE;
963     }
964 
965   device_width = axis_info_x->max_value - axis_info_x->min_value;
966   device_height = axis_info_y->max_value - axis_info_y->min_value;
967 
968   x_min = axis_info_x->min_value;
969   y_min = axis_info_y->min_value;
970 
971   surface_width = gdk_surface_get_width (surface);
972   surface_height = gdk_surface_get_height (surface);
973 
974   x_resolution = axis_info_x->resolution;
975   y_resolution = axis_info_y->resolution;
976 
977   /*
978    * Some drivers incorrectly report the resolution of the device
979    * as zero (in partiular linuxwacom < 0.5.3 with usb tablets).
980    * This causes the device_aspect to become NaN and totally
981    * breaks windowed mode.  If this is the case, the best we can
982    * do is to assume the resolution is non-zero is equal in both
983    * directions (which is true for many devices).  The absolute
984    * value of the resolution doesn't matter since we only use the
985    * ratio.
986    */
987   if (x_resolution == 0 || y_resolution == 0)
988     {
989       x_resolution = 1;
990       y_resolution = 1;
991     }
992 
993   device_aspect = (device_height * y_resolution) /
994     (device_width * x_resolution);
995 
996   if (device_aspect * surface_width >= surface_height)
997     {
998       /* device taller than surface */
999       x_scale = surface_width / device_width;
1000       y_scale = (x_scale * x_resolution) / y_resolution;
1001 
1002       x_offset = 0;
1003       y_offset = - (device_height * y_scale - surface_height) / 2;
1004     }
1005   else
1006     {
1007       /* surface taller than device */
1008       y_scale = surface_height / device_height;
1009       x_scale = (y_scale * y_resolution) / x_resolution;
1010 
1011       y_offset = 0;
1012       x_offset = - (device_width * x_scale - surface_width) / 2;
1013     }
1014 
1015   if (axis_value)
1016     {
1017       if (axis_info.use == GDK_AXIS_X)
1018         *axis_value = x_offset + x_scale * (value - x_min);
1019       else
1020         *axis_value = y_offset + y_scale * (value - y_min);
1021     }
1022 
1023   return TRUE;
1024 }
1025 
1026 gboolean
_gdk_device_translate_screen_coord(GdkDevice * device,GdkSurface * surface,double surface_root_x,double surface_root_y,double screen_width,double screen_height,guint index_,double value,double * axis_value)1027 _gdk_device_translate_screen_coord (GdkDevice *device,
1028                                     GdkSurface *surface,
1029                                     double     surface_root_x,
1030                                     double     surface_root_y,
1031                                     double     screen_width,
1032                                     double     screen_height,
1033                                     guint      index_,
1034                                     double     value,
1035                                     double    *axis_value)
1036 {
1037   GdkAxisInfo axis_info;
1038   double axis_width, scale, offset;
1039 
1040   if (index_ >= device->axes->len)
1041     return FALSE;
1042 
1043   axis_info = g_array_index (device->axes, GdkAxisInfo, index_);
1044 
1045   if (axis_info.use != GDK_AXIS_X &&
1046       axis_info.use != GDK_AXIS_Y)
1047     return FALSE;
1048 
1049   axis_width = axis_info.max_value - axis_info.min_value;
1050 
1051   if (axis_info.use == GDK_AXIS_X)
1052     {
1053       if (axis_width > 0)
1054         scale = screen_width / axis_width;
1055       else
1056         scale = 1;
1057 
1058       offset = - surface_root_x;
1059     }
1060   else
1061     {
1062       if (axis_width > 0)
1063         scale = screen_height / axis_width;
1064       else
1065         scale = 1;
1066 
1067       offset = - surface_root_y;
1068     }
1069 
1070   if (axis_value)
1071     *axis_value = offset + scale * (value - axis_info.min_value);
1072 
1073   return TRUE;
1074 }
1075 
1076 gboolean
_gdk_device_translate_axis(GdkDevice * device,guint index_,double value,double * axis_value)1077 _gdk_device_translate_axis (GdkDevice *device,
1078                             guint      index_,
1079                             double     value,
1080                             double    *axis_value)
1081 {
1082   GdkAxisInfo axis_info;
1083   double axis_width, out;
1084 
1085   if (index_ >= device->axes->len)
1086     return FALSE;
1087 
1088   axis_info = g_array_index (device->axes, GdkAxisInfo, index_);
1089 
1090   if (axis_info.use == GDK_AXIS_X ||
1091       axis_info.use == GDK_AXIS_Y)
1092     return FALSE;
1093 
1094   axis_width = axis_info.max_value - axis_info.min_value;
1095   out = (axis_info.max_axis * (value - axis_info.min_value) +
1096          axis_info.min_axis * (axis_info.max_value - value)) / axis_width;
1097 
1098   if (axis_value)
1099     *axis_value = out;
1100 
1101   return TRUE;
1102 }
1103 
1104 GdkSurface *
_gdk_device_surface_at_position(GdkDevice * device,double * win_x,double * win_y,GdkModifierType * mask)1105 _gdk_device_surface_at_position (GdkDevice       *device,
1106                                  double          *win_x,
1107                                  double          *win_y,
1108                                  GdkModifierType *mask)
1109 {
1110   return GDK_DEVICE_GET_CLASS (device)->surface_at_position (device,
1111                                                              win_x,
1112                                                              win_y,
1113                                                              mask);
1114 }
1115 
1116 /**
1117  * gdk_device_get_vendor_id: (attributes org.gtk.Method.get_property=vendor-id)
1118  * @device: a physical `GdkDevice`
1119  *
1120  * Returns the vendor ID of this device.
1121  *
1122  * This ID is retrieved from the device, and does not change.
1123  *
1124  * This function, together with [method@Gdk.Device.get_product_id],
1125  * can be used to eg. compose `GSettings` paths to store settings
1126  * for this device.
1127  *
1128  * ```c
1129  *  static GSettings *
1130  *  get_device_settings (GdkDevice *device)
1131  *  {
1132  *    const char *vendor, *product;
1133  *    GSettings *settings;
1134  *    GdkDevice *device;
1135  *    char *path;
1136  *
1137  *    vendor = gdk_device_get_vendor_id (device);
1138  *    product = gdk_device_get_product_id (device);
1139  *
1140  *    path = g_strdup_printf ("/org/example/app/devices/%s:%s/", vendor, product);
1141  *    settings = g_settings_new_with_path (DEVICE_SCHEMA, path);
1142  *    g_free (path);
1143  *
1144  *    return settings;
1145  *  }
1146  * ```
1147  *
1148  * Returns: (nullable): the vendor ID
1149  */
1150 const char *
gdk_device_get_vendor_id(GdkDevice * device)1151 gdk_device_get_vendor_id (GdkDevice *device)
1152 {
1153   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
1154 
1155   return device->vendor_id;
1156 }
1157 
1158 /**
1159  * gdk_device_get_product_id: (attributes org.gtk.Method.get_property=product-id)
1160  * @device: a physical `GdkDevice`
1161  *
1162  * Returns the product ID of this device.
1163  *
1164  * This ID is retrieved from the device, and does not change.
1165  * See [method@Gdk.Device.get_vendor_id] for more information.
1166  *
1167  * Returns: (nullable): the product ID
1168  */
1169 const char *
gdk_device_get_product_id(GdkDevice * device)1170 gdk_device_get_product_id (GdkDevice *device)
1171 {
1172   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
1173 
1174   return device->product_id;
1175 }
1176 
1177 void
gdk_device_set_seat(GdkDevice * device,GdkSeat * seat)1178 gdk_device_set_seat (GdkDevice *device,
1179                      GdkSeat   *seat)
1180 {
1181   g_return_if_fail (GDK_IS_DEVICE (device));
1182   g_return_if_fail (!seat || GDK_IS_SEAT (seat));
1183 
1184   if (device->seat == seat)
1185     return;
1186 
1187   device->seat = seat;
1188   g_object_notify (G_OBJECT (device), "seat");
1189 }
1190 
1191 /**
1192  * gdk_device_get_seat: (attributes org.gtk.Method.get_property=seat)
1193  * @device: A `GdkDevice`
1194  *
1195  * Returns the `GdkSeat` the device belongs to.
1196  *
1197  * Returns: (transfer none): a `GdkSeat`
1198  */
1199 GdkSeat *
gdk_device_get_seat(GdkDevice * device)1200 gdk_device_get_seat (GdkDevice *device)
1201 {
1202   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
1203 
1204   return device->seat;
1205 }
1206 
1207 void
gdk_device_update_tool(GdkDevice * device,GdkDeviceTool * tool)1208 gdk_device_update_tool (GdkDevice     *device,
1209                         GdkDeviceTool *tool)
1210 {
1211   g_return_if_fail (GDK_IS_DEVICE (device));
1212 
1213   if (g_set_object (&device->last_tool, tool))
1214     {
1215       g_object_notify (G_OBJECT (device), "tool");
1216       g_signal_emit (device, signals[TOOL_CHANGED], 0, tool);
1217     }
1218 }
1219 
1220 /**
1221  * gdk_device_get_num_touches:
1222  * @device: a `GdkDevice`
1223  *
1224  * Retrieves the number of touch points associated to @device.
1225  *
1226  * Returns: the number of touch points
1227  */
1228 guint
gdk_device_get_num_touches(GdkDevice * device)1229 gdk_device_get_num_touches (GdkDevice *device)
1230 {
1231   g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
1232 
1233   return device->num_touches;
1234 }
1235 
1236 /**
1237  * gdk_device_get_device_tool: (attributes org.gtk.Method.get_property=tool)
1238  * @device: a `GdkDevice`
1239  *
1240  * Retrieves the current tool for @device.
1241  *
1242  * Returns: (transfer none): the `GdkDeviceTool`
1243  */
1244 GdkDeviceTool *
gdk_device_get_device_tool(GdkDevice * device)1245 gdk_device_get_device_tool (GdkDevice *device)
1246 {
1247   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
1248 
1249   return device->last_tool;
1250 }
1251 
1252 /**
1253  * gdk_device_get_caps_lock_state: (attributes org.gtk.Method.get_property=caps-lock-state)
1254  * @device: a `GdkDevice`
1255  *
1256  * Retrieves whether the Caps Lock modifier of the keyboard is locked.
1257  *
1258  * This is only relevant for keyboard devices.
1259  *
1260  * Returns: %TRUE if Caps Lock is on for @device
1261  */
1262 gboolean
gdk_device_get_caps_lock_state(GdkDevice * device)1263 gdk_device_get_caps_lock_state (GdkDevice *device)
1264 {
1265   GdkKeymap *keymap = gdk_display_get_keymap (device->display);
1266 
1267   if (device->source == GDK_SOURCE_KEYBOARD)
1268     return gdk_keymap_get_caps_lock_state (keymap);
1269 
1270   return FALSE;
1271 }
1272 
1273 /**
1274  * gdk_device_get_num_lock_state: (attributes org.gtk.Method.get_property=num-lock-state)
1275  * @device: a ``GdkDevice`
1276  *
1277  * Retrieves whether the Num Lock modifier of the keyboard is locked.
1278  *
1279  * This is only relevant for keyboard devices.
1280  *
1281  * Returns: %TRUE if Num Lock is on for @device
1282  */
1283 gboolean
gdk_device_get_num_lock_state(GdkDevice * device)1284 gdk_device_get_num_lock_state (GdkDevice *device)
1285 {
1286   GdkKeymap *keymap = gdk_display_get_keymap (device->display);
1287 
1288   if (device->source == GDK_SOURCE_KEYBOARD)
1289     return gdk_keymap_get_num_lock_state (keymap);
1290 
1291   return FALSE;
1292 }
1293 
1294 /**
1295  * gdk_device_get_scroll_lock_state: (attributes org.gtk.Method.get_property=scroll-lock-state)
1296  * @device: a `GdkDevice`
1297  *
1298  * Retrieves whether the Scroll Lock modifier of the keyboard is locked.
1299  *
1300  * This is only relevant for keyboard devices.
1301  *
1302  * Returns: %TRUE if Scroll Lock is on for @device
1303  */
1304 gboolean
gdk_device_get_scroll_lock_state(GdkDevice * device)1305 gdk_device_get_scroll_lock_state (GdkDevice *device)
1306 {
1307   GdkKeymap *keymap = gdk_display_get_keymap (device->display);
1308 
1309   if (device->source == GDK_SOURCE_KEYBOARD)
1310     return gdk_keymap_get_scroll_lock_state (keymap);
1311 
1312   return FALSE;
1313 }
1314 
1315 /**
1316  * gdk_device_get_modifier_state: (attributes org.gtk.Method.get_property=modifier-state)
1317  * @device: a `GdkDevice`
1318  *
1319  * Retrieves the current modifier state of the keyboard.
1320  *
1321  * This is only relevant for keyboard devices.
1322  *
1323  * Returns: the current modifier state
1324  */
1325 GdkModifierType
gdk_device_get_modifier_state(GdkDevice * device)1326 gdk_device_get_modifier_state (GdkDevice *device)
1327 {
1328   GdkKeymap *keymap = gdk_display_get_keymap (device->display);
1329 
1330   if (device->source == GDK_SOURCE_KEYBOARD)
1331     return gdk_keymap_get_modifier_state (keymap);
1332 
1333   return 0;
1334 }
1335 
1336 /**
1337  * gdk_device_get_direction: (attributes org.gtk.Method.get_property=direction)
1338  * @device: a `GdkDevice`
1339  *
1340  * Returns the direction of effective layout of the keyboard.
1341  *
1342  * This is only relevant for keyboard devices.
1343  *
1344  * The direction of a layout is the direction of the majority
1345  * of its symbols. See [func@Pango.unichar_direction].
1346  *
1347  * Returns: %PANGO_DIRECTION_LTR or %PANGO_DIRECTION_RTL
1348  *   if it can determine the direction. %PANGO_DIRECTION_NEUTRAL
1349  *   otherwise
1350  */
1351 PangoDirection
gdk_device_get_direction(GdkDevice * device)1352 gdk_device_get_direction (GdkDevice *device)
1353 {
1354   GdkKeymap *keymap = gdk_display_get_keymap (device->display);
1355 
1356   if (device->source == GDK_SOURCE_KEYBOARD)
1357     return gdk_keymap_get_direction (keymap);
1358 
1359   return PANGO_DIRECTION_NEUTRAL;
1360 }
1361 
1362 /**
1363  * gdk_device_has_bidi_layouts: (attributes org.gtk.Method.get_property=has-bidi-layouts)
1364  * @device: a `GdkDevice`
1365  *
1366  * Determines if layouts for both right-to-left and
1367  * left-to-right languages are in use on the keyboard.
1368  *
1369  * This is only relevant for keyboard devices.
1370  *
1371  * Returns: %TRUE if there are layouts with both directions, %FALSE otherwise
1372  */
1373 gboolean
gdk_device_has_bidi_layouts(GdkDevice * device)1374 gdk_device_has_bidi_layouts (GdkDevice *device)
1375 {
1376   GdkKeymap *keymap = gdk_display_get_keymap (device->display);
1377 
1378   if (device->source == GDK_SOURCE_KEYBOARD)
1379     return gdk_keymap_have_bidi_layouts (keymap);
1380 
1381   return FALSE;
1382 }
1383 
1384 void
gdk_device_set_timestamp(GdkDevice * device,guint32 timestamp)1385 gdk_device_set_timestamp (GdkDevice *device,
1386                           guint32    timestamp)
1387 {
1388   device->timestamp = timestamp;
1389 }
1390 
1391 /**
1392  * gdk_device_get_timestamp:
1393  * @device: a `GdkDevice`
1394  *
1395  * Returns the timestamp of the last activity for this device.
1396  *
1397  * In practice, this means the timestamp of the last event that was
1398  * received from the OS for this device. (GTK may occasionally produce
1399  * events for a device that are not received from the OS, and will not
1400  * update the timestamp).
1401  *
1402  * Returns: the timestamp of the last activity for this device
1403  *
1404  * Since: 4.2
1405  */
1406 guint32
gdk_device_get_timestamp(GdkDevice * device)1407 gdk_device_get_timestamp (GdkDevice *device)
1408 {
1409   g_return_val_if_fail (GDK_IS_DEVICE (device), GDK_CURRENT_TIME);
1410 
1411   return device->timestamp;
1412 }
1413