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