1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Copyright © 2009, 2010, 2011  Intel Corp.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20  *
21  * Author: Emmanuele Bassi <ebassi@linux.intel.com>
22  */
23 
24 /**
25  * SECTION:clutter-input-device
26  * @short_description: An input device managed by Clutter
27  *
28  * #ClutterInputDevice represents an input device known to Clutter.
29  *
30  * The #ClutterInputDevice class holds the state of the device, but
31  * its contents are usually defined by the Clutter backend in use.
32  */
33 
34 #ifdef HAVE_CONFIG_H
35 #include "clutter-build-config.h"
36 #endif
37 
38 #include "clutter-input-device.h"
39 
40 #include "clutter-actor-private.h"
41 #include "clutter-debug.h"
42 #include "clutter-device-manager-private.h"
43 #include "clutter-enum-types.h"
44 #include "clutter-event-private.h"
45 #include "clutter-marshal.h"
46 #include "clutter-private.h"
47 #include "clutter-stage-private.h"
48 #include "clutter-input-device-tool.h"
49 
50 #include <math.h>
51 
52 enum
53 {
54   PROP_0,
55 
56   PROP_BACKEND,
57 
58   PROP_ID,
59   PROP_NAME,
60 
61   PROP_DEVICE_TYPE,
62   PROP_DEVICE_MANAGER,
63   PROP_DEVICE_MODE,
64 
65   PROP_HAS_CURSOR,
66   PROP_ENABLED,
67 
68   PROP_N_AXES,
69 
70   PROP_VENDOR_ID,
71   PROP_PRODUCT_ID,
72 
73   PROP_N_STRIPS,
74   PROP_N_RINGS,
75   PROP_N_MODE_GROUPS,
76   PROP_DEVICE_NODE,
77   PROP_MAPPING_MODE,
78 
79   PROP_LAST
80 };
81 
82 static void _clutter_input_device_free_touch_info (gpointer data);
83 static void on_cursor_actor_destroy (ClutterActor       *actor,
84                                      ClutterInputDevice *device);
85 static void on_cursor_actor_reactive_changed (ClutterActor       *actor,
86                                               GParamSpec         *pspec,
87                                               ClutterInputDevice *device);
88 
89 static GParamSpec *obj_props[PROP_LAST] = { NULL, };
90 
91 G_DEFINE_TYPE (ClutterInputDevice, clutter_input_device, G_TYPE_OBJECT);
92 
93 static void
clutter_input_device_dispose(GObject * gobject)94 clutter_input_device_dispose (GObject *gobject)
95 {
96   ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (gobject);
97 
98   g_clear_pointer (&device->device_name, free);
99   g_clear_pointer (&device->vendor_id, free);
100   g_clear_pointer (&device->product_id, free);
101 
102   if (device->associated != NULL)
103     {
104       if (device->device_mode == CLUTTER_INPUT_MODE_SLAVE)
105         _clutter_input_device_remove_slave (device->associated, device);
106 
107       _clutter_input_device_set_associated_device (device->associated, NULL);
108       g_object_unref (device->associated);
109       device->associated = NULL;
110     }
111 
112   g_clear_pointer (&device->axes, g_array_unref);
113   g_clear_pointer (&device->keys, g_array_unref);
114   g_clear_pointer (&device->scroll_info, g_array_unref);
115   g_clear_pointer (&device->touch_sequences_info, g_hash_table_unref);
116 
117   if (device->cursor_actor)
118     {
119       g_signal_handlers_disconnect_by_func (device->cursor_actor,
120                                             G_CALLBACK (on_cursor_actor_destroy),
121                                             device);
122       g_signal_handlers_disconnect_by_func (device->cursor_actor,
123                                             G_CALLBACK (on_cursor_actor_reactive_changed),
124                                             device);
125       _clutter_actor_set_has_pointer (device->cursor_actor, FALSE);
126       device->cursor_actor = NULL;
127     }
128 
129   if (device->inv_touch_sequence_actors)
130     {
131       GHashTableIter iter;
132       gpointer key, value;
133 
134       g_hash_table_iter_init (&iter, device->inv_touch_sequence_actors);
135       while (g_hash_table_iter_next (&iter, &key, &value))
136         {
137           g_signal_handlers_disconnect_by_func (key,
138                                                 G_CALLBACK (on_cursor_actor_destroy),
139                                                 device);
140           g_signal_handlers_disconnect_by_func (device->cursor_actor,
141                                                 G_CALLBACK (on_cursor_actor_reactive_changed),
142                                                 device);
143           _clutter_actor_set_has_pointer (key, FALSE);
144           g_list_free (value);
145         }
146 
147       g_hash_table_unref (device->inv_touch_sequence_actors);
148       device->inv_touch_sequence_actors = NULL;
149     }
150 
151   G_OBJECT_CLASS (clutter_input_device_parent_class)->dispose (gobject);
152 }
153 
154 static void
clutter_input_device_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * pspec)155 clutter_input_device_set_property (GObject      *gobject,
156                                    guint         prop_id,
157                                    const GValue *value,
158                                    GParamSpec   *pspec)
159 {
160   ClutterInputDevice *self = CLUTTER_INPUT_DEVICE (gobject);
161 
162   switch (prop_id)
163     {
164     case PROP_ID:
165       self->id = g_value_get_int (value);
166       break;
167 
168     case PROP_DEVICE_TYPE:
169       self->device_type = g_value_get_enum (value);
170       break;
171 
172     case PROP_DEVICE_MANAGER:
173       self->device_manager = g_value_get_object (value);
174       break;
175 
176     case PROP_DEVICE_MODE:
177       self->device_mode = g_value_get_enum (value);
178       break;
179 
180     case PROP_BACKEND:
181       self->backend = g_value_get_object (value);
182       break;
183 
184     case PROP_NAME:
185       self->device_name = g_value_dup_string (value);
186       break;
187 
188     case PROP_HAS_CURSOR:
189       self->has_cursor = g_value_get_boolean (value);
190       break;
191 
192     case PROP_ENABLED:
193       clutter_input_device_set_enabled (self, g_value_get_boolean (value));
194       break;
195 
196     case PROP_VENDOR_ID:
197       self->vendor_id = g_value_dup_string (value);
198       break;
199 
200     case PROP_PRODUCT_ID:
201       self->product_id = g_value_dup_string (value);
202       break;
203 
204     case PROP_N_RINGS:
205       self->n_rings = g_value_get_int (value);
206       break;
207 
208     case PROP_N_STRIPS:
209       self->n_strips = g_value_get_int (value);
210       break;
211 
212     case PROP_N_MODE_GROUPS:
213       self->n_mode_groups = g_value_get_int (value);
214       break;
215 
216     case PROP_DEVICE_NODE:
217       self->node_path = g_value_dup_string (value);
218       break;
219 
220     case PROP_MAPPING_MODE:
221       self->mapping_mode = g_value_get_enum (value);
222       break;
223 
224     default:
225       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
226       break;
227     }
228 }
229 
230 static void
clutter_input_device_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * pspec)231 clutter_input_device_get_property (GObject    *gobject,
232                                    guint       prop_id,
233                                    GValue     *value,
234                                    GParamSpec *pspec)
235 {
236   ClutterInputDevice *self = CLUTTER_INPUT_DEVICE (gobject);
237 
238   switch (prop_id)
239     {
240     case PROP_ID:
241       g_value_set_int (value, self->id);
242       break;
243 
244     case PROP_DEVICE_TYPE:
245       g_value_set_enum (value, self->device_type);
246       break;
247 
248     case PROP_DEVICE_MANAGER:
249       g_value_set_object (value, self->device_manager);
250       break;
251 
252     case PROP_DEVICE_MODE:
253       g_value_set_enum (value, self->device_mode);
254       break;
255 
256     case PROP_BACKEND:
257       g_value_set_object (value, self->backend);
258       break;
259 
260     case PROP_NAME:
261       g_value_set_string (value, self->device_name);
262       break;
263 
264     case PROP_HAS_CURSOR:
265       g_value_set_boolean (value, self->has_cursor);
266       break;
267 
268     case PROP_N_AXES:
269       g_value_set_uint (value, clutter_input_device_get_n_axes (self));
270       break;
271 
272     case PROP_ENABLED:
273       g_value_set_boolean (value, self->is_enabled);
274       break;
275 
276     case PROP_VENDOR_ID:
277       g_value_set_string (value, self->vendor_id);
278       break;
279 
280     case PROP_PRODUCT_ID:
281       g_value_set_string (value, self->product_id);
282       break;
283 
284     case PROP_N_RINGS:
285       g_value_set_int (value, self->n_rings);
286       break;
287 
288     case PROP_N_STRIPS:
289       g_value_set_int (value, self->n_strips);
290       break;
291 
292     case PROP_N_MODE_GROUPS:
293       g_value_set_int (value, self->n_mode_groups);
294       break;
295 
296     case PROP_DEVICE_NODE:
297       g_value_set_string (value, self->node_path);
298       break;
299 
300     case PROP_MAPPING_MODE:
301       g_value_set_enum (value, self->mapping_mode);
302       break;
303 
304     default:
305       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
306       break;
307     }
308 }
309 
310 static void
clutter_input_device_class_init(ClutterInputDeviceClass * klass)311 clutter_input_device_class_init (ClutterInputDeviceClass *klass)
312 {
313   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
314 
315   /**
316    * ClutterInputDevice:id:
317    *
318    * The unique identifier of the device
319    *
320    * Since: 1.2
321    */
322   obj_props[PROP_ID] =
323     g_param_spec_int ("id",
324                       P_("Id"),
325                       P_("Unique identifier of the device"),
326                       -1, G_MAXINT,
327                       0,
328                       CLUTTER_PARAM_READWRITE |
329                       G_PARAM_CONSTRUCT_ONLY);
330 
331   /**
332    * ClutterInputDevice:name:
333    *
334    * The name of the device
335    *
336    * Since: 1.2
337    */
338   obj_props[PROP_NAME] =
339     g_param_spec_string ("name",
340                          P_("Name"),
341                          P_("The name of the device"),
342                          NULL,
343                          CLUTTER_PARAM_READWRITE |
344                          G_PARAM_CONSTRUCT_ONLY);
345 
346   /**
347    * ClutterInputDevice:device-type:
348    *
349    * The type of the device
350    *
351    * Since: 1.2
352    */
353   obj_props[PROP_DEVICE_TYPE] =
354     g_param_spec_enum ("device-type",
355                        P_("Device Type"),
356                        P_("The type of the device"),
357                        CLUTTER_TYPE_INPUT_DEVICE_TYPE,
358                        CLUTTER_POINTER_DEVICE,
359                        CLUTTER_PARAM_READWRITE |
360                        G_PARAM_CONSTRUCT_ONLY);
361 
362   /**
363    * ClutterInputDevice:device-manager:
364    *
365    * The #ClutterDeviceManager instance which owns the device
366    *
367    * Since: 1.6
368    */
369   obj_props[PROP_DEVICE_MANAGER] =
370     g_param_spec_object ("device-manager",
371                          P_("Device Manager"),
372                          P_("The device manager instance"),
373                          CLUTTER_TYPE_DEVICE_MANAGER,
374                          CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
375 
376   /**
377    * ClutterInputDevice:mode:
378    *
379    * The mode of the device.
380    *
381    * Since: 1.6
382    */
383   obj_props[PROP_DEVICE_MODE] =
384     g_param_spec_enum ("device-mode",
385                        P_("Device Mode"),
386                        P_("The mode of the device"),
387                        CLUTTER_TYPE_INPUT_MODE,
388                        CLUTTER_INPUT_MODE_FLOATING,
389                        CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
390 
391   /**
392    * ClutterInputDevice:has-cursor:
393    *
394    * Whether the device has an on screen cursor following its movement.
395    *
396    * Since: 1.6
397    */
398   obj_props[PROP_HAS_CURSOR] =
399     g_param_spec_boolean ("has-cursor",
400                           P_("Has Cursor"),
401                           P_("Whether the device has a cursor"),
402                           FALSE,
403                           CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
404 
405   /**
406    * ClutterInputDevice:enabled:
407    *
408    * Whether the device is enabled.
409    *
410    * A device with the #ClutterInputDevice:device-mode property set
411    * to %CLUTTER_INPUT_MODE_MASTER cannot be disabled.
412    *
413    * A device must be enabled in order to receive events from it.
414    *
415    * Since: 1.6
416    */
417   obj_props[PROP_ENABLED] =
418     g_param_spec_boolean ("enabled",
419                           P_("Enabled"),
420                           P_("Whether the device is enabled"),
421                           FALSE,
422                           CLUTTER_PARAM_READWRITE);
423 
424   /**
425    * ClutterInputDevice:n-axes:
426    *
427    * The number of axes of the device.
428    *
429    * Since: 1.6
430    */
431   obj_props[PROP_N_AXES] =
432     g_param_spec_uint ("n-axes",
433                        P_("Number of Axes"),
434                        P_("The number of axes on the device"),
435                        0, G_MAXUINT,
436                        0,
437                        CLUTTER_PARAM_READABLE);
438 
439   /**
440    * ClutterInputDevice:backend:
441    *
442    * The #ClutterBackend that created the device.
443    *
444    * Since: 1.6
445    */
446   obj_props[PROP_BACKEND] =
447     g_param_spec_object ("backend",
448                          P_("Backend"),
449                          P_("The backend instance"),
450                          CLUTTER_TYPE_BACKEND,
451                          CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
452 
453   /**
454    * ClutterInputDevice:vendor-id:
455    *
456    * Vendor ID of this device.
457    *
458    * Since: 1.22
459    */
460   obj_props[PROP_VENDOR_ID] =
461     g_param_spec_string ("vendor-id",
462                          P_("Vendor ID"),
463                          P_("Vendor ID"),
464                          NULL,
465                          CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
466 
467   /**
468    * ClutterInputDevice:product-id:
469    *
470    * Product ID of this device.
471    *
472    * Since: 1.22
473    */
474   obj_props[PROP_PRODUCT_ID] =
475     g_param_spec_string ("product-id",
476                          P_("Product ID"),
477                          P_("Product ID"),
478                          NULL,
479                          CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
480 
481   obj_props[PROP_N_RINGS] =
482     g_param_spec_int ("n-rings",
483                       P_("Number of rings"),
484                       P_("Number of rings (circular sliders) in this device"),
485                       0, G_MAXINT, 0,
486                       CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
487 
488   obj_props[PROP_N_STRIPS] =
489     g_param_spec_int ("n-strips",
490                       P_("Number of strips"),
491                       P_("Number of strips (linear sliders) in this device"),
492                       0, G_MAXINT, 0,
493                       CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
494 
495   obj_props[PROP_N_MODE_GROUPS] =
496     g_param_spec_int ("n-mode-groups",
497                       P_("Number of mode groups"),
498                       P_("Number of mode groups"),
499                       0, G_MAXINT, 0,
500                       CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
501 
502   obj_props[PROP_DEVICE_NODE] =
503     g_param_spec_string ("device-node",
504                          P_("Device node path"),
505                          P_("Device node path"),
506                          NULL,
507                          CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
508 
509   obj_props[PROP_MAPPING_MODE] =
510     g_param_spec_enum ("mapping-mode",
511                        P_("Device mapping mode"),
512                        P_("Device mapping mode"),
513                        CLUTTER_TYPE_INPUT_DEVICE_MAPPING,
514                        CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE,
515                        CLUTTER_PARAM_READWRITE);
516 
517   gobject_class->dispose = clutter_input_device_dispose;
518   gobject_class->set_property = clutter_input_device_set_property;
519   gobject_class->get_property = clutter_input_device_get_property;
520   g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
521 }
522 
523 static void
clutter_input_device_init(ClutterInputDevice * self)524 clutter_input_device_init (ClutterInputDevice *self)
525 {
526   self->id = -1;
527   self->device_type = CLUTTER_POINTER_DEVICE;
528 
529   self->click_count = 0;
530 
531   self->current_time = self->previous_time = CLUTTER_CURRENT_TIME;
532   self->current_x = self->previous_x = -1;
533   self->current_y = self->previous_y = -1;
534   self->current_button_number = self->previous_button_number = -1;
535   self->current_state = self->previous_state = 0;
536 
537   self->touch_sequences_info =
538     g_hash_table_new_full (NULL, NULL,
539                            NULL, _clutter_input_device_free_touch_info);
540   self->inv_touch_sequence_actors = g_hash_table_new (NULL, NULL);
541 }
542 
543 static ClutterTouchInfo *
_clutter_input_device_ensure_touch_info(ClutterInputDevice * device,ClutterEventSequence * sequence,ClutterStage * stage)544 _clutter_input_device_ensure_touch_info (ClutterInputDevice *device,
545                                          ClutterEventSequence *sequence,
546                                          ClutterStage *stage)
547 {
548   ClutterTouchInfo *info;
549 
550   info = g_hash_table_lookup (device->touch_sequences_info, sequence);
551 
552   if (info == NULL)
553     {
554       info = g_slice_new0 (ClutterTouchInfo);
555       info->sequence = sequence;
556       g_hash_table_insert (device->touch_sequences_info, sequence, info);
557 
558       if (g_hash_table_size (device->touch_sequences_info) == 1)
559         _clutter_input_device_set_stage (device, stage);
560     }
561 
562   return info;
563 }
564 
565 /*< private >
566  * clutter_input_device_set_coords:
567  * @device: a #ClutterInputDevice
568  * @sequence: a #ClutterEventSequence or NULL
569  * @x: X coordinate of the device
570  * @y: Y coordinate of the device
571  *
572  * Stores the last known coordinates of the device
573  */
574 void
_clutter_input_device_set_coords(ClutterInputDevice * device,ClutterEventSequence * sequence,gfloat x,gfloat y,ClutterStage * stage)575 _clutter_input_device_set_coords (ClutterInputDevice   *device,
576                                   ClutterEventSequence *sequence,
577                                   gfloat                x,
578                                   gfloat                y,
579                                   ClutterStage         *stage)
580 {
581   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
582 
583   if (sequence == NULL)
584     {
585       if (device->current_x != x)
586         device->current_x = x;
587 
588       if (device->current_y != y)
589         device->current_y = y;
590     }
591   else
592     {
593       ClutterTouchInfo *info;
594       info = _clutter_input_device_ensure_touch_info (device, sequence, stage);
595       info->current_x = x;
596       info->current_y = y;
597     }
598 }
599 
600 /*< private >
601  * clutter_input_device_set_state:
602  * @device: a #ClutterInputDevice
603  * @state: a bitmask of modifiers
604  *
605  * Stores the last known modifiers state of the device
606  */
607 void
_clutter_input_device_set_state(ClutterInputDevice * device,ClutterModifierType state)608 _clutter_input_device_set_state (ClutterInputDevice  *device,
609                                  ClutterModifierType  state)
610 {
611   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
612 
613   device->current_state = state;
614 }
615 
616 /**
617  * clutter_input_device_get_modifier_state:
618  * @device: a #ClutterInputDevice
619  *
620  * Retrieves the current modifiers state of the device, as seen
621  * by the last event Clutter processed.
622  *
623  * Return value: the last known modifier state
624  *
625  * Since: 1.16
626  */
627 ClutterModifierType
clutter_input_device_get_modifier_state(ClutterInputDevice * device)628 clutter_input_device_get_modifier_state (ClutterInputDevice *device)
629 {
630   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
631 
632   return device->current_state;
633 }
634 
635 /*< private >
636  * clutter_input_device_set_time:
637  * @device: a #ClutterInputDevice
638  * @time_: the time
639  *
640  * Stores the last known event time of the device
641  */
642 void
_clutter_input_device_set_time(ClutterInputDevice * device,guint32 time_)643 _clutter_input_device_set_time (ClutterInputDevice *device,
644                                 guint32             time_)
645 {
646   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
647 
648   if (device->current_time != time_)
649     device->current_time = time_;
650 }
651 
652 /*< private >
653  * clutter_input_device_set_stage:
654  * @device: a #ClutterInputDevice
655  * @stage: a #ClutterStage or %NULL
656  *
657  * Stores the stage under the device
658  */
659 void
_clutter_input_device_set_stage(ClutterInputDevice * device,ClutterStage * stage)660 _clutter_input_device_set_stage (ClutterInputDevice *device,
661                                  ClutterStage       *stage)
662 {
663   if (device->stage == stage)
664     return;
665 
666   device->stage = stage;
667 
668   /* we leave the ->cursor_actor in place in order to check
669    * if we left the stage without crossing it again; this way
670    * we can emit a leave event on the cursor actor right before
671    * we emit the leave event on the stage.
672    */
673 }
674 
675 /*< private >
676  * clutter_input_device_get_stage:
677  * @device: a #ClutterInputDevice
678  *
679  * Retrieves the stage currently associated with @device.
680  *
681  * Return value: The stage currently associated with @device.
682  */
683 ClutterStage *
_clutter_input_device_get_stage(ClutterInputDevice * device)684 _clutter_input_device_get_stage (ClutterInputDevice *device)
685 {
686   return device->stage;
687 }
688 
689 static void
_clutter_input_device_free_touch_info(gpointer data)690 _clutter_input_device_free_touch_info (gpointer data)
691 {
692   g_slice_free (ClutterTouchInfo, data);
693 }
694 
695 static ClutterActor *
_clutter_input_device_get_actor(ClutterInputDevice * device,ClutterEventSequence * sequence)696 _clutter_input_device_get_actor (ClutterInputDevice   *device,
697                                  ClutterEventSequence *sequence)
698 {
699   ClutterTouchInfo *info;
700 
701   if (sequence == NULL)
702     return device->cursor_actor;
703 
704   info = g_hash_table_lookup (device->touch_sequences_info, sequence);
705 
706   return info->actor;
707 }
708 
709 static void
_clutter_input_device_associate_actor(ClutterInputDevice * device,ClutterEventSequence * sequence,ClutterActor * actor)710 _clutter_input_device_associate_actor (ClutterInputDevice   *device,
711                                        ClutterEventSequence *sequence,
712                                        ClutterActor         *actor)
713 {
714   if (sequence == NULL)
715     device->cursor_actor = actor;
716   else
717     {
718       GList *sequences =
719         g_hash_table_lookup (device->inv_touch_sequence_actors, actor);
720       ClutterTouchInfo *info;
721       ClutterStage *stage = CLUTTER_STAGE (clutter_actor_get_stage (actor));
722 
723       info = _clutter_input_device_ensure_touch_info (device, sequence, stage);
724       info->actor = actor;
725 
726       g_hash_table_insert (device->inv_touch_sequence_actors,
727                            actor, g_list_prepend (sequences, sequence));
728     }
729 
730   g_signal_connect (actor,
731                     "destroy", G_CALLBACK (on_cursor_actor_destroy),
732                     device);
733   g_signal_connect (actor,
734                     "notify::reactive", G_CALLBACK (on_cursor_actor_reactive_changed),
735                     device);
736   _clutter_actor_set_has_pointer (actor, TRUE);
737 }
738 
739 static void
_clutter_input_device_unassociate_actor(ClutterInputDevice * device,ClutterActor * actor,gboolean destroyed)740 _clutter_input_device_unassociate_actor (ClutterInputDevice   *device,
741                                          ClutterActor         *actor,
742                                          gboolean              destroyed)
743 {
744   if (device->cursor_actor == actor)
745     device->cursor_actor = NULL;
746   else
747     {
748       GList *l, *sequences =
749         g_hash_table_lookup (device->inv_touch_sequence_actors,
750                              actor);
751 
752       for (l = sequences; l != NULL; l = l->next)
753         {
754           ClutterTouchInfo *info =
755             g_hash_table_lookup (device->touch_sequences_info, l->data);
756 
757           if (info)
758             info->actor = NULL;
759         }
760 
761       g_list_free (sequences);
762       g_hash_table_remove (device->inv_touch_sequence_actors, actor);
763     }
764 
765   if (destroyed == FALSE)
766     {
767       g_signal_handlers_disconnect_by_func (actor,
768                                             G_CALLBACK (on_cursor_actor_destroy),
769                                             device);
770       g_signal_handlers_disconnect_by_func (actor,
771                                             G_CALLBACK (on_cursor_actor_reactive_changed),
772                                             device);
773       _clutter_actor_set_has_pointer (actor, FALSE);
774     }
775 }
776 
777 static void
on_cursor_actor_destroy(ClutterActor * actor,ClutterInputDevice * device)778 on_cursor_actor_destroy (ClutterActor       *actor,
779                          ClutterInputDevice *device)
780 {
781   _clutter_input_device_unassociate_actor (device, actor, TRUE);
782 }
783 
784 static void
on_cursor_actor_reactive_changed(ClutterActor * actor,GParamSpec * pspec,ClutterInputDevice * device)785 on_cursor_actor_reactive_changed (ClutterActor       *actor,
786                                   GParamSpec         *pspec,
787                                   ClutterInputDevice *device)
788 {
789   if (!clutter_actor_get_reactive (actor))
790     _clutter_input_device_unassociate_actor (device, actor, FALSE);
791 }
792 
793 /*< private >
794  * clutter_input_device_set_actor:
795  * @device: a #ClutterInputDevice
796  * @actor: a #ClutterActor
797  * @emit_crossing: %TRUE to emit crossing events
798  *
799  * Sets the actor under the pointer coordinates of @device
800  *
801  * This function is called by _clutter_input_device_update()
802  * and it will:
803  *
804  *   - queue a %CLUTTER_LEAVE event on the previous pointer actor
805  *     of @device, if any
806  *   - set to %FALSE the :has-pointer property of the previous
807  *     pointer actor of @device, if any
808  *   - queue a %CLUTTER_ENTER event on the new pointer actor
809  *   - set to %TRUE the :has-pointer property of the new pointer
810  *     actor
811  */
812 void
_clutter_input_device_set_actor(ClutterInputDevice * device,ClutterEventSequence * sequence,ClutterActor * actor,gboolean emit_crossing)813 _clutter_input_device_set_actor (ClutterInputDevice   *device,
814                                  ClutterEventSequence *sequence,
815                                  ClutterActor         *actor,
816                                  gboolean              emit_crossing)
817 {
818   ClutterActor *old_actor = _clutter_input_device_get_actor (device, sequence);
819 
820   if (old_actor == actor)
821     return;
822 
823   if (old_actor != NULL)
824     {
825       ClutterActor *tmp_old_actor;
826 
827       if (emit_crossing)
828         {
829           ClutterEvent *event;
830 
831           event = clutter_event_new (CLUTTER_LEAVE);
832           event->crossing.time = device->current_time;
833           event->crossing.flags = 0;
834           event->crossing.stage = device->stage;
835           event->crossing.source = old_actor;
836           event->crossing.x = device->current_x;
837           event->crossing.y = device->current_y;
838           event->crossing.related = actor;
839           clutter_event_set_device (event, device);
840 
841           /* we need to make sure that this event is processed
842            * before any other event we might have queued up until
843            * now, so we go on, and synthesize the event emission
844            * ourselves
845            */
846           _clutter_process_event (event);
847 
848           clutter_event_free (event);
849         }
850 
851       /* processing the event might have destroyed the actor */
852       tmp_old_actor = _clutter_input_device_get_actor (device, sequence);
853       _clutter_input_device_unassociate_actor (device,
854                                                old_actor,
855                                                tmp_old_actor == NULL);
856       old_actor = tmp_old_actor;
857     }
858 
859   if (actor != NULL)
860     {
861       _clutter_input_device_associate_actor (device, sequence, actor);
862 
863       if (emit_crossing)
864         {
865           ClutterEvent *event;
866 
867           event = clutter_event_new (CLUTTER_ENTER);
868           event->crossing.time = device->current_time;
869           event->crossing.flags = 0;
870           event->crossing.stage = device->stage;
871           event->crossing.x = device->current_x;
872           event->crossing.y = device->current_y;
873           event->crossing.source = actor;
874           event->crossing.related = old_actor;
875           clutter_event_set_device (event, device);
876 
877           /* see above */
878           _clutter_process_event (event);
879 
880           clutter_event_free (event);
881         }
882     }
883 }
884 
885 /**
886  * clutter_input_device_get_device_type:
887  * @device: a #ClutterInputDevice
888  *
889  * Retrieves the type of @device
890  *
891  * Return value: the type of the device
892  *
893  * Since: 1.0
894  */
895 ClutterInputDeviceType
clutter_input_device_get_device_type(ClutterInputDevice * device)896 clutter_input_device_get_device_type (ClutterInputDevice *device)
897 {
898   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
899                         CLUTTER_POINTER_DEVICE);
900 
901   return device->device_type;
902 }
903 
904 /**
905  * clutter_input_device_get_device_id:
906  * @device: a #ClutterInputDevice
907  *
908  * Retrieves the unique identifier of @device
909  *
910  * Return value: the identifier of the device
911  *
912  * Since: 1.0
913  */
914 gint
clutter_input_device_get_device_id(ClutterInputDevice * device)915 clutter_input_device_get_device_id (ClutterInputDevice *device)
916 {
917   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), -1);
918 
919   return device->id;
920 }
921 
922 /**
923  * clutter_input_device_set_enabled:
924  * @device: a #ClutterInputDevice
925  * @enabled: %TRUE to enable the @device
926  *
927  * Enables or disables a #ClutterInputDevice.
928  *
929  * Only devices with a #ClutterInputDevice:device-mode property set
930  * to %CLUTTER_INPUT_MODE_SLAVE or %CLUTTER_INPUT_MODE_FLOATING can
931  * be disabled.
932  *
933  * Since: 1.6
934  */
935 void
clutter_input_device_set_enabled(ClutterInputDevice * device,gboolean enabled)936 clutter_input_device_set_enabled (ClutterInputDevice *device,
937                                   gboolean            enabled)
938 {
939   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
940 
941   enabled = !!enabled;
942 
943   if (!enabled && device->device_mode == CLUTTER_INPUT_MODE_MASTER)
944     return;
945 
946   if (device->is_enabled == enabled)
947     return;
948 
949   device->is_enabled = enabled;
950 
951   g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_ENABLED]);
952 }
953 
954 /**
955  * clutter_input_device_get_enabled:
956  * @device: a #ClutterInputDevice
957  *
958  * Retrieves whether @device is enabled.
959  *
960  * Return value: %TRUE if the device is enabled
961  *
962  * Since: 1.6
963  */
964 gboolean
clutter_input_device_get_enabled(ClutterInputDevice * device)965 clutter_input_device_get_enabled (ClutterInputDevice *device)
966 {
967   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
968 
969   return device->is_enabled;
970 }
971 
972 /**
973  * clutter_input_device_get_coords:
974  * @device: a #ClutterInputDevice
975  * @sequence: (allow-none): a #ClutterEventSequence, or %NULL if
976  *   the device is not touch-based
977  * @point: (out caller-allocates): return location for the pointer
978  *   or touch point
979  *
980  * Retrieves the latest coordinates of a pointer or touch point of
981  * @device.
982  *
983  * Return value: %FALSE if the device's sequence hasn't been found,
984  *   and %TRUE otherwise.
985  *
986  * Since: 1.12
987  */
988 gboolean
clutter_input_device_get_coords(ClutterInputDevice * device,ClutterEventSequence * sequence,ClutterPoint * point)989 clutter_input_device_get_coords (ClutterInputDevice   *device,
990                                  ClutterEventSequence *sequence,
991                                  ClutterPoint         *point)
992 {
993   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
994   g_return_val_if_fail (point != NULL, FALSE);
995 
996   if (sequence == NULL)
997     {
998       point->x = device->current_x;
999       point->y = device->current_y;
1000     }
1001   else
1002     {
1003       ClutterTouchInfo *info =
1004         g_hash_table_lookup (device->touch_sequences_info, sequence);
1005 
1006       if (info == NULL)
1007         return FALSE;
1008 
1009       point->x = info->current_x;
1010       point->y = info->current_y;
1011     }
1012 
1013   return TRUE;
1014 }
1015 
1016 /*
1017  * _clutter_input_device_update:
1018  * @device: a #ClutterInputDevice
1019  *
1020  * Updates the input @device by determining the #ClutterActor underneath the
1021  * pointer's cursor
1022  *
1023  * This function calls _clutter_input_device_set_actor() if needed.
1024  *
1025  * This function only works for #ClutterInputDevice of type
1026  * %CLUTTER_POINTER_DEVICE.
1027  *
1028  * Since: 1.2
1029  */
1030 ClutterActor *
_clutter_input_device_update(ClutterInputDevice * device,ClutterEventSequence * sequence,gboolean emit_crossing)1031 _clutter_input_device_update (ClutterInputDevice   *device,
1032                               ClutterEventSequence *sequence,
1033                               gboolean              emit_crossing)
1034 {
1035   ClutterStage *stage;
1036   ClutterActor *new_cursor_actor;
1037   ClutterActor *old_cursor_actor;
1038   ClutterPoint point = { -1, -1 };
1039 
1040   if (device->device_type == CLUTTER_KEYBOARD_DEVICE)
1041     return NULL;
1042 
1043   stage = device->stage;
1044   if (G_UNLIKELY (stage == NULL))
1045     {
1046       CLUTTER_NOTE (EVENT, "No stage defined for device %d '%s'",
1047                     clutter_input_device_get_device_id (device),
1048                     clutter_input_device_get_device_name (device));
1049       return NULL;
1050     }
1051 
1052   clutter_input_device_get_coords (device, sequence, &point);
1053 
1054   old_cursor_actor = _clutter_input_device_get_actor (device, sequence);
1055   new_cursor_actor =
1056     _clutter_stage_do_pick (stage, point.x, point.y, CLUTTER_PICK_REACTIVE);
1057 
1058   /* if the pick could not find an actor then we do not update the
1059    * input device, to avoid ghost enter/leave events; the pick should
1060    * never fail, except for bugs in the glReadPixels() implementation
1061    * in which case this is the safest course of action anyway
1062    */
1063   if (new_cursor_actor == NULL)
1064     return NULL;
1065 
1066   CLUTTER_NOTE (EVENT,
1067                 "Actor under cursor (device %d, at %.2f, %.2f): %s",
1068                 clutter_input_device_get_device_id (device),
1069                 point.x,
1070                 point.y,
1071                 _clutter_actor_get_debug_name (new_cursor_actor));
1072 
1073   /* short-circuit here */
1074   if (new_cursor_actor == old_cursor_actor)
1075     return old_cursor_actor;
1076 
1077   _clutter_input_device_set_actor (device, sequence,
1078                                    new_cursor_actor,
1079                                    emit_crossing);
1080 
1081   return new_cursor_actor;
1082 }
1083 
1084 /**
1085  * clutter_input_device_get_pointer_actor:
1086  * @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE
1087  *
1088  * Retrieves the #ClutterActor underneath the pointer of @device
1089  *
1090  * Return value: (transfer none): a pointer to the #ClutterActor or %NULL
1091  *
1092  * Since: 1.2
1093  */
1094 ClutterActor *
clutter_input_device_get_pointer_actor(ClutterInputDevice * device)1095 clutter_input_device_get_pointer_actor (ClutterInputDevice *device)
1096 {
1097   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
1098   g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, NULL);
1099 
1100   return device->cursor_actor;
1101 }
1102 
1103 /**
1104  * clutter_input_device_get_pointer_stage:
1105  * @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE
1106  *
1107  * Retrieves the #ClutterStage underneath the pointer of @device
1108  *
1109  * Return value: (transfer none): a pointer to the #ClutterStage or %NULL
1110  *
1111  * Since: 1.2
1112  */
1113 ClutterStage *
clutter_input_device_get_pointer_stage(ClutterInputDevice * device)1114 clutter_input_device_get_pointer_stage (ClutterInputDevice *device)
1115 {
1116   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
1117   g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, NULL);
1118 
1119   return device->stage;
1120 }
1121 
1122 /**
1123  * clutter_input_device_get_device_name:
1124  * @device: a #ClutterInputDevice
1125  *
1126  * Retrieves the name of the @device
1127  *
1128  * Return value: the name of the device, or %NULL. The returned string
1129  *   is owned by the #ClutterInputDevice and should never be modified
1130  *   or freed
1131  *
1132  * Since: 1.2
1133  */
1134 const gchar *
clutter_input_device_get_device_name(ClutterInputDevice * device)1135 clutter_input_device_get_device_name (ClutterInputDevice *device)
1136 {
1137   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
1138 
1139   return device->device_name;
1140 }
1141 
1142 /**
1143  * clutter_input_device_get_has_cursor:
1144  * @device: a #ClutterInputDevice
1145  *
1146  * Retrieves whether @device has a pointer that follows the
1147  * device motion.
1148  *
1149  * Return value: %TRUE if the device has a cursor
1150  *
1151  * Since: 1.6
1152  */
1153 gboolean
clutter_input_device_get_has_cursor(ClutterInputDevice * device)1154 clutter_input_device_get_has_cursor (ClutterInputDevice *device)
1155 {
1156   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
1157 
1158   return device->has_cursor;
1159 }
1160 
1161 /**
1162  * clutter_input_device_get_device_mode:
1163  * @device: a #ClutterInputDevice
1164  *
1165  * Retrieves the #ClutterInputMode of @device.
1166  *
1167  * Return value: the device mode
1168  *
1169  * Since: 1.6
1170  */
1171 ClutterInputMode
clutter_input_device_get_device_mode(ClutterInputDevice * device)1172 clutter_input_device_get_device_mode (ClutterInputDevice *device)
1173 {
1174   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
1175                         CLUTTER_INPUT_MODE_FLOATING);
1176 
1177   return device->device_mode;
1178 }
1179 
1180 /**
1181  * clutter_input_device_update_from_event:
1182  * @device: a #ClutterInputDevice
1183  * @event: a #ClutterEvent
1184  * @update_stage: whether to update the #ClutterStage of the @device
1185  *   using the stage of the event
1186  *
1187  * Forcibly updates the state of the @device using a #ClutterEvent
1188  *
1189  * This function should never be used by applications: it is meant
1190  * for integration with embedding toolkits, like clutter-gtk
1191  *
1192  * Embedding toolkits that disable the event collection inside Clutter
1193  * need to use this function to update the state of input devices depending
1194  * on a #ClutterEvent that they are going to submit to the event handling code
1195  * in Clutter though clutter_do_event(). Since the input devices hold the state
1196  * that is going to be used to fill in fields like the #ClutterButtonEvent
1197  * click count, or to emit synthesized events like %CLUTTER_ENTER and
1198  * %CLUTTER_LEAVE, it is necessary for embedding toolkits to also be
1199  * responsible of updating the input device state.
1200  *
1201  * For instance, this might be the code to translate an embedding toolkit
1202  * native motion notification into a Clutter #ClutterMotionEvent and ask
1203  * Clutter to process it:
1204  *
1205  * |[
1206  *   ClutterEvent c_event;
1207  *
1208  *   translate_native_event_to_clutter (native_event, &c_event);
1209  *
1210  *   clutter_do_event (&c_event);
1211  * ]|
1212  *
1213  * Before letting clutter_do_event() process the event, it is necessary to call
1214  * clutter_input_device_update_from_event():
1215  *
1216  * |[
1217  *   ClutterEvent c_event;
1218  *   ClutterDeviceManager *manager;
1219  *   ClutterInputDevice *device;
1220  *
1221  *   translate_native_event_to_clutter (native_event, &c_event);
1222  *
1223  *   // get the device manager
1224  *   manager = clutter_device_manager_get_default ();
1225  *
1226  *   // use the default Core Pointer that Clutter backends register by default
1227  *   device = clutter_device_manager_get_core_device (manager, %CLUTTER_POINTER_DEVICE);
1228  *
1229  *   // update the state of the input device
1230  *   clutter_input_device_update_from_event (device, &c_event, FALSE);
1231  *
1232  *   clutter_do_event (&c_event);
1233  * ]|
1234  *
1235  * The @update_stage boolean argument should be used when the input device
1236  * enters and leaves a #ClutterStage; it will use the #ClutterStage field
1237  * of the passed @event to update the stage associated to the input device.
1238  *
1239  * Since: 1.2
1240  */
1241 void
clutter_input_device_update_from_event(ClutterInputDevice * device,ClutterEvent * event,gboolean update_stage)1242 clutter_input_device_update_from_event (ClutterInputDevice *device,
1243                                         ClutterEvent       *event,
1244                                         gboolean            update_stage)
1245 {
1246   ClutterModifierType event_state;
1247   ClutterEventSequence *sequence;
1248   ClutterStage *event_stage;
1249   gfloat event_x, event_y;
1250   guint32 event_time;
1251 
1252   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
1253   g_return_if_fail (event != NULL);
1254 
1255   event_state = clutter_event_get_state (event);
1256   event_time = clutter_event_get_time (event);
1257   event_stage = clutter_event_get_stage (event);
1258   sequence = clutter_event_get_event_sequence (event);
1259   clutter_event_get_coords (event, &event_x, &event_y);
1260 
1261   _clutter_input_device_set_coords (device, sequence, event_x, event_y, event_stage);
1262   _clutter_input_device_set_state (device, event_state);
1263   _clutter_input_device_set_time (device, event_time);
1264 
1265   if (update_stage)
1266     _clutter_input_device_set_stage (device, event_stage);
1267 }
1268 
1269 /*< private >
1270  * clutter_input_device_reset_axes:
1271  * @device: a #ClutterInputDevice
1272  *
1273  * Resets the axes on @device
1274  */
1275 void
_clutter_input_device_reset_axes(ClutterInputDevice * device)1276 _clutter_input_device_reset_axes (ClutterInputDevice *device)
1277 {
1278   if (device->axes != NULL)
1279     {
1280       g_array_free (device->axes, TRUE);
1281       device->axes = NULL;
1282 
1283       g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_N_AXES]);
1284     }
1285 }
1286 
1287 /*< private >
1288  * clutter_input_device_add_axis:
1289  * @device: a #ClutterInputDevice
1290  * @axis: the axis type
1291  * @minimum: the minimum axis value
1292  * @maximum: the maximum axis value
1293  * @resolution: the axis resolution
1294  *
1295  * Adds an axis of type @axis on @device.
1296  */
1297 guint
_clutter_input_device_add_axis(ClutterInputDevice * device,ClutterInputAxis axis,gdouble minimum,gdouble maximum,gdouble resolution)1298 _clutter_input_device_add_axis (ClutterInputDevice *device,
1299                                 ClutterInputAxis    axis,
1300                                 gdouble             minimum,
1301                                 gdouble             maximum,
1302                                 gdouble             resolution)
1303 {
1304   ClutterAxisInfo info;
1305   guint pos;
1306 
1307   if (device->axes == NULL)
1308     device->axes = g_array_new (FALSE, TRUE, sizeof (ClutterAxisInfo));
1309 
1310   info.axis = axis;
1311   info.min_value = minimum;
1312   info.max_value = maximum;
1313   info.resolution = resolution;
1314 
1315   switch (axis)
1316     {
1317     case CLUTTER_INPUT_AXIS_X:
1318     case CLUTTER_INPUT_AXIS_Y:
1319       info.min_axis = 0;
1320       info.max_axis = 0;
1321       break;
1322 
1323     case CLUTTER_INPUT_AXIS_XTILT:
1324     case CLUTTER_INPUT_AXIS_YTILT:
1325       info.min_axis = -1;
1326       info.max_axis = 1;
1327       break;
1328 
1329     default:
1330       info.min_axis = 0;
1331       info.max_axis = 1;
1332       break;
1333     }
1334 
1335   device->axes = g_array_append_val (device->axes, info);
1336   pos = device->axes->len - 1;
1337 
1338   g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_N_AXES]);
1339 
1340   return pos;
1341 }
1342 
1343 /*< private >
1344  * clutter_input_translate_axis:
1345  * @device: a #ClutterInputDevice
1346  * @index_: the index of the axis
1347  * @gint: the absolute value of the axis
1348  * @axis_value: (out): the translated value of the axis
1349  *
1350  * Performs a conversion from the absolute value of the axis
1351  * to a relative value.
1352  *
1353  * The axis at @index_ must not be %CLUTTER_INPUT_AXIS_X or
1354  * %CLUTTER_INPUT_AXIS_Y.
1355  *
1356  * Return value: %TRUE if the conversion was successful
1357  */
1358 gboolean
_clutter_input_device_translate_axis(ClutterInputDevice * device,guint index_,gdouble value,gdouble * axis_value)1359 _clutter_input_device_translate_axis (ClutterInputDevice *device,
1360                                       guint               index_,
1361                                       gdouble             value,
1362                                       gdouble            *axis_value)
1363 {
1364   ClutterAxisInfo *info;
1365   gdouble width;
1366   gdouble real_value;
1367 
1368   if (device->axes == NULL || index_ >= device->axes->len)
1369     return FALSE;
1370 
1371   info = &g_array_index (device->axes, ClutterAxisInfo, index_);
1372 
1373   if (info->axis == CLUTTER_INPUT_AXIS_X ||
1374       info->axis == CLUTTER_INPUT_AXIS_Y)
1375     return FALSE;
1376 
1377   if (fabs (info->max_value - info->min_value) < 0.0000001)
1378     return FALSE;
1379 
1380   width = info->max_value - info->min_value;
1381   real_value = (info->max_axis * (value - info->min_value)
1382              + info->min_axis * (info->max_value - value))
1383              / width;
1384 
1385   if (axis_value)
1386     *axis_value = real_value;
1387 
1388   return TRUE;
1389 }
1390 
1391 /**
1392  * clutter_input_device_get_axis:
1393  * @device: a #ClutterInputDevice
1394  * @index_: the index of the axis
1395  *
1396  * Retrieves the type of axis on @device at the given index.
1397  *
1398  * Return value: the axis type
1399  *
1400  * Since: 1.6
1401  */
1402 ClutterInputAxis
clutter_input_device_get_axis(ClutterInputDevice * device,guint index_)1403 clutter_input_device_get_axis (ClutterInputDevice *device,
1404                                guint               index_)
1405 {
1406   ClutterAxisInfo *info;
1407 
1408   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
1409                         CLUTTER_INPUT_AXIS_IGNORE);
1410 
1411   if (device->axes == NULL)
1412     return CLUTTER_INPUT_AXIS_IGNORE;
1413 
1414   if (index_ >= device->axes->len)
1415     return CLUTTER_INPUT_AXIS_IGNORE;
1416 
1417   info = &g_array_index (device->axes, ClutterAxisInfo, index_);
1418 
1419   return info->axis;
1420 }
1421 
1422 /**
1423  * clutter_input_device_get_axis_value:
1424  * @device: a #ClutterInputDevice
1425  * @axes: (array): an array of axes values, typically
1426  *   coming from clutter_event_get_axes()
1427  * @axis: the axis to extract
1428  * @value: (out): return location for the axis value
1429  *
1430  * Extracts the value of the given @axis of a #ClutterInputDevice from
1431  * an array of axis values.
1432  *
1433  * An example of typical usage for this function is:
1434  *
1435  * |[
1436  *   ClutterInputDevice *device = clutter_event_get_device (event);
1437  *   gdouble *axes = clutter_event_get_axes (event, NULL);
1438  *   gdouble pressure_value = 0;
1439  *
1440  *   clutter_input_device_get_axis_value (device, axes,
1441  *                                        CLUTTER_INPUT_AXIS_PRESSURE,
1442  *                                        &pressure_value);
1443  * ]|
1444  *
1445  * Return value: %TRUE if the value was set, and %FALSE otherwise
1446  *
1447  * Since: 1.6
1448  */
1449 gboolean
clutter_input_device_get_axis_value(ClutterInputDevice * device,gdouble * axes,ClutterInputAxis axis,gdouble * value)1450 clutter_input_device_get_axis_value (ClutterInputDevice *device,
1451                                      gdouble            *axes,
1452                                      ClutterInputAxis    axis,
1453                                      gdouble            *value)
1454 {
1455   gint i;
1456 
1457   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
1458   g_return_val_if_fail (device->axes != NULL, FALSE);
1459 
1460   for (i = 0; i < device->axes->len; i++)
1461     {
1462       ClutterAxisInfo *info;
1463 
1464       info = &g_array_index (device->axes, ClutterAxisInfo, i);
1465 
1466       if (info->axis == axis)
1467         {
1468           if (value)
1469             *value = axes[i];
1470 
1471           return TRUE;
1472         }
1473     }
1474 
1475   return FALSE;
1476 }
1477 
1478 /**
1479  * clutter_input_device_get_n_axes:
1480  * @device: a #ClutterInputDevice
1481  *
1482  * Retrieves the number of axes available on @device.
1483  *
1484  * Return value: the number of axes on the device
1485  *
1486  * Since: 1.6
1487  */
1488 guint
clutter_input_device_get_n_axes(ClutterInputDevice * device)1489 clutter_input_device_get_n_axes (ClutterInputDevice *device)
1490 {
1491   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
1492 
1493   if (device->axes != NULL)
1494     return device->axes->len;
1495 
1496   return 0;
1497 }
1498 
1499 /*< private >
1500  * clutter_input_device_set_n_keys:
1501  * @device: a #ClutterInputDevice
1502  * @n_keys: the number of keys of the device
1503  *
1504  * Initializes the keys of @device.
1505  *
1506  * Call clutter_input_device_set_key() on each key to set the keyval
1507  * and modifiers.
1508  */
1509 void
_clutter_input_device_set_n_keys(ClutterInputDevice * device,guint n_keys)1510 _clutter_input_device_set_n_keys (ClutterInputDevice *device,
1511                                   guint               n_keys)
1512 {
1513   if (device->keys != NULL)
1514     g_array_free (device->keys, TRUE);
1515 
1516   device->n_keys = n_keys;
1517   device->keys = g_array_sized_new (FALSE, TRUE,
1518                                     sizeof (ClutterKeyInfo),
1519                                     n_keys);
1520 }
1521 
1522 /**
1523  * clutter_input_device_get_n_keys:
1524  * @device: a #ClutterInputDevice
1525  *
1526  * Retrieves the number of keys registered for @device.
1527  *
1528  * Return value: the number of registered keys
1529  *
1530  * Since: 1.6
1531  */
1532 guint
clutter_input_device_get_n_keys(ClutterInputDevice * device)1533 clutter_input_device_get_n_keys (ClutterInputDevice *device)
1534 {
1535   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
1536 
1537   return device->n_keys;
1538 }
1539 
1540 /**
1541  * clutter_input_device_set_key:
1542  * @device: a #ClutterInputDevice
1543  * @index_: the index of the key
1544  * @keyval: the keyval
1545  * @modifiers: a bitmask of modifiers
1546  *
1547  * Sets the keyval and modifiers at the given @index_ for @device.
1548  *
1549  * Clutter will use the keyval and modifiers set when filling out
1550  * an event coming from the same input device.
1551  *
1552  * Since: 1.6
1553  */
1554 void
clutter_input_device_set_key(ClutterInputDevice * device,guint index_,guint keyval,ClutterModifierType modifiers)1555 clutter_input_device_set_key (ClutterInputDevice  *device,
1556                               guint                index_,
1557                               guint                keyval,
1558                               ClutterModifierType  modifiers)
1559 {
1560   ClutterKeyInfo *key_info;
1561 
1562   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
1563   g_return_if_fail (index_ < device->n_keys);
1564 
1565   key_info = &g_array_index (device->keys, ClutterKeyInfo, index_);
1566   key_info->keyval = keyval;
1567   key_info->modifiers = modifiers;
1568 }
1569 
1570 /**
1571  * clutter_input_device_get_key:
1572  * @device: a #ClutterInputDevice
1573  * @index_: the index of the key
1574  * @keyval: (out): return location for the keyval at @index_
1575  * @modifiers: (out): return location for the modifiers at @index_
1576  *
1577  * Retrieves the key set using clutter_input_device_set_key()
1578  *
1579  * Return value: %TRUE if a key was set at the given index
1580  *
1581  * Since: 1.6
1582  */
1583 gboolean
clutter_input_device_get_key(ClutterInputDevice * device,guint index_,guint * keyval,ClutterModifierType * modifiers)1584 clutter_input_device_get_key (ClutterInputDevice  *device,
1585                               guint                index_,
1586                               guint               *keyval,
1587                               ClutterModifierType *modifiers)
1588 {
1589   ClutterKeyInfo *key_info;
1590 
1591   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
1592 
1593   if (device->keys == NULL)
1594     return FALSE;
1595 
1596   if (index_ > device->keys->len)
1597     return FALSE;
1598 
1599   key_info = &g_array_index (device->keys, ClutterKeyInfo, index_);
1600 
1601   if (!key_info->keyval && !key_info->modifiers)
1602     return FALSE;
1603 
1604   if (keyval)
1605     *keyval = key_info->keyval;
1606 
1607   if (modifiers)
1608     *modifiers = key_info->modifiers;
1609 
1610   return TRUE;
1611 }
1612 
1613 /*< private >
1614  * clutter_input_device_add_slave:
1615  * @master: a #ClutterInputDevice
1616  * @slave: a #ClutterInputDevice
1617  *
1618  * Adds @slave to the list of slave devices of @master
1619  *
1620  * This function does not increase the reference count of either @master
1621  * or @slave.
1622  */
1623 void
_clutter_input_device_add_slave(ClutterInputDevice * master,ClutterInputDevice * slave)1624 _clutter_input_device_add_slave (ClutterInputDevice *master,
1625                                  ClutterInputDevice *slave)
1626 {
1627   if (g_list_find (master->slaves, slave) == NULL)
1628     master->slaves = g_list_prepend (master->slaves, slave);
1629 }
1630 
1631 /*< private >
1632  * clutter_input_device_remove_slave:
1633  * @master: a #ClutterInputDevice
1634  * @slave: a #ClutterInputDevice
1635  *
1636  * Removes @slave from the list of slave devices of @master.
1637  *
1638  * This function does not decrease the reference count of either @master
1639  * or @slave.
1640  */
1641 void
_clutter_input_device_remove_slave(ClutterInputDevice * master,ClutterInputDevice * slave)1642 _clutter_input_device_remove_slave (ClutterInputDevice *master,
1643                                     ClutterInputDevice *slave)
1644 {
1645   if (g_list_find (master->slaves, slave) != NULL)
1646     master->slaves = g_list_remove (master->slaves, slave);
1647 }
1648 
1649 /*< private >
1650  * clutter_input_device_add_sequence:
1651  * @device: a #ClutterInputDevice
1652  * @sequence: a #ClutterEventSequence
1653  *
1654  * Start tracking informations related to a touch point (position,
1655  * actor underneath the touch point).
1656  */
1657 void
_clutter_input_device_add_event_sequence(ClutterInputDevice * device,ClutterEvent * event)1658 _clutter_input_device_add_event_sequence (ClutterInputDevice *device,
1659                                           ClutterEvent       *event)
1660 {
1661   ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);
1662   ClutterStage *stage;
1663 
1664   if (sequence == NULL)
1665     return;
1666 
1667   stage = clutter_event_get_stage (event);
1668   if (stage == NULL)
1669     return;
1670 
1671   _clutter_input_device_ensure_touch_info (device, sequence, stage);
1672 }
1673 
1674 /*< private >
1675  * clutter_input_device_remove_sequence:
1676  * @device: a #ClutterInputDevice
1677  * @sequence: a #ClutterEventSequence
1678  *
1679  * Stop tracking informations related to a touch point.
1680  */
1681 void
_clutter_input_device_remove_event_sequence(ClutterInputDevice * device,ClutterEvent * event)1682 _clutter_input_device_remove_event_sequence (ClutterInputDevice *device,
1683                                              ClutterEvent       *event)
1684 {
1685   ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);
1686   ClutterTouchInfo *info =
1687     g_hash_table_lookup (device->touch_sequences_info, sequence);
1688 
1689   if (info == NULL)
1690     return;
1691 
1692   if (info->actor != NULL)
1693     {
1694       GList *sequences =
1695         g_hash_table_lookup (device->inv_touch_sequence_actors, info->actor);
1696 
1697       sequences = g_list_remove (sequences, sequence);
1698 
1699       g_hash_table_replace (device->inv_touch_sequence_actors,
1700                             info->actor, sequences);
1701       _clutter_input_device_set_actor (device, sequence, NULL, TRUE);
1702     }
1703 
1704   g_hash_table_remove (device->touch_sequences_info, sequence);
1705 }
1706 
1707 /**
1708  * clutter_input_device_get_slave_devices:
1709  * @device: a #ClutterInputDevice
1710  *
1711  * Retrieves the slave devices attached to @device.
1712  *
1713  * Return value: (transfer container) (element-type Clutter.InputDevice): a
1714  *   list of #ClutterInputDevice, or %NULL. The contents of the list are
1715  *   owned by the device. Use g_list_free() when done
1716  *
1717  * Since: 1.6
1718  */
1719 GList *
clutter_input_device_get_slave_devices(ClutterInputDevice * device)1720 clutter_input_device_get_slave_devices (ClutterInputDevice *device)
1721 {
1722   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
1723 
1724   return g_list_copy (device->slaves);
1725 }
1726 
1727 /*< internal >
1728  * clutter_input_device_set_associated_device:
1729  * @device: a #ClutterInputDevice
1730  * @associated: (allow-none): a #ClutterInputDevice, or %NULL
1731  *
1732  * Sets the associated device for @device.
1733  *
1734  * This function keeps a reference on the associated device.
1735  */
1736 void
_clutter_input_device_set_associated_device(ClutterInputDevice * device,ClutterInputDevice * associated)1737 _clutter_input_device_set_associated_device (ClutterInputDevice *device,
1738                                              ClutterInputDevice *associated)
1739 {
1740   if (device->associated == associated)
1741     return;
1742 
1743   if (device->associated != NULL)
1744     g_object_unref (device->associated);
1745 
1746   device->associated = associated;
1747   if (device->associated != NULL)
1748     g_object_ref (device->associated);
1749 
1750   CLUTTER_NOTE (MISC, "Associating device %d '%s' to device %d '%s'",
1751                 clutter_input_device_get_device_id (device),
1752                 clutter_input_device_get_device_name (device),
1753                 device->associated != NULL
1754                   ? clutter_input_device_get_device_id (device->associated)
1755                   : -1,
1756                 device->associated != NULL
1757                   ? clutter_input_device_get_device_name (device->associated)
1758                   : "(none)");
1759 
1760   if (device->device_mode != CLUTTER_INPUT_MODE_MASTER)
1761     {
1762       if (device->associated != NULL)
1763         device->device_mode = CLUTTER_INPUT_MODE_SLAVE;
1764       else
1765         device->device_mode = CLUTTER_INPUT_MODE_FLOATING;
1766 
1767       g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_DEVICE_MODE]);
1768     }
1769 }
1770 
1771 /**
1772  * clutter_input_device_get_associated_device:
1773  * @device: a #ClutterInputDevice
1774  *
1775  * Retrieves a pointer to the #ClutterInputDevice that has been
1776  * associated to @device.
1777  *
1778  * If the #ClutterInputDevice:device-mode property of @device is
1779  * set to %CLUTTER_INPUT_MODE_MASTER, this function will return
1780  * %NULL.
1781  *
1782  * Return value: (transfer none): a #ClutterInputDevice, or %NULL
1783  *
1784  * Since: 1.6
1785  */
1786 ClutterInputDevice *
clutter_input_device_get_associated_device(ClutterInputDevice * device)1787 clutter_input_device_get_associated_device (ClutterInputDevice *device)
1788 {
1789   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
1790 
1791   return device->associated;
1792 }
1793 
1794 /**
1795  * clutter_input_device_keycode_to_evdev:
1796  * @device: A #ClutterInputDevice
1797  * @hardware_keycode: The hardware keycode from a #ClutterKeyEvent
1798  * @evdev_keycode: The return location for the evdev keycode
1799  *
1800  * Translates a hardware keycode from a #ClutterKeyEvent to the
1801  * equivalent evdev keycode. Note that depending on the input backend
1802  * used by Clutter this function can fail if there is no obvious
1803  * mapping between the key codes. The hardware keycode can be taken
1804  * from the #ClutterKeyEvent.hardware_keycode member of #ClutterKeyEvent.
1805  *
1806  * Return value: %TRUE if the conversion succeeded, %FALSE otherwise.
1807  *
1808  * Since: 1.10
1809  */
1810 gboolean
clutter_input_device_keycode_to_evdev(ClutterInputDevice * device,guint hardware_keycode,guint * evdev_keycode)1811 clutter_input_device_keycode_to_evdev (ClutterInputDevice *device,
1812                                        guint               hardware_keycode,
1813                                        guint              *evdev_keycode)
1814 {
1815   ClutterInputDeviceClass *device_class;
1816 
1817   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
1818 
1819   device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device);
1820   if (device_class->keycode_to_evdev == NULL)
1821     return FALSE;
1822   else
1823     return device_class->keycode_to_evdev (device,
1824                                            hardware_keycode,
1825                                            evdev_keycode);
1826 }
1827 
1828 void
_clutter_input_device_add_scroll_info(ClutterInputDevice * device,guint index_,ClutterScrollDirection direction,gdouble increment)1829 _clutter_input_device_add_scroll_info (ClutterInputDevice     *device,
1830                                        guint                   index_,
1831                                        ClutterScrollDirection  direction,
1832                                        gdouble                 increment)
1833 {
1834   ClutterScrollInfo info;
1835 
1836   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
1837   g_return_if_fail (index_ < clutter_input_device_get_n_axes (device));
1838 
1839   info.axis_id = index_;
1840   info.direction = direction;
1841   info.increment = increment;
1842   info.last_value_valid = FALSE;
1843 
1844   if (device->scroll_info == NULL)
1845     {
1846       device->scroll_info = g_array_new (FALSE,
1847                                          FALSE,
1848                                          sizeof (ClutterScrollInfo));
1849     }
1850 
1851   g_array_append_val (device->scroll_info, info);
1852 }
1853 
1854 gboolean
_clutter_input_device_get_scroll_delta(ClutterInputDevice * device,guint index_,gdouble value,ClutterScrollDirection * direction_p,gdouble * delta_p)1855 _clutter_input_device_get_scroll_delta (ClutterInputDevice     *device,
1856                                         guint                   index_,
1857                                         gdouble                 value,
1858                                         ClutterScrollDirection *direction_p,
1859                                         gdouble                *delta_p)
1860 {
1861   guint i;
1862 
1863   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
1864   g_return_val_if_fail (index_ < clutter_input_device_get_n_axes (device), FALSE);
1865 
1866   if (device->scroll_info == NULL)
1867     return FALSE;
1868 
1869   for (i = 0; i < device->scroll_info->len; i++)
1870     {
1871       ClutterScrollInfo *info = &g_array_index (device->scroll_info,
1872                                                 ClutterScrollInfo,
1873                                                 i);
1874 
1875       if (info->axis_id == index_)
1876         {
1877           if (direction_p != NULL)
1878             *direction_p = info->direction;
1879 
1880           if (delta_p != NULL)
1881             *delta_p = 0.0;
1882 
1883           if (info->last_value_valid)
1884             {
1885               if (delta_p != NULL)
1886                 {
1887                   *delta_p = (value - info->last_value)
1888                            / info->increment;
1889                 }
1890 
1891               info->last_value = value;
1892             }
1893           else
1894             {
1895               info->last_value = value;
1896               info->last_value_valid = TRUE;
1897             }
1898 
1899           return TRUE;
1900         }
1901     }
1902 
1903   return FALSE;
1904 }
1905 
1906 void
_clutter_input_device_reset_scroll_info(ClutterInputDevice * device)1907 _clutter_input_device_reset_scroll_info (ClutterInputDevice *device)
1908 {
1909   guint i;
1910 
1911   if (device->scroll_info == NULL)
1912     return;
1913 
1914   for (i = 0; i < device->scroll_info->len; i++)
1915     {
1916       ClutterScrollInfo *info = &g_array_index (device->scroll_info,
1917                                                 ClutterScrollInfo,
1918                                                 i);
1919 
1920       info->last_value_valid = FALSE;
1921     }
1922 }
1923 
1924 static void
on_grab_sequence_actor_destroy(ClutterActor * actor,ClutterInputDevice * device)1925 on_grab_sequence_actor_destroy (ClutterActor       *actor,
1926                                 ClutterInputDevice *device)
1927 {
1928   ClutterEventSequence *sequence =
1929     g_hash_table_lookup (device->inv_sequence_grab_actors, actor);
1930 
1931   if (sequence != NULL)
1932     {
1933       g_hash_table_remove (device->sequence_grab_actors, sequence);
1934       g_hash_table_remove (device->inv_sequence_grab_actors, actor);
1935     }
1936 }
1937 
1938 /**
1939  * clutter_input_device_sequence_grab:
1940  * @device: a #ClutterInputDevice
1941  * @sequence: a #ClutterEventSequence
1942  * @actor: a #ClutterActor
1943  *
1944  * Acquires a grab on @actor for the given @device and the given touch
1945  * @sequence.
1946  *
1947  * Any touch event coming from @device and from @sequence will be
1948  * delivered to @actor, bypassing the usual event delivery mechanism,
1949  * until the grab is released by calling
1950  * clutter_input_device_sequence_ungrab().
1951  *
1952  * The grab is client-side: even if the windowing system used by the Clutter
1953  * backend has the concept of "device grabs", Clutter will not use them.
1954  *
1955  * Since: 1.12
1956  */
1957 void
clutter_input_device_sequence_grab(ClutterInputDevice * device,ClutterEventSequence * sequence,ClutterActor * actor)1958 clutter_input_device_sequence_grab (ClutterInputDevice   *device,
1959                                     ClutterEventSequence *sequence,
1960                                     ClutterActor         *actor)
1961 {
1962   ClutterActor *grab_actor;
1963 
1964   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
1965   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
1966 
1967   if (device->sequence_grab_actors == NULL)
1968     {
1969       grab_actor = NULL;
1970       device->sequence_grab_actors = g_hash_table_new (NULL, NULL);
1971       device->inv_sequence_grab_actors = g_hash_table_new (NULL, NULL);
1972     }
1973   else
1974     {
1975       grab_actor = g_hash_table_lookup (device->sequence_grab_actors, sequence);
1976     }
1977 
1978   if (grab_actor != NULL)
1979     {
1980       g_signal_handlers_disconnect_by_func (grab_actor,
1981                                             G_CALLBACK (on_grab_sequence_actor_destroy),
1982                                             device);
1983       g_hash_table_remove (device->sequence_grab_actors, sequence);
1984       g_hash_table_remove (device->inv_sequence_grab_actors, grab_actor);
1985     }
1986 
1987   g_hash_table_insert (device->sequence_grab_actors, sequence, actor);
1988   g_hash_table_insert (device->inv_sequence_grab_actors, actor, sequence);
1989   g_signal_connect (actor,
1990                     "destroy",
1991                     G_CALLBACK (on_grab_sequence_actor_destroy),
1992                     device);
1993 }
1994 
1995 /**
1996  * clutter_input_device_sequence_ungrab:
1997  * @device: a #ClutterInputDevice
1998  * @sequence: a #ClutterEventSequence
1999  *
2000  * Releases the grab on the @device for the given @sequence, if one is
2001  * in place.
2002  *
2003  * Since: 1.12
2004  */
2005 void
clutter_input_device_sequence_ungrab(ClutterInputDevice * device,ClutterEventSequence * sequence)2006 clutter_input_device_sequence_ungrab (ClutterInputDevice   *device,
2007                                       ClutterEventSequence *sequence)
2008 {
2009   ClutterActor *grab_actor;
2010 
2011   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
2012 
2013   if (device->sequence_grab_actors == NULL)
2014     return;
2015 
2016   grab_actor = g_hash_table_lookup (device->sequence_grab_actors, sequence);
2017 
2018   if (grab_actor == NULL)
2019     return;
2020 
2021   g_signal_handlers_disconnect_by_func (grab_actor,
2022                                         G_CALLBACK (on_grab_sequence_actor_destroy),
2023                                         device);
2024   g_hash_table_remove (device->sequence_grab_actors, sequence);
2025   g_hash_table_remove (device->inv_sequence_grab_actors, grab_actor);
2026 
2027   if (g_hash_table_size (device->sequence_grab_actors) == 0)
2028     {
2029       g_hash_table_destroy (device->sequence_grab_actors);
2030       device->sequence_grab_actors = NULL;
2031       g_hash_table_destroy (device->inv_sequence_grab_actors);
2032       device->inv_sequence_grab_actors = NULL;
2033     }
2034 }
2035 
2036 /**
2037  * clutter_input_device_sequence_get_grabbed_actor:
2038  * @device: a #ClutterInputDevice
2039  * @sequence: a #ClutterEventSequence
2040  *
2041  * Retrieves a pointer to the #ClutterActor currently grabbing the
2042  * touch events coming from @device given the @sequence.
2043  *
2044  * Return value: (transfer none): a #ClutterActor, or %NULL
2045  *
2046  * Since: 1.12
2047  */
2048 ClutterActor *
clutter_input_device_sequence_get_grabbed_actor(ClutterInputDevice * device,ClutterEventSequence * sequence)2049 clutter_input_device_sequence_get_grabbed_actor (ClutterInputDevice   *device,
2050                                                  ClutterEventSequence *sequence)
2051 {
2052   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
2053 
2054   if (device->sequence_grab_actors == NULL)
2055     return NULL;
2056 
2057   return g_hash_table_lookup (device->sequence_grab_actors, sequence);
2058 }
2059 
2060 /**
2061  * clutter_input_device_get_vendor_id:
2062  * @device: a slave #ClutterInputDevice
2063  *
2064  * Gets the vendor ID of this device.
2065  *
2066  * Returns: the vendor ID
2067  *
2068  * Since: 1.22
2069  */
2070 const gchar *
clutter_input_device_get_vendor_id(ClutterInputDevice * device)2071 clutter_input_device_get_vendor_id (ClutterInputDevice *device)
2072 {
2073   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
2074   g_return_val_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_MASTER, NULL);
2075 
2076   return device->vendor_id;
2077 }
2078 
2079 /**
2080  * clutter_input_device_get_product_id:
2081  * @device: a slave #ClutterInputDevice
2082  *
2083  * Gets the product ID of this device.
2084  *
2085  * Returns: the product ID
2086  *
2087  * Since: 1.22
2088  */
2089 const gchar *
clutter_input_device_get_product_id(ClutterInputDevice * device)2090 clutter_input_device_get_product_id (ClutterInputDevice *device)
2091 {
2092   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
2093   g_return_val_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_MASTER, NULL);
2094 
2095   return device->product_id;
2096 }
2097 
2098 void
clutter_input_device_add_tool(ClutterInputDevice * device,ClutterInputDeviceTool * tool)2099 clutter_input_device_add_tool (ClutterInputDevice     *device,
2100                                ClutterInputDeviceTool *tool)
2101 {
2102   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
2103   g_return_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_MASTER);
2104   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL (tool));
2105 
2106   if (!device->tools)
2107     device->tools = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
2108 
2109   g_ptr_array_add (device->tools, tool);
2110 }
2111 
2112 ClutterInputDeviceTool *
clutter_input_device_lookup_tool(ClutterInputDevice * device,guint64 serial,ClutterInputDeviceToolType type)2113 clutter_input_device_lookup_tool (ClutterInputDevice         *device,
2114                                   guint64                     serial,
2115                                   ClutterInputDeviceToolType  type)
2116 {
2117   ClutterInputDeviceTool *tool;
2118   guint i;
2119 
2120   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
2121   g_return_val_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_MASTER, NULL);
2122 
2123   if (!device->tools)
2124     return NULL;
2125 
2126   for (i = 0; i < device->tools->len; i++)
2127     {
2128       tool = g_ptr_array_index (device->tools, i);
2129 
2130       if (serial == clutter_input_device_tool_get_serial (tool) &&
2131           type == clutter_input_device_tool_get_tool_type (tool))
2132         return tool;
2133     }
2134 
2135   return NULL;
2136 }
2137 
2138 void
clutter_input_device_update_from_tool(ClutterInputDevice * device,ClutterInputDeviceTool * tool)2139 clutter_input_device_update_from_tool (ClutterInputDevice     *device,
2140                                        ClutterInputDeviceTool *tool)
2141 {
2142   ClutterInputDeviceClass *device_class;
2143 
2144   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
2145 
2146   device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device);
2147 
2148   if (device_class->update_from_tool)
2149     device_class->update_from_tool (device, tool);
2150 }
2151 
2152 gint
clutter_input_device_get_n_rings(ClutterInputDevice * device)2153 clutter_input_device_get_n_rings (ClutterInputDevice *device)
2154 {
2155   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
2156 
2157   return device->n_rings;
2158 }
2159 
2160 gint
clutter_input_device_get_n_strips(ClutterInputDevice * device)2161 clutter_input_device_get_n_strips (ClutterInputDevice *device)
2162 {
2163   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
2164 
2165   return device->n_strips;
2166 }
2167 
2168 gint
clutter_input_device_get_n_mode_groups(ClutterInputDevice * device)2169 clutter_input_device_get_n_mode_groups (ClutterInputDevice *device)
2170 {
2171   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
2172   g_return_val_if_fail (clutter_input_device_get_device_type (device) ==
2173                         CLUTTER_PAD_DEVICE, 0);
2174 
2175   return device->n_mode_groups;
2176 }
2177 
2178 gint
clutter_input_device_get_group_n_modes(ClutterInputDevice * device,gint group)2179 clutter_input_device_get_group_n_modes (ClutterInputDevice *device,
2180                                         gint                group)
2181 {
2182   ClutterInputDeviceClass *device_class;
2183 
2184   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
2185   g_return_val_if_fail (clutter_input_device_get_device_type (device) ==
2186                         CLUTTER_PAD_DEVICE, 0);
2187   g_return_val_if_fail (group >= 0, 0);
2188 
2189   device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device);
2190 
2191   if (device_class->get_group_n_modes)
2192     return device_class->get_group_n_modes (device, group);
2193 
2194   return 0;
2195 }
2196 
2197 gboolean
clutter_input_device_is_mode_switch_button(ClutterInputDevice * device,guint group,guint button)2198 clutter_input_device_is_mode_switch_button (ClutterInputDevice *device,
2199                                             guint               group,
2200                                             guint               button)
2201 {
2202   ClutterInputDeviceClass *device_class;
2203 
2204   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
2205   g_return_val_if_fail (clutter_input_device_get_device_type (device) ==
2206                         CLUTTER_PAD_DEVICE, FALSE);
2207 
2208   device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device);
2209 
2210   if (device_class->is_mode_switch_button)
2211     return device_class->is_mode_switch_button (device, group, button);
2212 
2213   return FALSE;
2214 }
2215 
2216 gint
clutter_input_device_get_mode_switch_button_group(ClutterInputDevice * device,guint button)2217 clutter_input_device_get_mode_switch_button_group (ClutterInputDevice *device,
2218                                                    guint               button)
2219 {
2220   gint group;
2221 
2222   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), -1);
2223   g_return_val_if_fail (clutter_input_device_get_device_type (device) ==
2224                         CLUTTER_PAD_DEVICE, -1);
2225 
2226   for (group = 0; group < device->n_mode_groups; group++)
2227     {
2228       if (clutter_input_device_is_mode_switch_button (device, group, button))
2229         return group;
2230     }
2231 
2232   return -1;
2233 }
2234 
2235 const gchar *
clutter_input_device_get_device_node(ClutterInputDevice * device)2236 clutter_input_device_get_device_node (ClutterInputDevice *device)
2237 {
2238   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
2239 
2240   return device->node_path;
2241 }
2242 
2243 ClutterInputDeviceMapping
clutter_input_device_get_mapping_mode(ClutterInputDevice * device)2244 clutter_input_device_get_mapping_mode (ClutterInputDevice *device)
2245 {
2246   ClutterInputDeviceType device_type;
2247 
2248   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
2249                         CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE);
2250 
2251   device_type = clutter_input_device_get_device_type (device);
2252   g_return_val_if_fail (device_type == CLUTTER_TABLET_DEVICE ||
2253                         device_type == CLUTTER_PEN_DEVICE ||
2254                         device_type == CLUTTER_ERASER_DEVICE,
2255                         CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE);
2256 
2257   return device->mapping_mode;
2258 }
2259 
2260 void
clutter_input_device_set_mapping_mode(ClutterInputDevice * device,ClutterInputDeviceMapping mapping)2261 clutter_input_device_set_mapping_mode (ClutterInputDevice        *device,
2262                                        ClutterInputDeviceMapping  mapping)
2263 {
2264   ClutterInputDeviceType device_type;
2265 
2266   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
2267 
2268   device_type = clutter_input_device_get_device_type (device);
2269   g_return_if_fail (device_type == CLUTTER_TABLET_DEVICE ||
2270                     device_type == CLUTTER_PEN_DEVICE ||
2271                     device_type == CLUTTER_ERASER_DEVICE);
2272 
2273   if (device->mapping_mode == mapping)
2274     return;
2275 
2276   device->mapping_mode = mapping;
2277   g_object_notify (G_OBJECT (device), "mapping-mode");
2278 }
2279 
2280 gboolean
clutter_input_device_is_grouped(ClutterInputDevice * device,ClutterInputDevice * other_device)2281 clutter_input_device_is_grouped (ClutterInputDevice *device,
2282                                  ClutterInputDevice *other_device)
2283 {
2284   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
2285   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (other_device), FALSE);
2286 
2287   return CLUTTER_INPUT_DEVICE_GET_CLASS (device)->is_grouped (device, other_device);
2288 }
2289