]> Pileus Git - ~andy/gtk/blob - gdk/gdkdevice.c
Hide GdkDevice struct
[~andy/gtk] / gdk / gdkdevice.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include "gdkdevice.h"
23
24 #include "gdkinternals.h"
25 #include "gdkdeviceprivate.h"
26 #include "gdkintl.h"
27
28 typedef struct _GdkAxisInfo GdkAxisInfo;
29
30 struct _GdkAxisInfo
31 {
32   GdkAtom label;
33   GdkAxisUse use;
34
35   gdouble min_axis;
36   gdouble max_axis;
37
38   gdouble min_value;
39   gdouble max_value;
40   gdouble resolution;
41 };
42
43 enum {
44   CHANGED,
45   LAST_SIGNAL
46 };
47
48 static guint signals [LAST_SIGNAL] = { 0 };
49
50
51 static void gdk_device_dispose      (GObject      *object);
52 static void gdk_device_set_property (GObject      *object,
53                                      guint         prop_id,
54                                      const GValue *value,
55                                      GParamSpec   *pspec);
56 static void gdk_device_get_property (GObject      *object,
57                                      guint         prop_id,
58                                      GValue       *value,
59                                      GParamSpec   *pspec);
60
61
62 G_DEFINE_ABSTRACT_TYPE (GdkDevice, gdk_device, G_TYPE_OBJECT)
63
64 enum {
65   PROP_0,
66   PROP_DISPLAY,
67   PROP_DEVICE_MANAGER,
68   PROP_NAME,
69   PROP_ASSOCIATED_DEVICE,
70   PROP_TYPE,
71   PROP_INPUT_SOURCE,
72   PROP_INPUT_MODE,
73   PROP_HAS_CURSOR,
74   PROP_N_AXES
75 };
76
77
78 static void
79 gdk_device_class_init (GdkDeviceClass *klass)
80 {
81   GObjectClass *object_class = G_OBJECT_CLASS (klass);
82
83   object_class->dispose = gdk_device_dispose;
84   object_class->set_property = gdk_device_set_property;
85   object_class->get_property = gdk_device_get_property;
86
87   /**
88    * GdkDevice:display:
89    *
90    * The #GdkDisplay the #GdkDevice pertains to.
91    *
92    * Since: 3.0
93    */
94   g_object_class_install_property (object_class,
95                                    PROP_DISPLAY,
96                                    g_param_spec_object ("display",
97                                                         P_("Device Display"),
98                                                         P_("Display which the device belongs to"),
99                                                         GDK_TYPE_DISPLAY,
100                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
101                                                         G_PARAM_STATIC_STRINGS));
102   /**
103    * GdkDevice:device-manager:
104    *
105    * The #GdkDeviceManager the #GdkDevice pertains to.
106    *
107    * Since: 3.0
108    */
109   g_object_class_install_property (object_class,
110                                    PROP_DEVICE_MANAGER,
111                                    g_param_spec_object ("device-manager",
112                                                         P_("Device manager"),
113                                                         P_("Device manager which the device belongs to"),
114                                                         GDK_TYPE_DEVICE_MANAGER,
115                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
116                                                         G_PARAM_STATIC_STRINGS));
117   /**
118    * GdkDevice:name:
119    *
120    * The device name.
121    *
122    * Since: 3.0
123    */
124   g_object_class_install_property (object_class,
125                                    PROP_NAME,
126                                    g_param_spec_string ("name",
127                                                         P_("Device name"),
128                                                         P_("Device name"),
129                                                         NULL,
130                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
131                                                         G_PARAM_STATIC_STRINGS));
132   /**
133    * GdkDevice:type:
134    *
135    * Device role in the device manager.
136    *
137    * Since: 3.0
138    */
139   g_object_class_install_property (object_class,
140                                    PROP_TYPE,
141                                    g_param_spec_enum ("type",
142                                                       P_("Device type"),
143                                                       P_("Device role in the device manager"),
144                                                       GDK_TYPE_DEVICE_TYPE,
145                                                       GDK_DEVICE_TYPE_MASTER,
146                                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
147                                                       G_PARAM_STATIC_STRINGS));
148   /**
149    * GdkDevice:associated-device:
150    *
151    * Associated pointer or keyboard with this device, if any. Devices of type #GDK_DEVICE_TYPE_MASTER
152    * always come in keyboard/pointer pairs. Other device types will have a %NULL associated device.
153    *
154    * Since: 3.0
155    */
156   g_object_class_install_property (object_class,
157                                    PROP_ASSOCIATED_DEVICE,
158                                    g_param_spec_object ("associated-device",
159                                                         P_("Associated device"),
160                                                         P_("Associated pointer or keyboard with this device"),
161                                                         GDK_TYPE_DEVICE,
162                                                         G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
163   /**
164    * GdkDevice:input-source:
165    *
166    * Source type for the device.
167    *
168    * Since: 3.0
169    */
170   g_object_class_install_property (object_class,
171                                    PROP_INPUT_SOURCE,
172                                    g_param_spec_enum ("input-source",
173                                                       P_("Input source"),
174                                                       P_("Source type for the device"),
175                                                       GDK_TYPE_INPUT_SOURCE,
176                                                       GDK_SOURCE_MOUSE,
177                                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
178                                                       G_PARAM_STATIC_STRINGS));
179   /**
180    * GdkDevice:input-mode:
181    *
182    * Input mode for the device.
183    *
184    * Since: 3.0
185    */
186   g_object_class_install_property (object_class,
187                                    PROP_INPUT_MODE,
188                                    g_param_spec_enum ("input-mode",
189                                                       P_("Input mode for the device"),
190                                                       P_("Input mode for the device"),
191                                                       GDK_TYPE_INPUT_MODE,
192                                                       GDK_MODE_DISABLED,
193                                                       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
194   /**
195    * GdkDevice:has-cursor:
196    *
197    * Whether the device is represented by a cursor on the screen. Devices of type
198    * %GDK_DEVICE_TYPE_MASTER will have %TRUE here.
199    *
200    * Since: 3.0
201    */
202   g_object_class_install_property (object_class,
203                                    PROP_HAS_CURSOR,
204                                    g_param_spec_boolean ("has-cursor",
205                                                          P_("Whether the device has a cursor"),
206                                                          P_("Whether there is a visible cursor following device motion"),
207                                                          FALSE,
208                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
209                                                          G_PARAM_STATIC_STRINGS));
210   /**
211    * GdkDevice:n-axes:
212    *
213    * Number of axes in the device.
214    *
215    * Since: 3.0
216    */
217   g_object_class_install_property (object_class,
218                                    PROP_N_AXES,
219                                    g_param_spec_uint ("n-axes",
220                                                       P_("Number of axes in the device"),
221                                                       P_("Number of axes in the device"),
222                                                       0, G_MAXUINT, 0,
223                                                       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
224
225   /**
226    * GdkDevice::changed:
227    * @device: the #GdkDevice that changed.
228    *
229    * The ::changed signal is emitted either when the #GdkDevice
230    * has changed the number of either axes or keys. For example
231    * In X this will normally happen when the slave device routing
232    * events through the master device changes (for example, user
233    * switches from the USB mouse to a tablet), in that case the
234    * master device will change to reflect the new slave device
235    * axes and keys.
236    */
237   signals[CHANGED] =
238     g_signal_new (g_intern_static_string ("changed"),
239                   G_TYPE_FROM_CLASS (object_class),
240                   G_SIGNAL_RUN_LAST,
241                   0, NULL, NULL,
242                   g_cclosure_marshal_VOID__VOID,
243                   G_TYPE_NONE, 0);
244 }
245
246 static void
247 gdk_device_init (GdkDevice *device)
248 {
249   device->axes = g_array_new (FALSE, TRUE, sizeof (GdkAxisInfo));
250 }
251
252 static void
253 gdk_device_dispose (GObject *object)
254 {
255   GdkDevice *device = GDK_DEVICE (object);
256
257   if (device->type == GDK_DEVICE_TYPE_SLAVE)
258     _gdk_device_remove_slave (device->associated, device);
259
260   if (device->associated)
261     {
262       _gdk_device_set_associated_device (device->associated, NULL);
263       g_object_unref (device->associated);
264       device->associated = NULL;
265     }
266
267   if (device->axes)
268     {
269       g_array_free (device->axes, TRUE);
270       device->axes = NULL;
271     }
272
273   g_free (device->name);
274   g_free (device->keys);
275
276   device->name = NULL;
277   device->keys = NULL;
278
279   G_OBJECT_CLASS (gdk_device_parent_class)->dispose (object);
280 }
281
282 static void
283 gdk_device_set_property (GObject      *object,
284                          guint         prop_id,
285                          const GValue *value,
286                          GParamSpec   *pspec)
287 {
288   GdkDevice *device = GDK_DEVICE (object);
289
290   switch (prop_id)
291     {
292     case PROP_DISPLAY:
293       device->display = g_value_get_object (value);
294       break;
295     case PROP_DEVICE_MANAGER:
296       device->manager = g_value_get_object (value);
297       break;
298     case PROP_NAME:
299       if (device->name)
300         g_free (device->name);
301
302       device->name = g_value_dup_string (value);
303       break;
304     case PROP_TYPE:
305       device->type = g_value_get_enum (value);
306       break;
307     case PROP_INPUT_SOURCE:
308       device->source = g_value_get_enum (value);
309       break;
310     case PROP_INPUT_MODE:
311       gdk_device_set_mode (device, g_value_get_enum (value));
312       break;
313     case PROP_HAS_CURSOR:
314       device->has_cursor = g_value_get_boolean (value);
315       break;
316     default:
317       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
318       break;
319     }
320 }
321
322 static void
323 gdk_device_get_property (GObject    *object,
324                          guint       prop_id,
325                          GValue     *value,
326                          GParamSpec *pspec)
327 {
328   GdkDevice *device = GDK_DEVICE (object);
329
330   switch (prop_id)
331     {
332     case PROP_DISPLAY:
333       g_value_set_object (value, device->display);
334       break;
335     case PROP_DEVICE_MANAGER:
336       g_value_set_object (value, device->manager);
337       break;
338     case PROP_ASSOCIATED_DEVICE:
339       g_value_set_object (value, device->associated);
340       break;
341     case PROP_NAME:
342       g_value_set_string (value, device->name);
343       break;
344     case PROP_TYPE:
345       g_value_set_enum (value, device->type);
346       break;
347     case PROP_INPUT_SOURCE:
348       g_value_set_enum (value, device->source);
349       break;
350     case PROP_INPUT_MODE:
351       g_value_set_enum (value, device->mode);
352       break;
353     case PROP_HAS_CURSOR:
354       g_value_set_boolean (value, device->has_cursor);
355       break;
356     case PROP_N_AXES:
357       g_value_set_uint (value, device->axes->len);
358       break;
359     default:
360       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
361       break;
362     }
363 }
364
365 /**
366  * gdk_device_get_state:
367  * @device: a #GdkDevice.
368  * @window: a #GdkWindow.
369  * @axes: an array of doubles to store the values of the axes of @device in,
370  * or %NULL.
371  * @mask: location to store the modifiers, or %NULL.
372  *
373  * Gets the current state of a pointer device relative to @window.
374  */
375 void
376 gdk_device_get_state (GdkDevice       *device,
377                       GdkWindow       *window,
378                       gdouble         *axes,
379                       GdkModifierType *mask)
380 {
381   g_return_if_fail (GDK_IS_DEVICE (device));
382   g_return_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD);
383   g_return_if_fail (GDK_IS_WINDOW (window));
384
385   if (GDK_DEVICE_GET_CLASS (device)->get_state)
386     GDK_DEVICE_GET_CLASS (device)->get_state (device, window, axes, mask);
387 }
388
389 /**
390  * gdk_device_get_history:
391  * @device: a #GdkDevice
392  * @window: the window with respect to which which the event coordinates will be reported
393  * @start: starting timestamp for range of events to return
394  * @stop: ending timestamp for the range of events to return
395  * @events: (array length=n_events) (out) (transfer none): location to store a newly-allocated array of #GdkTimeCoord, or %NULL
396  * @n_events: location to store the length of @events, or %NULL
397  *
398  * Obtains the motion history for a pointer device; given a starting and
399  * ending timestamp, return all events in the motion history for
400  * the device in the given range of time. Some windowing systems
401  * do not support motion history, in which case, %FALSE will
402  * be returned. (This is not distinguishable from the case where
403  * motion history is supported and no events were found.)
404  *
405  * Return value: %TRUE if the windowing system supports motion history and
406  *  at least one event was found.
407  **/
408 gboolean
409 gdk_device_get_history (GdkDevice      *device,
410                         GdkWindow      *window,
411                         guint32         start,
412                         guint32         stop,
413                         GdkTimeCoord ***events,
414                         gint           *n_events)
415 {
416   g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
417   g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, FALSE);
418   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
419
420   if (n_events)
421     *n_events = 0;
422
423   if (events)
424     *events = NULL;
425
426   if (GDK_WINDOW_DESTROYED (window))
427     return FALSE;
428
429   if (!GDK_DEVICE_GET_CLASS (device)->get_history)
430     return FALSE;
431
432   return GDK_DEVICE_GET_CLASS (device)->get_history (device, window,
433                                                      start, stop,
434                                                      events, n_events);
435 }
436
437 GdkTimeCoord **
438 _gdk_device_allocate_history (GdkDevice *device,
439                               gint       n_events)
440 {
441   GdkTimeCoord **result = g_new (GdkTimeCoord *, n_events);
442   gint i;
443
444   for (i = 0; i < n_events; i++)
445     result[i] = g_malloc (sizeof (GdkTimeCoord) -
446                           sizeof (double) * (GDK_MAX_TIMECOORD_AXES - device->axes->len));
447   return result;
448 }
449
450 /**
451  * gdk_device_free_history:
452  * @events: (inout) (transfer none): an array of #GdkTimeCoord.
453  * @n_events: the length of the array.
454  *
455  * Frees an array of #GdkTimeCoord that was returned by gdk_device_get_history().
456  */
457 void
458 gdk_device_free_history (GdkTimeCoord **events,
459                          gint           n_events)
460 {
461   gint i;
462
463   for (i = 0; i < n_events; i++)
464     g_free (events[i]);
465
466   g_free (events);
467 }
468
469 /**
470  * gdk_device_get_name:
471  * @device: a #GdkDevice
472  *
473  * Determines the name of the device.
474  *
475  * Return value: a name
476  *
477  * Since: 2.20
478  **/
479 const gchar *
480 gdk_device_get_name (GdkDevice *device)
481 {
482   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
483
484   return device->name;
485 }
486
487 /**
488  * gdk_device_get_has_cursor:
489  * @device: a #GdkDevice
490  *
491  * Determines whether the pointer follows device motion.
492  *
493  * Return value: %TRUE if the pointer follows device motion
494  *
495  * Since: 2.20
496  **/
497 gboolean
498 gdk_device_get_has_cursor (GdkDevice *device)
499 {
500   g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
501   g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, FALSE);
502
503   return device->has_cursor;
504 }
505
506 /**
507  * gdk_device_get_source:
508  * @device: a #GdkDevice
509  *
510  * Determines the type of the device.
511  *
512  * Return value: a #GdkInputSource
513  *
514  * Since: 2.20
515  **/
516 GdkInputSource
517 gdk_device_get_source (GdkDevice *device)
518 {
519   g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
520
521   return device->source;
522 }
523
524 /**
525  * gdk_device_set_source:
526  * @device: a #GdkDevice.
527  * @source: the source type.
528  *
529  * Sets the source type for an input device.
530  **/
531 void
532 gdk_device_set_source (GdkDevice      *device,
533                        GdkInputSource  source)
534 {
535   g_return_if_fail (GDK_IS_DEVICE (device));
536
537   device->source = source;
538   g_object_notify (G_OBJECT (device), "input-source");
539 }
540
541 /**
542  * gdk_device_get_mode:
543  * @device: a #GdkDevice
544  *
545  * Determines the mode of the device.
546  *
547  * Return value: a #GdkInputSource
548  *
549  * Since: 2.20
550  **/
551 GdkInputMode
552 gdk_device_get_mode (GdkDevice *device)
553 {
554   g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
555
556   return device->mode;
557 }
558
559 /**
560  * gdk_device_set_mode:
561  * @device: a #GdkDevice.
562  * @mode: the input mode.
563  *
564  * Sets a the mode of an input device. The mode controls if the
565  * device is active and whether the device's range is mapped to the
566  * entire screen or to a single window.
567  *
568  * Returns: %TRUE if the mode was successfully changed.
569  **/
570 gboolean
571 gdk_device_set_mode (GdkDevice    *device,
572                      GdkInputMode  mode)
573 {
574   g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
575
576   if (device->mode == mode)
577     return TRUE;
578
579   if (mode == GDK_MODE_DISABLED &&
580       gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER)
581     return FALSE;
582
583   device->mode = mode;
584   g_object_notify (G_OBJECT (device), "input-mode");
585
586   return TRUE;
587 }
588
589 /**
590  * gdk_device_get_n_keys:
591  * @device: a #GdkDevice
592  *
593  * Returns the number of keys the device currently has.
594  *
595  * Returns: the number of keys.
596  *
597  * Since: 2.24
598  **/
599 gint
600 gdk_device_get_n_keys (GdkDevice *device)
601 {
602   g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
603
604   return device->num_keys;
605 }
606
607 /**
608  * gdk_device_get_key:
609  * @device: a #GdkDevice.
610  * @index_: the index of the macro button to get.
611  * @keyval: return value for the keyval.
612  * @modifiers: return value for modifiers.
613  *
614  * If @index_ has a valid keyval, this function will return %TRUE
615  * and fill in @keyval and @modifiers with the keyval settings.
616  *
617  * Returns: %TRUE if keyval is set for @index.
618  *
619  * Since: 2.20
620  **/
621 gboolean
622 gdk_device_get_key (GdkDevice       *device,
623                     guint            index_,
624                     guint           *keyval,
625                     GdkModifierType *modifiers)
626 {
627   g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
628   g_return_val_if_fail (index_ < device->num_keys, FALSE);
629
630   if (!device->keys[index_].keyval &&
631       !device->keys[index_].modifiers)
632     return FALSE;
633
634   if (keyval)
635     *keyval = device->keys[index_].keyval;
636
637   if (modifiers)
638     *modifiers = device->keys[index_].modifiers;
639
640   return TRUE;
641 }
642
643 /**
644  * gdk_device_set_key:
645  * @device: a #GdkDevice
646  * @index_: the index of the macro button to set
647  * @keyval: the keyval to generate
648  * @modifiers: the modifiers to set
649  *
650  * Specifies the X key event to generate when a macro button of a device
651  * is pressed.
652  **/
653 void
654 gdk_device_set_key (GdkDevice      *device,
655                     guint           index_,
656                     guint           keyval,
657                     GdkModifierType modifiers)
658 {
659   g_return_if_fail (GDK_IS_DEVICE (device));
660   g_return_if_fail (index_ < device->num_keys);
661
662   device->keys[index_].keyval = keyval;
663   device->keys[index_].modifiers = modifiers;
664 }
665
666 /**
667  * gdk_device_get_axis_use:
668  * @device: a pointer #GdkDevice.
669  * @index_: the index of the axis.
670  *
671  * Returns the axis use for @index_.
672  *
673  * Returns: a #GdkAxisUse specifying how the axis is used.
674  *
675  * Since: 2.20
676  **/
677 GdkAxisUse
678 gdk_device_get_axis_use (GdkDevice *device,
679                          guint      index_)
680 {
681   GdkAxisInfo *info;
682
683   g_return_val_if_fail (GDK_IS_DEVICE (device), GDK_AXIS_IGNORE);
684   g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, GDK_AXIS_IGNORE);
685   g_return_val_if_fail (index_ < device->axes->len, GDK_AXIS_IGNORE);
686
687   info = &g_array_index (device->axes, GdkAxisInfo, index_);
688
689   return info->use;
690 }
691
692 /**
693  * gdk_device_set_axis_use:
694  * @device: a pointer #GdkDevice
695  * @index_: the index of the axis
696  * @use: specifies how the axis is used
697  *
698  * Specifies how an axis of a device is used.
699  **/
700 void
701 gdk_device_set_axis_use (GdkDevice   *device,
702                          guint        index_,
703                          GdkAxisUse   use)
704 {
705   GdkAxisInfo *info;
706
707   g_return_if_fail (GDK_IS_DEVICE (device));
708   g_return_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD);
709   g_return_if_fail (index_ < device->axes->len);
710
711   info = &g_array_index (device->axes, GdkAxisInfo, index_);
712   info->use = use;
713
714   switch (use)
715     {
716     case GDK_AXIS_X:
717     case GDK_AXIS_Y:
718       info->min_axis = 0;
719       info->max_axis = 0;
720       break;
721     case GDK_AXIS_XTILT:
722     case GDK_AXIS_YTILT:
723       info->min_axis = -1;
724       info->max_axis = 1;
725       break;
726     default:
727       info->min_axis = 0;
728       info->max_axis = 1;
729       break;
730     }
731 }
732
733 /**
734  * gdk_device_get_display:
735  * @device: a #GdkDevice
736  *
737  * Returns the #GdkDisplay to which @device pertains.
738  *
739  * Returns: (transfer none): a #GdkDisplay. This memory is owned
740  *          by GTK+, and must not be freed or unreffed.
741  *
742  * Since: 3.0
743  **/
744 GdkDisplay *
745 gdk_device_get_display (GdkDevice *device)
746 {
747   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
748
749   return device->display;
750 }
751
752 /**
753  * gdk_device_get_associated_device:
754  * @device: a #GdkDevice
755  *
756  * Returns the associated device to @device, if @device is of type
757  * %GDK_DEVICE_TYPE_MASTER, it will return the paired pointer or
758  * keyboard.
759  *
760  * If @device is of type %GDK_DEVICE_TYPE_SLAVE, it will return
761  * the master device to which @device is attached to.
762  *
763  * If @device is of type %GDK_DEVICE_TYPE_FLOATING, %NULL will be
764  * returned, as there is no associated device.
765  *
766  * Returns: (transfer none): The associated device, or %NULL
767  *
768  * Since: 3.0
769  **/
770 GdkDevice *
771 gdk_device_get_associated_device (GdkDevice *device)
772 {
773   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
774
775   return device->associated;
776 }
777
778 static void
779 _gdk_device_set_device_type (GdkDevice     *device,
780                              GdkDeviceType  type)
781 {
782   if (device->type != type)
783     {
784       device->type = type;
785
786       g_object_notify (G_OBJECT (device), "type");
787     }
788 }
789
790 void
791 _gdk_device_set_associated_device (GdkDevice *device,
792                                    GdkDevice *associated)
793 {
794   g_return_if_fail (GDK_IS_DEVICE (device));
795   g_return_if_fail (associated == NULL || GDK_IS_DEVICE (associated));
796
797   if (device->associated == associated)
798     return;
799
800   if (device->associated)
801     {
802       g_object_unref (device->associated);
803       device->associated = NULL;
804     }
805
806   if (associated)
807     device->associated = g_object_ref (associated);
808
809   if (device->type != GDK_DEVICE_TYPE_MASTER)
810     {
811       if (device->associated)
812         _gdk_device_set_device_type (device, GDK_DEVICE_TYPE_SLAVE);
813       else
814         _gdk_device_set_device_type (device, GDK_DEVICE_TYPE_FLOATING);
815     }
816 }
817
818 /**
819  * gdk_device_list_slave_devices:
820  * @device: a #GdkDevice
821  *
822  * If the device if of type %GDK_DEVICE_TYPE_MASTER, it will return
823  * the list of slave devices attached to it, otherwise it will return
824  * %NULL
825  *
826  * Returns: (transfer container): the list of slave devices, or %NULL. The
827  *          list must be freed with g_list_free(), the contents of the list
828  *          are owned by GTK+ and should not be freed.
829  **/
830 GList *
831 gdk_device_list_slave_devices (GdkDevice *device)
832 {
833   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
834   g_return_val_if_fail (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER, NULL);
835
836   return g_list_copy (device->slaves);
837 }
838
839 void
840 _gdk_device_add_slave (GdkDevice *device,
841                        GdkDevice *slave)
842 {
843   g_return_if_fail (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER);
844   g_return_if_fail (gdk_device_get_device_type (slave) != GDK_DEVICE_TYPE_MASTER);
845
846   if (!g_list_find (device->slaves, slave))
847     device->slaves = g_list_prepend (device->slaves, slave);
848 }
849
850 void
851 _gdk_device_remove_slave (GdkDevice *device,
852                           GdkDevice *slave)
853 {
854   GList *elem;
855
856   g_return_if_fail (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER);
857   g_return_if_fail (gdk_device_get_device_type (slave) != GDK_DEVICE_TYPE_MASTER);
858
859   elem = g_list_find (device->slaves, slave);
860
861   if (!elem)
862     return;
863
864   device->slaves = g_list_delete_link (device->slaves, elem);
865 }
866
867 /**
868  * gdk_device_get_device_type:
869  * @device: a #GdkDevice
870  *
871  * Returns the device type for @device.
872  *
873  * Returns: the #GdkDeviceType for @device.
874  *
875  * Since: 3.0
876  **/
877 GdkDeviceType
878 gdk_device_get_device_type (GdkDevice *device)
879 {
880   g_return_val_if_fail (GDK_IS_DEVICE (device), GDK_DEVICE_TYPE_MASTER);
881
882   return device->type;
883 }
884
885 /**
886  * gdk_device_get_n_axes:
887  * @device: a pointer #GdkDevice
888  *
889  * Returns the number of axes the device currently has.
890  *
891  * Returns: the number of axes.
892  *
893  * Since: 3.0
894  **/
895 gint
896 gdk_device_get_n_axes (GdkDevice *device)
897 {
898   g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
899   g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, 0);
900
901   return device->axes->len;
902 }
903
904 /**
905  * gdk_device_list_axes:
906  * @device: a pointer #GdkDevice
907  *
908  * Returns a #GList of #GdkAtom<!-- -->s, containing the labels for
909  * the axes that @device currently has.
910  *
911  * Returns: (transfer container) (element-type GdkAtom):
912  *     A #GList of #GdkAtom<!-- -->s, free with g_list_free().
913  *
914  * Since: 3.0
915  **/
916 GList *
917 gdk_device_list_axes (GdkDevice *device)
918 {
919   GList *axes = NULL;
920   gint i;
921
922   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
923   g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, NULL);
924
925   for (i = 0; i < device->axes->len; i++)
926     {
927       GdkAxisInfo axis_info;
928
929       axis_info = g_array_index (device->axes, GdkAxisInfo, i);
930       axes = g_list_prepend (axes, GDK_ATOM_TO_POINTER (axis_info.label));
931     }
932
933   return g_list_reverse (axes);
934 }
935
936 /**
937  * gdk_device_get_axis_value:
938  * @device: a pointer #GdkDevice.
939  * @axes: pointer to an array of axes
940  * @axis_label: #GdkAtom with the axis label.
941  * @value: location to store the found value.
942  *
943  * Interprets an array of double as axis values for a given device,
944  * and locates the value in the array for a given axis label, as returned
945  * by gdk_device_list_axes()
946  *
947  * Returns: %TRUE if the given axis use was found, otherwise %FALSE.
948  *
949  * Since: 3.0
950  **/
951 gboolean
952 gdk_device_get_axis_value (GdkDevice *device,
953                            gdouble   *axes,
954                            GdkAtom    axis_label,
955                            gdouble   *value)
956 {
957   gint i;
958
959   g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
960   g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, FALSE);
961
962   if (axes == NULL)
963     return FALSE;
964
965   for (i = 0; i < device->axes->len; i++)
966     {
967       GdkAxisInfo axis_info;
968
969       axis_info = g_array_index (device->axes, GdkAxisInfo, i);
970
971       if (axis_info.label != axis_label)
972         continue;
973
974       if (value)
975         *value = axes[i];
976
977       return TRUE;
978     }
979
980   return FALSE;
981 }
982
983 /**
984  * gdk_device_get_axis:
985  * @device: a #GdkDevice
986  * @axes: pointer to an array of axes
987  * @use: the use to look for
988  * @value: location to store the found value.
989  *
990  * Interprets an array of double as axis values for a given device,
991  * and locates the value in the array for a given axis use.
992  *
993  * Return value: %TRUE if the given axis use was found, otherwise %FALSE
994  **/
995 gboolean
996 gdk_device_get_axis (GdkDevice  *device,
997                      gdouble    *axes,
998                      GdkAxisUse  use,
999                      gdouble    *value)
1000 {
1001   gint i;
1002
1003   g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
1004   g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, FALSE);
1005
1006   if (axes == NULL)
1007     return FALSE;
1008
1009   g_return_val_if_fail (device->axes != NULL, FALSE);
1010
1011   for (i = 0; i < device->axes->len; i++)
1012     {
1013       GdkAxisInfo axis_info;
1014
1015       axis_info = g_array_index (device->axes, GdkAxisInfo, i);
1016
1017       if (axis_info.use != use)
1018         continue;
1019
1020       if (value)
1021         *value = axes[i];
1022
1023       return TRUE;
1024     }
1025
1026   return FALSE;
1027 }
1028
1029 static GdkEventMask
1030 get_native_grab_event_mask (GdkEventMask grab_mask)
1031 {
1032   /* Similar to the above but for pointer events only */
1033   return
1034     GDK_POINTER_MOTION_MASK |
1035     GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1036     GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
1037     GDK_SCROLL_MASK |
1038     (grab_mask &
1039      ~(GDK_POINTER_MOTION_HINT_MASK |
1040        GDK_BUTTON_MOTION_MASK |
1041        GDK_BUTTON1_MOTION_MASK |
1042        GDK_BUTTON2_MOTION_MASK |
1043        GDK_BUTTON3_MOTION_MASK));
1044 }
1045
1046 /**
1047  * gdk_device_grab:
1048  * @device: a #GdkDevice
1049  * @window: the #GdkWindow which will own the grab (the grab window)
1050  * @grab_ownership: specifies the grab ownership.
1051  * @owner_events: if %FALSE then all device events are reported with respect to
1052  *                @window and are only reported if selected by @event_mask. If
1053  *                %TRUE then pointer events for this application are reported
1054  *                as normal, but pointer events outside this application are
1055  *                reported with respect to @window and only if selected by
1056  *                @event_mask. In either mode, unreported events are discarded.
1057  * @event_mask: specifies the event mask, which is used in accordance with
1058  *              @owner_events.
1059  * @cursor: the cursor to display while the grab is active if the device is
1060  *          a pointer. If this is %NULL then the normal cursors are used for
1061  *          @window and its descendants, and the cursor for @window is used
1062  *          elsewhere.
1063  * @time_: the timestamp of the event which led to this pointer grab. This
1064  *         usually comes from the #GdkEvent struct, though %GDK_CURRENT_TIME
1065  *         can be used if the time isn't known.
1066  *
1067  * Grabs the device so that all events coming from this device are passed to
1068  * this application until the device is ungrabbed with gdk_device_ungrab(),
1069  * or the window becomes unviewable. This overrides any previous grab on the device
1070  * by this client.
1071  *
1072  * Device grabs are used for operations which need complete control over the
1073  * given device events (either pointer or keyboard). For example in GTK+ this
1074  * is used for Drag and Drop operations, popup menus and such.
1075  *
1076  * Note that if the event mask of an X window has selected both button press
1077  * and button release events, then a button press event will cause an automatic
1078  * pointer grab until the button is released. X does this automatically since
1079  * most applications expect to receive button press and release events in pairs.
1080  * It is equivalent to a pointer grab on the window with @owner_events set to
1081  * %TRUE.
1082  *
1083  * If you set up anything at the time you take the grab that needs to be
1084  * cleaned up when the grab ends, you should handle the #GdkEventGrabBroken
1085  * events that are emitted when the grab ends unvoluntarily.
1086  *
1087  * Returns: %GDK_GRAB_SUCCESS if the grab was successful.
1088  *
1089  * Since: 3.0
1090  **/
1091 GdkGrabStatus
1092 gdk_device_grab (GdkDevice        *device,
1093                  GdkWindow        *window,
1094                  GdkGrabOwnership  grab_ownership,
1095                  gboolean          owner_events,
1096                  GdkEventMask      event_mask,
1097                  GdkCursor        *cursor,
1098                  guint32           time_)
1099 {
1100   GdkGrabStatus res;
1101   GdkWindow *native;
1102
1103   g_return_val_if_fail (GDK_IS_DEVICE (device), GDK_GRAB_SUCCESS);
1104   g_return_val_if_fail (GDK_IS_WINDOW (window), GDK_GRAB_SUCCESS);
1105
1106   if (_gdk_native_windows)
1107     native = window;
1108   else
1109     native = gdk_window_get_toplevel (window);
1110
1111   while (native->window_type == GDK_WINDOW_OFFSCREEN)
1112     {
1113       native = gdk_offscreen_window_get_embedder (native);
1114
1115       if (native == NULL ||
1116           (!_gdk_window_has_impl (native) &&
1117            !gdk_window_is_viewable (native)))
1118         return GDK_GRAB_NOT_VIEWABLE;
1119
1120       native = gdk_window_get_toplevel (native);
1121     }
1122
1123   if (native == NULL || GDK_WINDOW_DESTROYED (native))
1124     return GDK_GRAB_NOT_VIEWABLE;
1125
1126   res = GDK_DEVICE_GET_CLASS (device)->grab (device,
1127                                              native,
1128                                              owner_events,
1129                                              get_native_grab_event_mask (event_mask),
1130                                              NULL,
1131                                              cursor,
1132                                              time_);
1133
1134   if (res == GDK_GRAB_SUCCESS)
1135     {
1136       GdkDisplay *display;
1137       gulong serial;
1138
1139       display = gdk_window_get_display (window);
1140       serial = _gdk_windowing_window_get_next_serial (display);
1141
1142       _gdk_display_add_device_grab (display,
1143                                     device,
1144                                     window,
1145                                     native,
1146                                     grab_ownership,
1147                                     owner_events,
1148                                     event_mask,
1149                                     serial,
1150                                     time_,
1151                                     FALSE);
1152     }
1153
1154   return res;
1155 }
1156
1157 /**
1158  * gdk_device_ungrab:
1159  * @device: a #GdkDevice
1160  * @time_: a timestap (e.g. %GDK_CURRENT_TIME).
1161  *
1162  * Release any grab on @device.
1163  *
1164  * Since: 3.0
1165  */
1166 void
1167 gdk_device_ungrab (GdkDevice  *device,
1168                    guint32     time_)
1169 {
1170   g_return_if_fail (GDK_IS_DEVICE (device));
1171
1172   GDK_DEVICE_GET_CLASS (device)->ungrab (device, time_);
1173 }
1174
1175 /* Private API */
1176 void
1177 _gdk_device_reset_axes (GdkDevice *device)
1178 {
1179   gint i;
1180
1181   for (i = device->axes->len - 1; i >= 0; i--)
1182     g_array_remove_index (device->axes, i);
1183
1184   g_object_notify (G_OBJECT (device), "n-axes");
1185 }
1186
1187 guint
1188 _gdk_device_add_axis (GdkDevice   *device,
1189                       GdkAtom      label_atom,
1190                       GdkAxisUse   use,
1191                       gdouble      min_value,
1192                       gdouble      max_value,
1193                       gdouble      resolution)
1194 {
1195   GdkAxisInfo axis_info;
1196   guint pos;
1197
1198   axis_info.use = use;
1199   axis_info.label = label_atom;
1200   axis_info.min_value = min_value;
1201   axis_info.max_value = max_value;
1202   axis_info.resolution = resolution;
1203
1204   switch (use)
1205     {
1206     case GDK_AXIS_X:
1207     case GDK_AXIS_Y:
1208       axis_info.min_axis = 0;
1209       axis_info.max_axis = 0;
1210       break;
1211     case GDK_AXIS_XTILT:
1212     case GDK_AXIS_YTILT:
1213       axis_info.min_axis = -1;
1214       axis_info.max_axis = 1;
1215       break;
1216     default:
1217       axis_info.min_axis = 0;
1218       axis_info.max_axis = 1;
1219       break;
1220     }
1221
1222   device->axes = g_array_append_val (device->axes, axis_info);
1223   pos = device->axes->len - 1;
1224
1225   g_object_notify (G_OBJECT (device), "n-axes");
1226
1227   return pos;
1228 }
1229
1230 void
1231 _gdk_device_set_keys (GdkDevice *device,
1232                       guint      num_keys)
1233 {
1234   if (device->keys)
1235     g_free (device->keys);
1236
1237   device->num_keys = num_keys;
1238   device->keys = g_new0 (GdkDeviceKey, num_keys);
1239 }
1240
1241 static GdkAxisInfo *
1242 find_axis_info (GArray     *array,
1243                 GdkAxisUse  use)
1244 {
1245   GdkAxisInfo *info;
1246   gint i;
1247
1248   for (i = 0; i < GDK_AXIS_LAST; i++)
1249     {
1250       info = &g_array_index (array, GdkAxisInfo, i);
1251
1252       if (info->use == use)
1253         return info;
1254     }
1255
1256   return NULL;
1257 }
1258
1259 GdkAxisUse
1260 _gdk_device_get_axis_use (GdkDevice *device,
1261                           guint      index_)
1262 {
1263   GdkAxisInfo info;
1264
1265   info = g_array_index (device->axes, GdkAxisInfo, index_);
1266   return info.use;
1267 }
1268
1269 gboolean
1270 _gdk_device_translate_window_coord (GdkDevice *device,
1271                                     GdkWindow *window,
1272                                     guint      index_,
1273                                     gdouble    value,
1274                                     gdouble   *axis_value)
1275 {
1276   GdkAxisInfo axis_info;
1277   GdkAxisInfo *axis_info_x, *axis_info_y;
1278   gdouble device_width, device_height;
1279   gdouble x_offset, y_offset;
1280   gdouble x_scale, y_scale;
1281   gdouble x_min, y_min;
1282   gdouble x_resolution, y_resolution;
1283   gdouble device_aspect;
1284   gint window_width, window_height;
1285
1286   if (index_ >= device->axes->len)
1287     return FALSE;
1288
1289   axis_info = g_array_index (device->axes, GdkAxisInfo, index_);
1290
1291   if (axis_info.use != GDK_AXIS_X &&
1292       axis_info.use != GDK_AXIS_Y)
1293     return FALSE;
1294
1295   if (axis_info.use == GDK_AXIS_X)
1296     {
1297       axis_info_x = &axis_info;
1298       axis_info_y = find_axis_info (device->axes, GDK_AXIS_Y);
1299     }
1300   else
1301     {
1302       axis_info_x = find_axis_info (device->axes, GDK_AXIS_X);
1303       axis_info_y = &axis_info;
1304     }
1305
1306   device_width = axis_info_x->max_value - axis_info_x->min_value;
1307   device_height = axis_info_y->max_value - axis_info_y->min_value;
1308
1309   if (device_width > 0)
1310     x_min = axis_info_x->min_value;
1311   else
1312     {
1313       device_width = gdk_screen_get_width (gdk_window_get_screen (window));
1314       x_min = 0;
1315     }
1316
1317   if (device_height > 0)
1318     y_min = axis_info_y->min_value;
1319   else
1320     {
1321       device_height = gdk_screen_get_height (gdk_window_get_screen (window));
1322       y_min = 0;
1323     }
1324
1325   window_width = gdk_window_get_width (window);
1326   window_height = gdk_window_get_height (window);
1327
1328   x_resolution = axis_info_x->resolution;
1329   y_resolution = axis_info_y->resolution;
1330
1331   /*
1332    * Some drivers incorrectly report the resolution of the device
1333    * as zero (in partiular linuxwacom < 0.5.3 with usb tablets).
1334    * This causes the device_aspect to become NaN and totally
1335    * breaks windowed mode.  If this is the case, the best we can
1336    * do is to assume the resolution is non-zero is equal in both
1337    * directions (which is true for many devices).  The absolute
1338    * value of the resolution doesn't matter since we only use the
1339    * ratio.
1340    */
1341   if (x_resolution == 0 || y_resolution == 0)
1342     {
1343       x_resolution = 1;
1344       y_resolution = 1;
1345     }
1346
1347   device_aspect = (device_height * y_resolution) /
1348     (device_width * x_resolution);
1349
1350   if (device_aspect * window_width >= window_height)
1351     {
1352       /* device taller than window */
1353       x_scale = window_width / device_width;
1354       y_scale = (x_scale * x_resolution) / y_resolution;
1355
1356       x_offset = 0;
1357       y_offset = - (device_height * y_scale - window_height) / 2;
1358     }
1359   else
1360     {
1361       /* window taller than device */
1362       y_scale = window_height / device_height;
1363       x_scale = (y_scale * y_resolution) / x_resolution;
1364
1365       y_offset = 0;
1366       x_offset = - (device_width * x_scale - window_width) / 2;
1367     }
1368
1369   if (axis_value)
1370     {
1371       if (axis_info.use == GDK_AXIS_X)
1372         *axis_value = x_offset + x_scale * (value - x_min);
1373       else
1374         *axis_value = y_offset + y_scale * (value - y_min);
1375     }
1376
1377   return TRUE;
1378 }
1379
1380 gboolean
1381 _gdk_device_translate_screen_coord (GdkDevice *device,
1382                                     GdkWindow *window,
1383                                     gint       window_root_x,
1384                                     gint       window_root_y,
1385                                     guint      index_,
1386                                     gdouble    value,
1387                                     gdouble   *axis_value)
1388 {
1389   GdkAxisInfo axis_info;
1390   gdouble axis_width, scale, offset;
1391
1392   if (device->mode != GDK_MODE_SCREEN)
1393     return FALSE;
1394
1395   if (index_ >= device->axes->len)
1396     return FALSE;
1397
1398   axis_info = g_array_index (device->axes, GdkAxisInfo, index_);
1399
1400   if (axis_info.use != GDK_AXIS_X &&
1401       axis_info.use != GDK_AXIS_Y)
1402     return FALSE;
1403
1404   axis_width = axis_info.max_value - axis_info.min_value;
1405
1406   if (axis_info.use == GDK_AXIS_X)
1407     {
1408       if (axis_width > 0)
1409         scale = gdk_screen_get_width (gdk_window_get_screen (window)) / axis_width;
1410       else
1411         scale = 1;
1412
1413       offset = - window_root_x - window->abs_x;
1414     }
1415   else
1416     {
1417       if (axis_width > 0)
1418         scale = gdk_screen_get_height (gdk_window_get_screen (window)) / axis_width;
1419       else
1420         scale = 1;
1421
1422       offset = - window_root_y - window->abs_y;
1423     }
1424
1425   if (axis_value)
1426     *axis_value = offset + scale * (value - axis_info.min_value);
1427
1428   return TRUE;
1429 }
1430
1431 gboolean
1432 _gdk_device_translate_axis (GdkDevice *device,
1433                             guint      index_,
1434                             gdouble    value,
1435                             gdouble   *axis_value)
1436 {
1437   GdkAxisInfo axis_info;
1438   gdouble axis_width, out;
1439
1440   if (index_ >= device->axes->len)
1441     return FALSE;
1442
1443   axis_info = g_array_index (device->axes, GdkAxisInfo, index_);
1444
1445   if (axis_info.use == GDK_AXIS_X ||
1446       axis_info.use == GDK_AXIS_Y)
1447     return FALSE;
1448
1449   axis_width = axis_info.max_value - axis_info.min_value;
1450   out = (axis_info.max_axis * (value - axis_info.min_value) +
1451          axis_info.min_axis * (axis_info.max_value - value)) / axis_width;
1452
1453   if (axis_value)
1454     *axis_value = out;
1455
1456   return TRUE;
1457 }
1458