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