4 * An OpenGL based 'interactive canvas' library.
6 * Copyright © 2009, 2010, 2011 Intel Corp.
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.
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.
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/>.
21 * Author: Emmanuele Bassi <ebassi@linux.intel.com>
25 * SECTION:clutter-input-device
26 * @short_description: An input device managed by Clutter
28 * #ClutterInputDevice represents an input device known to Clutter.
30 * The #ClutterInputDevice class holds the state of the device, but
31 * its contents are usually defined by the Clutter backend in use.
38 #include "clutter-input-device.h"
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"
70 static GParamSpec *obj_props[PROP_LAST] = { NULL, };
72 G_DEFINE_TYPE (ClutterInputDevice, clutter_input_device, G_TYPE_OBJECT);
75 clutter_input_device_dispose (GObject *gobject)
77 ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (gobject);
79 g_free (device->device_name);
81 if (device->associated != NULL)
83 if (device->device_mode == CLUTTER_INPUT_MODE_SLAVE)
84 _clutter_input_device_remove_slave (device->associated, device);
86 _clutter_input_device_set_associated_device (device->associated, NULL);
87 g_object_unref (device->associated);
88 device->associated = NULL;
91 if (device->axes != NULL)
93 g_array_free (device->axes, TRUE);
97 if (device->keys != NULL)
99 g_array_free (device->keys, TRUE);
103 G_OBJECT_CLASS (clutter_input_device_parent_class)->dispose (gobject);
107 clutter_input_device_set_property (GObject *gobject,
112 ClutterInputDevice *self = CLUTTER_INPUT_DEVICE (gobject);
117 self->id = g_value_get_int (value);
120 case PROP_DEVICE_TYPE:
121 self->device_type = g_value_get_enum (value);
124 case PROP_DEVICE_MANAGER:
125 self->device_manager = g_value_get_object (value);
128 case PROP_DEVICE_MODE:
129 self->device_mode = g_value_get_enum (value);
133 self->backend = g_value_get_object (value);
137 self->device_name = g_value_dup_string (value);
140 case PROP_HAS_CURSOR:
141 self->has_cursor = g_value_get_boolean (value);
145 clutter_input_device_set_enabled (self, g_value_get_boolean (value));
149 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
155 clutter_input_device_get_property (GObject *gobject,
160 ClutterInputDevice *self = CLUTTER_INPUT_DEVICE (gobject);
165 g_value_set_int (value, self->id);
168 case PROP_DEVICE_TYPE:
169 g_value_set_enum (value, self->device_type);
172 case PROP_DEVICE_MANAGER:
173 g_value_set_object (value, self->device_manager);
176 case PROP_DEVICE_MODE:
177 g_value_set_enum (value, self->device_mode);
181 g_value_set_object (value, self->backend);
185 g_value_set_string (value, self->device_name);
188 case PROP_HAS_CURSOR:
189 g_value_set_boolean (value, self->has_cursor);
193 g_value_set_uint (value, clutter_input_device_get_n_axes (self));
197 g_value_set_boolean (value, self->is_enabled);
201 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
207 clutter_input_device_class_init (ClutterInputDeviceClass *klass)
209 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
212 * ClutterInputDevice:id:
214 * The unique identifier of the device
219 g_param_spec_int ("id",
221 P_("Unique identifier of the device"),
224 CLUTTER_PARAM_READWRITE |
225 G_PARAM_CONSTRUCT_ONLY);
228 * ClutterInputDevice:name:
230 * The name of the device
234 obj_props[PROP_NAME] =
235 g_param_spec_string ("name",
237 P_("The name of the device"),
239 CLUTTER_PARAM_READWRITE |
240 G_PARAM_CONSTRUCT_ONLY);
243 * ClutterInputDevice:device-type:
245 * The type of the device
249 obj_props[PROP_DEVICE_TYPE] =
250 g_param_spec_enum ("device-type",
252 P_("The type of the device"),
253 CLUTTER_TYPE_INPUT_DEVICE_TYPE,
254 CLUTTER_POINTER_DEVICE,
255 CLUTTER_PARAM_READWRITE |
256 G_PARAM_CONSTRUCT_ONLY);
259 * ClutterInputDevice:device-manager:
261 * The #ClutterDeviceManager instance which owns the device
265 obj_props[PROP_DEVICE_MANAGER] =
266 g_param_spec_object ("device-manager",
267 P_("Device Manager"),
268 P_("The device manager instance"),
269 CLUTTER_TYPE_DEVICE_MANAGER,
270 CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
273 * ClutterInputDevice:mode:
275 * The mode of the device.
279 obj_props[PROP_DEVICE_MODE] =
280 g_param_spec_enum ("device-mode",
282 P_("The mode of the device"),
283 CLUTTER_TYPE_INPUT_MODE,
284 CLUTTER_INPUT_MODE_FLOATING,
285 CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
288 * ClutterInputDevice:has-cursor:
290 * Whether the device has an on screen cursor following its movement.
294 obj_props[PROP_HAS_CURSOR] =
295 g_param_spec_boolean ("has-cursor",
297 P_("Whether the device has a cursor"),
299 CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
302 * ClutterInputDevice:enabled:
304 * Whether the device is enabled.
306 * A device with the #ClutterInputDevice:device-mode property set
307 * to %CLUTTER_INPUT_MODE_MASTER cannot be disabled.
309 * A device must be enabled in order to receive events from it.
313 obj_props[PROP_ENABLED] =
314 g_param_spec_boolean ("enabled",
316 P_("Whether the device is enabled"),
318 CLUTTER_PARAM_READWRITE);
321 * ClutterInputDevice:n-axes:
323 * The number of axes of the device.
327 obj_props[PROP_N_AXES] =
328 g_param_spec_uint ("n-axes",
329 P_("Number of Axes"),
330 P_("The number of axes on the device"),
333 CLUTTER_PARAM_READABLE);
336 * ClutterInputDevice:backend:
338 * The #ClutterBackend that created the device.
342 obj_props[PROP_BACKEND] =
343 g_param_spec_object ("backend",
345 P_("The backend instance"),
346 CLUTTER_TYPE_BACKEND,
347 CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
349 gobject_class->dispose = clutter_input_device_dispose;
350 gobject_class->set_property = clutter_input_device_set_property;
351 gobject_class->get_property = clutter_input_device_get_property;
352 g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
356 clutter_input_device_init (ClutterInputDevice *self)
359 self->device_type = CLUTTER_POINTER_DEVICE;
361 self->click_count = 0;
363 self->current_time = self->previous_time = CLUTTER_CURRENT_TIME;
364 self->current_x = self->previous_x = -1;
365 self->current_y = self->previous_y = -1;
366 self->current_button_number = self->previous_button_number = -1;
367 self->current_state = self->previous_state = 0;
371 * clutter_input_device_set_coords:
372 * @device: a #ClutterInputDevice
373 * @x: X coordinate of the device
374 * @y: Y coordinate of the device
376 * Stores the last known coordinates of the device
379 _clutter_input_device_set_coords (ClutterInputDevice *device,
383 g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
385 if (device->current_x != x)
386 device->current_x = x;
388 if (device->current_y != y)
389 device->current_y = y;
393 * clutter_input_device_set_state:
394 * @device: a #ClutterInputDevice
395 * @state: a bitmask of modifiers
397 * Stores the last known modifiers state of the device
400 _clutter_input_device_set_state (ClutterInputDevice *device,
401 ClutterModifierType state)
403 g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
405 device->current_state = state;
409 * clutter_input_device_set_time:
410 * @device: a #ClutterInputDevice
413 * Stores the last known event time of the device
416 _clutter_input_device_set_time (ClutterInputDevice *device,
419 g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
421 if (device->current_time != time_)
422 device->current_time = time_;
426 on_cursor_actor_destroy (ClutterActor *actor,
427 ClutterInputDevice *device)
429 device->cursor_actor = NULL;
433 * clutter_input_device_set_stage:
434 * @device: a #ClutterInputDevice
435 * @stage: a #ClutterStage or %NULL
437 * Stores the stage under the device
440 _clutter_input_device_set_stage (ClutterInputDevice *device,
443 if (device->stage == stage)
446 device->stage = stage;
448 /* we leave the ->cursor_actor in place in order to check
449 * if we left the stage without crossing it again; this way
450 * we can emit a leave event on the cursor actor right before
451 * we emit the leave event on the stage.
456 * clutter_input_device_get_stage:
457 * @device: a #ClutterInputDevice
459 * Retrieves the stage currently associated with @device.
461 * Return value: The stage currently associated with @device.
464 _clutter_input_device_get_stage (ClutterInputDevice *device)
466 return device->stage;
470 * clutter_input_device_set_actor:
471 * @device: a #ClutterInputDevice
472 * @actor: a #ClutterActor
473 * @emit_crossing: %TRUE to emit crossing events
475 * Sets the actor under the pointer coordinates of @device
477 * This function is called by _clutter_input_device_update()
480 * - queue a %CLUTTER_LEAVE event on the previous pointer actor
482 * - set to %FALSE the :has-pointer property of the previous
483 * pointer actor of @device, if any
484 * - queue a %CLUTTER_ENTER event on the new pointer actor
485 * - set to %TRUE the :has-pointer property of the new pointer
489 _clutter_input_device_set_actor (ClutterInputDevice *device,
491 gboolean emit_crossing)
493 ClutterActor *old_actor;
495 if (device->cursor_actor == actor)
498 old_actor = device->cursor_actor;
500 if (old_actor != NULL)
506 event = clutter_event_new (CLUTTER_LEAVE);
507 event->crossing.time = device->current_time;
508 event->crossing.flags = 0;
509 event->crossing.stage = device->stage;
510 event->crossing.source = device->cursor_actor;
511 event->crossing.x = device->current_x;
512 event->crossing.y = device->current_y;
513 event->crossing.related = actor;
514 clutter_event_set_device (event, device);
516 /* we need to make sure that this event is processed
517 * before any other event we might have queued up until
518 * now, so we go on, and synthesize the event emission
521 _clutter_process_event (event);
523 clutter_event_free (event);
526 /* processing the event might have destroyed the actor */
527 if (device->cursor_actor != NULL)
529 _clutter_actor_set_has_pointer (device->cursor_actor, FALSE);
530 g_signal_handlers_disconnect_by_func (device->cursor_actor,
531 G_CALLBACK (on_cursor_actor_destroy),
534 device->cursor_actor = NULL;
544 event = clutter_event_new (CLUTTER_ENTER);
545 event->crossing.time = device->current_time;
546 event->crossing.flags = 0;
547 event->crossing.stage = device->stage;
548 event->crossing.x = device->current_x;
549 event->crossing.y = device->current_y;
550 event->crossing.source = actor;
551 event->crossing.related = old_actor;
552 clutter_event_set_device (event, device);
555 _clutter_process_event (event);
557 clutter_event_free (event);
561 device->cursor_actor = actor;
562 if (device->cursor_actor != NULL)
564 g_signal_connect (device->cursor_actor,
565 "destroy", G_CALLBACK (on_cursor_actor_destroy),
567 _clutter_actor_set_has_pointer (device->cursor_actor, TRUE);
572 * clutter_input_device_get_device_type:
573 * @device: a #ClutterInputDevice
575 * Retrieves the type of @device
577 * Return value: the type of the device
581 ClutterInputDeviceType
582 clutter_input_device_get_device_type (ClutterInputDevice *device)
584 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
585 CLUTTER_POINTER_DEVICE);
587 return device->device_type;
591 * clutter_input_device_get_device_id:
592 * @device: a #ClutterInputDevice
594 * Retrieves the unique identifier of @device
596 * Return value: the identifier of the device
601 clutter_input_device_get_device_id (ClutterInputDevice *device)
603 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), -1);
609 * clutter_input_device_set_enabled:
610 * @device: a #ClutterInputDevice
611 * @enabled: %TRUE to enable the @device
613 * Enables or disables a #ClutterInputDevice.
615 * Only devices with a #ClutterInputDevice:device-mode property set
616 * to %CLUTTER_INPUT_MODE_SLAVE or %CLUTTER_INPUT_MODE_FLOATING can
622 clutter_input_device_set_enabled (ClutterInputDevice *device,
625 g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
629 if (!enabled && device->device_mode == CLUTTER_INPUT_MODE_MASTER)
632 if (device->is_enabled == enabled)
635 device->is_enabled = enabled;
637 g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_ENABLED]);
641 * clutter_input_device_get_enabled:
642 * @device: a #ClutterInputDevice
644 * Retrieves whether @device is enabled.
646 * Return value: %TRUE if the device is enabled
651 clutter_input_device_get_enabled (ClutterInputDevice *device)
653 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
655 return device->is_enabled;
659 * clutter_input_device_get_device_coords:
660 * @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE
661 * @x: (out): return location for the X coordinate
662 * @y: (out): return location for the Y coordinate
664 * Retrieves the latest coordinates of the pointer of @device
669 clutter_input_device_get_device_coords (ClutterInputDevice *device,
673 g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
676 *x = device->current_x;
679 *y = device->current_y;
683 * _clutter_input_device_update:
684 * @device: a #ClutterInputDevice
686 * Updates the input @device by determining the #ClutterActor underneath the
689 * This function calls _clutter_input_device_set_actor() if needed.
691 * This function only works for #ClutterInputDevice of type
692 * %CLUTTER_POINTER_DEVICE.
697 _clutter_input_device_update (ClutterInputDevice *device,
698 gboolean emit_crossing)
701 ClutterActor *new_cursor_actor;
702 ClutterActor *old_cursor_actor;
705 if (device->device_type == CLUTTER_KEYBOARD_DEVICE)
708 stage = device->stage;
709 if (G_UNLIKELY (stage == NULL))
711 CLUTTER_NOTE (EVENT, "No stage defined for device '%s'",
712 clutter_input_device_get_device_name (device));
716 clutter_input_device_get_device_coords (device, &x, &y);
718 old_cursor_actor = device->cursor_actor;
720 _clutter_stage_do_pick (stage, x, y, CLUTTER_PICK_REACTIVE);
722 /* if the pick could not find an actor then we do not update the
723 * input device, to avoid ghost enter/leave events; the pick should
724 * never fail, except for bugs in the glReadPixels() implementation
725 * in which case this is the safest course of action anyway
727 if (new_cursor_actor == NULL)
731 "Actor under cursor (device %d, at %d, %d): %s",
732 clutter_input_device_get_device_id (device),
734 clutter_actor_get_name (new_cursor_actor) != NULL
735 ? clutter_actor_get_name (new_cursor_actor)
736 : G_OBJECT_TYPE_NAME (new_cursor_actor));
738 /* short-circuit here */
739 if (new_cursor_actor == old_cursor_actor)
740 return old_cursor_actor;
742 _clutter_input_device_set_actor (device, new_cursor_actor, emit_crossing);
744 return device->cursor_actor;
748 * clutter_input_device_get_pointer_actor:
749 * @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE
751 * Retrieves the #ClutterActor underneath the pointer of @device
753 * Return value: (transfer none): a pointer to the #ClutterActor or %NULL
758 clutter_input_device_get_pointer_actor (ClutterInputDevice *device)
760 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
761 g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, NULL);
763 return device->cursor_actor;
767 * clutter_input_device_get_pointer_stage:
768 * @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE
770 * Retrieves the #ClutterStage underneath the pointer of @device
772 * Return value: (transfer none): a pointer to the #ClutterStage or %NULL
777 clutter_input_device_get_pointer_stage (ClutterInputDevice *device)
779 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
780 g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, NULL);
782 return device->stage;
786 * clutter_input_device_get_device_name:
787 * @device: a #ClutterInputDevice
789 * Retrieves the name of the @device
791 * Return value: the name of the device, or %NULL. The returned string
792 * is owned by the #ClutterInputDevice and should never be modified
798 clutter_input_device_get_device_name (ClutterInputDevice *device)
800 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
802 return device->device_name;
806 * clutter_input_device_get_has_cursor:
807 * @device: a #ClutterInputDevice
809 * Retrieves whether @device has a pointer that follows the
812 * Return value: %TRUE if the device has a cursor
817 clutter_input_device_get_has_cursor (ClutterInputDevice *device)
819 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
821 return device->has_cursor;
825 * clutter_input_device_get_device_mode:
826 * @device: a #ClutterInputDevice
828 * Retrieves the #ClutterInputMode of @device.
830 * Return value: the device mode
835 clutter_input_device_get_device_mode (ClutterInputDevice *device)
837 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
838 CLUTTER_INPUT_MODE_FLOATING);
840 return device->device_mode;
844 * clutter_input_device_update_from_event:
845 * @device: a #ClutterInputDevice
846 * @event: a #ClutterEvent
847 * @update_stage: whether to update the #ClutterStage of the @device
848 * using the stage of the event
850 * Forcibly updates the state of the @device using a #ClutterEvent
852 * This function should never be used by applications: it is meant
853 * for integration with embedding toolkits, like clutter-gtk
855 * Embedding toolkits that disable the event collection inside Clutter
856 * need to use this function to update the state of input devices depending
857 * on a #ClutterEvent that they are going to submit to the event handling code
858 * in Clutter though clutter_do_event(). Since the input devices hold the state
859 * that is going to be used to fill in fields like the #ClutterButtonEvent
860 * click count, or to emit synthesized events like %CLUTTER_ENTER and
861 * %CLUTTER_LEAVE, it is necessary for embedding toolkits to also be
862 * responsible of updating the input device state.
864 * For instance, this might be the code to translate an embedding toolkit
865 * native motion notification into a Clutter #ClutterMotionEvent and ask
866 * Clutter to process it:
869 * ClutterEvent c_event;
871 * translate_native_event_to_clutter (native_event, &c_event);
873 * clutter_do_event (&c_event);
876 * Before letting clutter_do_event() process the event, it is necessary to call
877 * clutter_input_device_update_from_event():
880 * ClutterEvent c_event;
881 * ClutterDeviceManager *manager;
882 * ClutterInputDevice *device;
884 * translate_native_event_to_clutter (native_event, &c_event);
886 * /* get the device manager */
887 * manager = clutter_device_manager_get_default ();
889 * /* use the default Core Pointer that Clutter
890 * * backends register by default
892 * device = clutter_device_manager_get_core_device (manager, %CLUTTER_POINTER_DEVICE);
894 * /* update the state of the input device */
895 * clutter_input_device_update_from_event (device, &c_event, FALSE);
897 * clutter_do_event (&c_event);
900 * The @update_stage boolean argument should be used when the input device
901 * enters and leaves a #ClutterStage; it will use the #ClutterStage field
902 * of the passed @event to update the stage associated to the input device.
907 clutter_input_device_update_from_event (ClutterInputDevice *device,
909 gboolean update_stage)
911 ClutterModifierType event_state;
912 ClutterStage *event_stage;
913 gfloat event_x, event_y;
916 g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
917 g_return_if_fail (event != NULL);
919 event_state = clutter_event_get_state (event);
920 event_time = clutter_event_get_time (event);
921 event_stage = clutter_event_get_stage (event);
922 clutter_event_get_coords (event, &event_x, &event_y);
924 _clutter_input_device_set_coords (device, event_x, event_y);
925 _clutter_input_device_set_state (device, event_state);
926 _clutter_input_device_set_time (device, event_time);
929 _clutter_input_device_set_stage (device, event_stage);
933 * clutter_input_device_reset_axes:
934 * @device: a #ClutterInputDevice
936 * Resets the axes on @device
939 _clutter_input_device_reset_axes (ClutterInputDevice *device)
941 if (device->axes != NULL)
943 g_array_free (device->axes, TRUE);
946 g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_N_AXES]);
951 * clutter_input_device_add_axis:
952 * @device: a #ClutterInputDevice
953 * @axis: the axis type
954 * @minimum: the minimum axis value
955 * @maximum: the maximum axis value
956 * @resolution: the axis resolution
958 * Adds an axis of type @axis on @device.
961 _clutter_input_device_add_axis (ClutterInputDevice *device,
962 ClutterInputAxis axis,
967 ClutterAxisInfo info;
970 if (device->axes == NULL)
971 device->axes = g_array_new (FALSE, TRUE, sizeof (ClutterAxisInfo));
974 info.min_value = minimum;
975 info.max_value = maximum;
976 info.resolution = resolution;
980 case CLUTTER_INPUT_AXIS_X:
981 case CLUTTER_INPUT_AXIS_Y:
986 case CLUTTER_INPUT_AXIS_XTILT:
987 case CLUTTER_INPUT_AXIS_YTILT:
998 device->axes = g_array_append_val (device->axes, info);
999 pos = device->axes->len - 1;
1001 g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_N_AXES]);
1007 * clutter_input_translate_axis:
1008 * @device: a #ClutterInputDevice
1009 * @index_: the index of the axis
1010 * @gint: the absolute value of the axis
1011 * @axis_value: (out): the translated value of the axis
1013 * Performs a conversion from the absolute value of the axis
1014 * to a relative value.
1016 * The axis at @index_ must not be %CLUTTER_INPUT_AXIS_X or
1017 * %CLUTTER_INPUT_AXIS_Y.
1019 * Return value: %TRUE if the conversion was successful
1022 _clutter_input_device_translate_axis (ClutterInputDevice *device,
1025 gdouble *axis_value)
1027 ClutterAxisInfo *info;
1031 if (device->axes == NULL || index_ >= device->axes->len)
1034 info = &g_array_index (device->axes, ClutterAxisInfo, index_);
1036 if (info->axis == CLUTTER_INPUT_AXIS_X ||
1037 info->axis == CLUTTER_INPUT_AXIS_Y)
1040 width = info->max_value - info->min_value;
1041 real_value = (info->max_axis * (value - info->min_value)
1042 + info->min_axis * (info->max_value - value))
1046 *axis_value = real_value;
1052 * clutter_input_device_get_axis:
1053 * @device: a #ClutterInputDevice
1054 * @index_: the index of the axis
1056 * Retrieves the type of axis on @device at the given index.
1058 * Return value: the axis type
1063 clutter_input_device_get_axis (ClutterInputDevice *device,
1066 ClutterAxisInfo *info;
1068 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
1069 CLUTTER_INPUT_AXIS_IGNORE);
1071 if (device->axes == NULL)
1072 return CLUTTER_INPUT_AXIS_IGNORE;
1074 if (index_ >= device->axes->len)
1075 return CLUTTER_INPUT_AXIS_IGNORE;
1077 info = &g_array_index (device->axes, ClutterAxisInfo, index_);
1083 * clutter_input_device_get_axis_value:
1084 * @device: a #ClutterInputDevice
1085 * @axes: (array): an array of axes values, typically
1086 * coming from clutter_event_get_axes()
1087 * @axis: the axis to extract
1088 * @value: (out): return location for the axis value
1090 * Extracts the value of the given @axis of a #ClutterInputDevice from
1091 * an array of axis values.
1093 * An example of typical usage for this function is:
1096 * ClutterInputDevice *device = clutter_event_get_device (event);
1097 * gdouble *axes = clutter_event_get_axes (event, NULL);
1098 * gdouble pressure_value = 0;
1100 * clutter_input_device_get_axis_value (device, axes,
1101 * CLUTTER_INPUT_AXIS_PRESSURE,
1102 * &pressure_value);
1105 * Return value: %TRUE if the value was set, and %FALSE otherwise
1110 clutter_input_device_get_axis_value (ClutterInputDevice *device,
1112 ClutterInputAxis axis,
1117 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
1118 g_return_val_if_fail (device->axes != NULL, FALSE);
1120 for (i = 0; i < device->axes->len; i++)
1122 ClutterAxisInfo *info;
1124 info = &g_array_index (device->axes, ClutterAxisInfo, i);
1126 if (info->axis == axis)
1139 * clutter_input_device_get_n_axes:
1140 * @device: a #ClutterInputDevice
1142 * Retrieves the number of axes available on @device.
1144 * Return value: the number of axes on the device
1149 clutter_input_device_get_n_axes (ClutterInputDevice *device)
1151 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
1153 if (device->axes != NULL)
1154 return device->axes->len;
1160 * clutter_input_device_set_n_keys:
1161 * @device: a #ClutterInputDevice
1162 * @n_keys: the number of keys of the device
1164 * Initializes the keys of @device.
1166 * Call clutter_input_device_set_key() on each key to set the keyval
1170 _clutter_input_device_set_n_keys (ClutterInputDevice *device,
1173 if (device->keys != NULL)
1174 g_array_free (device->keys, TRUE);
1176 device->n_keys = n_keys;
1177 device->keys = g_array_sized_new (FALSE, TRUE,
1178 sizeof (ClutterKeyInfo),
1183 * clutter_input_device_get_n_keys:
1184 * @device: a #ClutterInputDevice
1186 * Retrieves the number of keys registered for @device.
1188 * Return value: the number of registered keys
1193 clutter_input_device_get_n_keys (ClutterInputDevice *device)
1195 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
1197 return device->n_keys;
1201 * clutter_input_device_set_key:
1202 * @device: a #ClutterInputDevice
1203 * @index_: the index of the key
1204 * @keyval: the keyval
1205 * @modifiers: a bitmask of modifiers
1207 * Sets the keyval and modifiers at the given @index_ for @device.
1209 * Clutter will use the keyval and modifiers set when filling out
1210 * an event coming from the same input device.
1215 clutter_input_device_set_key (ClutterInputDevice *device,
1218 ClutterModifierType modifiers)
1220 ClutterKeyInfo *key_info;
1222 g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
1223 g_return_if_fail (index_ < device->n_keys);
1225 key_info = &g_array_index (device->keys, ClutterKeyInfo, index_);
1226 key_info->keyval = keyval;
1227 key_info->modifiers = modifiers;
1231 * clutter_input_device_get_key:
1232 * @device: a #ClutterInputDevice
1233 * @index_: the index of the key
1234 * @keyval: (out): return location for the keyval at @index_
1235 * @modifiers: (out): return location for the modifiers at @index_
1237 * Retrieves the key set using clutter_input_device_set_key()
1239 * Return value: %TRUE if a key was set at the given index
1244 clutter_input_device_get_key (ClutterInputDevice *device,
1247 ClutterModifierType *modifiers)
1249 ClutterKeyInfo *key_info;
1251 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
1253 if (device->keys == NULL)
1256 if (index_ > device->keys->len)
1259 key_info = &g_array_index (device->keys, ClutterKeyInfo, index_);
1261 if (!key_info->keyval && !key_info->modifiers)
1265 *keyval = key_info->keyval;
1268 *modifiers = key_info->modifiers;
1274 * clutter_input_device_add_slave:
1275 * @master: a #ClutterInputDevice
1276 * @slave: a #ClutterInputDevice
1278 * Adds @slave to the list of slave devices of @master
1280 * This function does not increase the reference count of either @master
1284 _clutter_input_device_add_slave (ClutterInputDevice *master,
1285 ClutterInputDevice *slave)
1287 if (g_list_find (master->slaves, slave) == NULL)
1288 master->slaves = g_list_prepend (master->slaves, slave);
1292 * clutter_input_device_remove_slave:
1293 * @master: a #ClutterInputDevice
1294 * @slave: a #ClutterInputDevice
1296 * Removes @slave from the list of slave devices of @master.
1298 * This function does not decrease the reference count of either @master
1302 _clutter_input_device_remove_slave (ClutterInputDevice *master,
1303 ClutterInputDevice *slave)
1305 if (g_list_find (master->slaves, slave) != NULL)
1306 master->slaves = g_list_remove (master->slaves, slave);
1310 * clutter_input_device_get_slave_devices:
1311 * @device: a #ClutterInputDevice
1313 * Retrieves the slave devices attached to @device.
1315 * Return value: (transfer container) (element-type Clutter.InputDevice): a
1316 * list of #ClutterInputDevice, or %NULL. The contents of the list are
1317 * owned by the device. Use g_list_free() when done
1322 clutter_input_device_get_slave_devices (ClutterInputDevice *device)
1324 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
1326 return g_list_copy (device->slaves);
1330 * clutter_input_device_set_associated_device:
1331 * @device: a #ClutterInputDevice
1332 * @associated: (allow-none): a #ClutterInputDevice, or %NULL
1334 * Sets the associated device for @device.
1336 * This function keeps a reference on the associated device.
1339 _clutter_input_device_set_associated_device (ClutterInputDevice *device,
1340 ClutterInputDevice *associated)
1342 if (device->associated == associated)
1345 if (device->associated != NULL)
1346 g_object_unref (device->associated);
1348 device->associated = associated;
1349 if (device->associated != NULL)
1350 g_object_ref (device->associated);
1352 CLUTTER_NOTE (MISC, "Associating device '%s' to device '%s'",
1353 clutter_input_device_get_device_name (device),
1354 device->associated != NULL
1355 ? clutter_input_device_get_device_name (device->associated)
1358 if (device->device_mode != CLUTTER_INPUT_MODE_MASTER)
1360 if (device->associated != NULL)
1361 device->device_mode = CLUTTER_INPUT_MODE_SLAVE;
1363 device->device_mode = CLUTTER_INPUT_MODE_FLOATING;
1365 g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_DEVICE_MODE]);
1370 * clutter_input_device_get_associated_device:
1371 * @device: a #ClutterInputDevice
1373 * Retrieves a pointer to the #ClutterInputDevice that has been
1374 * associated to @device.
1376 * If the #ClutterInputDevice:device-mode property of @device is
1377 * set to %CLUTTER_INPUT_MODE_MASTER, this function will return
1380 * Return value: (transfer none): a #ClutterInputDevice, or %NULL
1384 ClutterInputDevice *
1385 clutter_input_device_get_associated_device (ClutterInputDevice *device)
1387 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
1389 return device->associated;
1393 * clutter_input_device_select_stage_events:
1394 * @device: a #ClutterInputDevice
1395 * @stage: the #ClutterStage to select events on
1396 * @event_mask: platform-specific mask of events
1398 * Selects input device events on @stage.
1400 * The implementation of this function depends on the backend used.
1403 _clutter_input_device_select_stage_events (ClutterInputDevice *device,
1404 ClutterStage *stage,
1407 ClutterInputDeviceClass *device_class;
1409 device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device);
1410 if (device_class->select_stage_events != NULL)
1411 device_class->select_stage_events (device, stage, event_mask);
1415 * clutter_input_device_keycode_to_evdev:
1416 * @device: A #ClutterInputDevice
1417 * @hardware_keycode: The hardware keycode from a #ClutterKeyEvent
1418 * @evdev_keycode: The return location for the evdev keycode
1420 * Translates a hardware keycode from a #ClutterKeyEvent to the
1421 * equivalent evdev keycode. Note that depending on the input backend
1422 * used by Clutter this function can fail if there is no obvious
1423 * mapping between the key codes. The hardware keycode can be taken
1424 * from the #ClutterKeyEvent.hardware_keycode member of #ClutterKeyEvent.
1426 * Return value: %TRUE if the conversion succeeded, %FALSE otherwise.
1431 clutter_input_device_keycode_to_evdev (ClutterInputDevice *device,
1432 guint hardware_keycode,
1433 guint *evdev_keycode)
1435 ClutterInputDeviceClass *device_class;
1437 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
1439 device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device);
1440 if (device_class->keycode_to_evdev == NULL)
1443 return device_class->keycode_to_evdev (device,
1449 _clutter_input_device_add_scroll_info (ClutterInputDevice *device,
1451 ClutterScrollDirection direction,
1454 ClutterScrollInfo info;
1456 g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
1457 g_return_if_fail (index_ < clutter_input_device_get_n_axes (device));
1459 info.axis_id = index_;
1460 info.direction = direction;
1461 info.increment = increment;
1462 info.last_value_valid = FALSE;
1464 if (device->scroll_info == NULL)
1466 device->scroll_info = g_array_new (FALSE,
1468 sizeof (ClutterScrollInfo));
1471 g_array_append_val (device->scroll_info, info);
1475 _clutter_input_device_get_scroll_delta (ClutterInputDevice *device,
1478 ClutterScrollDirection *direction_p,
1483 g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
1484 g_return_val_if_fail (index_ < clutter_input_device_get_n_axes (device), FALSE);
1486 if (device->scroll_info == NULL)
1489 for (i = 0; i < device->scroll_info->len; i++)
1491 ClutterScrollInfo *info = &g_array_index (device->scroll_info,
1495 if (info->axis_id == index_)
1497 if (direction_p != NULL)
1498 *direction_p = info->direction;
1500 if (delta_p != NULL)
1503 if (info->last_value_valid)
1505 if (delta_p != NULL)
1507 *delta_p = (value - info->last_value)
1511 info->last_value = value;
1515 info->last_value = value;
1516 info->last_value_valid = TRUE;
1527 _clutter_input_device_reset_scroll_info (ClutterInputDevice *device)
1531 if (device->scroll_info == NULL)
1534 for (i = 0; i < device->scroll_info->len; i++)
1536 ClutterScrollInfo *info = &g_array_index (device->scroll_info,
1540 info->last_value_valid = FALSE;