/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Copyright © 2009, 2010, 2011 Intel Corp. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Author: Emmanuele Bassi */ /** * SECTION:clutter-input-device * @short_description: An input device managed by Clutter * * #ClutterInputDevice represents an input device known to Clutter. * * The #ClutterInputDevice class holds the state of the device, but * its contents are usually defined by the Clutter backend in use. */ #include "clutter-build-config.h" #include "clutter-input-device.h" #include "clutter-actor-private.h" #include "clutter-debug.h" #include "clutter-enum-types.h" #include "clutter-event-private.h" #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-stage-private.h" #include "clutter-input-device-private.h" #include "clutter-input-device-tool.h" #include enum { PROP_0, PROP_BACKEND, PROP_NAME, PROP_DEVICE_TYPE, PROP_SEAT, PROP_DEVICE_MODE, PROP_HAS_CURSOR, PROP_VENDOR_ID, PROP_PRODUCT_ID, PROP_N_STRIPS, PROP_N_RINGS, PROP_N_MODE_GROUPS, PROP_N_BUTTONS, PROP_DEVICE_NODE, PROP_LAST }; static GParamSpec *obj_props[PROP_LAST] = { NULL, }; typedef struct _ClutterInputDevicePrivate ClutterInputDevicePrivate; struct _ClutterInputDevicePrivate { ClutterInputDeviceType device_type; ClutterInputMode device_mode; char *device_name; ClutterSeat *seat; ClutterBackend *backend; char *vendor_id; char *product_id; char *node_path; int n_rings; int n_strips; int n_mode_groups; int n_buttons; gboolean has_cursor; }; G_DEFINE_TYPE_WITH_PRIVATE (ClutterInputDevice, clutter_input_device, G_TYPE_OBJECT); static void clutter_input_device_dispose (GObject *gobject) { ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (gobject); ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_clear_pointer (&priv->device_name, g_free); g_clear_pointer (&priv->vendor_id, g_free); g_clear_pointer (&priv->product_id, g_free); g_clear_pointer (&priv->node_path, g_free); if (device->accessibility_virtual_device) g_clear_object (&device->accessibility_virtual_device); G_OBJECT_CLASS (clutter_input_device_parent_class)->dispose (gobject); } static void clutter_input_device_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterInputDevice *self = CLUTTER_INPUT_DEVICE (gobject); ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (self); switch (prop_id) { case PROP_DEVICE_TYPE: priv->device_type = g_value_get_enum (value); break; case PROP_SEAT: priv->seat = g_value_get_object (value); break; case PROP_DEVICE_MODE: priv->device_mode = g_value_get_enum (value); break; case PROP_BACKEND: priv->backend = g_value_get_object (value); break; case PROP_NAME: priv->device_name = g_value_dup_string (value); break; case PROP_HAS_CURSOR: priv->has_cursor = g_value_get_boolean (value); break; case PROP_VENDOR_ID: priv->vendor_id = g_value_dup_string (value); break; case PROP_PRODUCT_ID: priv->product_id = g_value_dup_string (value); break; case PROP_N_RINGS: priv->n_rings = g_value_get_int (value); break; case PROP_N_STRIPS: priv->n_strips = g_value_get_int (value); break; case PROP_N_MODE_GROUPS: priv->n_mode_groups = g_value_get_int (value); break; case PROP_N_BUTTONS: priv->n_buttons = g_value_get_int (value); break; case PROP_DEVICE_NODE: priv->node_path = g_value_dup_string (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_input_device_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterInputDevice *self = CLUTTER_INPUT_DEVICE (gobject); ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (self); switch (prop_id) { case PROP_DEVICE_TYPE: g_value_set_enum (value, priv->device_type); break; case PROP_SEAT: g_value_set_object (value, priv->seat); break; case PROP_DEVICE_MODE: g_value_set_enum (value, priv->device_mode); break; case PROP_BACKEND: g_value_set_object (value, priv->backend); break; case PROP_NAME: g_value_set_string (value, priv->device_name); break; case PROP_HAS_CURSOR: g_value_set_boolean (value, priv->has_cursor); break; case PROP_VENDOR_ID: g_value_set_string (value, priv->vendor_id); break; case PROP_PRODUCT_ID: g_value_set_string (value, priv->product_id); break; case PROP_N_RINGS: g_value_set_int (value, priv->n_rings); break; case PROP_N_STRIPS: g_value_set_int (value, priv->n_strips); break; case PROP_N_MODE_GROUPS: g_value_set_int (value, priv->n_mode_groups); break; case PROP_N_BUTTONS: g_value_set_int (value, priv->n_buttons); break; case PROP_DEVICE_NODE: g_value_set_string (value, priv->node_path); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void clutter_input_device_class_init (ClutterInputDeviceClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); /** * ClutterInputDevice:name: * * The name of the device * * Since: 1.2 */ obj_props[PROP_NAME] = g_param_spec_string ("name", P_("Name"), P_("The name of the device"), NULL, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterInputDevice:device-type: * * The type of the device * * Since: 1.2 */ obj_props[PROP_DEVICE_TYPE] = g_param_spec_enum ("device-type", P_("Device Type"), P_("The type of the device"), CLUTTER_TYPE_INPUT_DEVICE_TYPE, CLUTTER_POINTER_DEVICE, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterInputDevice:seat: * * The #ClutterSeat instance which owns the device */ obj_props[PROP_SEAT] = g_param_spec_object ("seat", P_("Seat"), P_("Seat"), CLUTTER_TYPE_SEAT, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterInputDevice:mode: * * The mode of the device. * * Since: 1.6 */ obj_props[PROP_DEVICE_MODE] = g_param_spec_enum ("device-mode", P_("Device Mode"), P_("The mode of the device"), CLUTTER_TYPE_INPUT_MODE, CLUTTER_INPUT_MODE_FLOATING, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterInputDevice:has-cursor: * * Whether the device has an on screen cursor following its movement. * * Since: 1.6 */ obj_props[PROP_HAS_CURSOR] = g_param_spec_boolean ("has-cursor", P_("Has Cursor"), P_("Whether the device has a cursor"), FALSE, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterInputDevice:backend: * * The #ClutterBackend that created the device. * * Since: 1.6 */ obj_props[PROP_BACKEND] = g_param_spec_object ("backend", P_("Backend"), P_("The backend instance"), CLUTTER_TYPE_BACKEND, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterInputDevice:vendor-id: * * Vendor ID of this device. * * Since: 1.22 */ obj_props[PROP_VENDOR_ID] = g_param_spec_string ("vendor-id", P_("Vendor ID"), P_("Vendor ID"), NULL, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * ClutterInputDevice:product-id: * * Product ID of this device. * * Since: 1.22 */ obj_props[PROP_PRODUCT_ID] = g_param_spec_string ("product-id", P_("Product ID"), P_("Product ID"), NULL, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); obj_props[PROP_N_RINGS] = g_param_spec_int ("n-rings", P_("Number of rings"), P_("Number of rings (circular sliders) in this device"), 0, G_MAXINT, 0, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); obj_props[PROP_N_STRIPS] = g_param_spec_int ("n-strips", P_("Number of strips"), P_("Number of strips (linear sliders) in this device"), 0, G_MAXINT, 0, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); obj_props[PROP_N_MODE_GROUPS] = g_param_spec_int ("n-mode-groups", P_("Number of mode groups"), P_("Number of mode groups"), 0, G_MAXINT, 0, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); obj_props[PROP_N_BUTTONS] = g_param_spec_int ("n-buttons", P_("Number of buttons"), P_("Number of buttons"), 0, G_MAXINT, 0, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); obj_props[PROP_DEVICE_NODE] = g_param_spec_string ("device-node", P_("Device node path"), P_("Device node path"), NULL, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); gobject_class->dispose = clutter_input_device_dispose; gobject_class->set_property = clutter_input_device_set_property; gobject_class->get_property = clutter_input_device_get_property; g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); } static void clutter_input_device_init (ClutterInputDevice *self) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (self); priv->device_type = CLUTTER_POINTER_DEVICE; } /** * clutter_input_device_get_device_type: * @device: a #ClutterInputDevice * * Retrieves the type of @device * * Return value: the type of the device * * Since: 1.0 */ ClutterInputDeviceType clutter_input_device_get_device_type (ClutterInputDevice *device) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), CLUTTER_POINTER_DEVICE); return priv->device_type; } /** * clutter_input_device_get_device_name: * @device: a #ClutterInputDevice * * Retrieves the name of the @device * * Return value: the name of the device, or %NULL. The returned string * is owned by the #ClutterInputDevice and should never be modified * or freed * * Since: 1.2 */ const gchar * clutter_input_device_get_device_name (ClutterInputDevice *device) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); return priv->device_name; } /** * clutter_input_device_get_has_cursor: * @device: a #ClutterInputDevice * * Retrieves whether @device has a pointer that follows the * device motion. * * Return value: %TRUE if the device has a cursor * * Since: 1.6 */ gboolean clutter_input_device_get_has_cursor (ClutterInputDevice *device) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); return priv->has_cursor; } /** * clutter_input_device_get_device_mode: * @device: a #ClutterInputDevice * * Retrieves the #ClutterInputMode of @device. * * Return value: the device mode * * Since: 1.6 */ ClutterInputMode clutter_input_device_get_device_mode (ClutterInputDevice *device) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), CLUTTER_INPUT_MODE_FLOATING); return priv->device_mode; } static void on_grab_actor_destroy (ClutterActor *actor, ClutterInputDevice *device) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); switch (priv->device_type) { case CLUTTER_POINTER_DEVICE: case CLUTTER_TABLET_DEVICE: device->pointer_grab_actor = NULL; break; case CLUTTER_KEYBOARD_DEVICE: device->keyboard_grab_actor = NULL; break; default: g_assert_not_reached (); } } /** * clutter_input_device_grab: * @device: a #ClutterInputDevice * @actor: a #ClutterActor * * Acquires a grab on @actor for the given @device. * * Any event coming from @device will be delivered to @actor, bypassing * the usual event delivery mechanism, until the grab is released by * calling clutter_input_device_ungrab(). * * The grab is client-side: even if the windowing system used by the Clutter * backend has the concept of "device grabs", Clutter will not use them. * * Only #ClutterInputDevice of types %CLUTTER_POINTER_DEVICE, * %CLUTTER_TABLET_DEVICE and %CLUTTER_KEYBOARD_DEVICE can hold a grab. * * Since: 1.10 */ void clutter_input_device_grab (ClutterInputDevice *device, ClutterActor *actor) { ClutterActor **grab_actor; ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); switch (priv->device_type) { case CLUTTER_POINTER_DEVICE: case CLUTTER_TABLET_DEVICE: grab_actor = &device->pointer_grab_actor; break; case CLUTTER_KEYBOARD_DEVICE: grab_actor = &device->keyboard_grab_actor; break; default: g_critical ("Only pointer and keyboard devices can grab an actor"); return; } if (*grab_actor != NULL) { g_signal_handlers_disconnect_by_func (*grab_actor, G_CALLBACK (on_grab_actor_destroy), device); } *grab_actor = actor; g_signal_connect (*grab_actor, "destroy", G_CALLBACK (on_grab_actor_destroy), device); } /** * clutter_input_device_ungrab: * @device: a #ClutterInputDevice * * Releases the grab on the @device, if one is in place. * * Since: 1.10 */ void clutter_input_device_ungrab (ClutterInputDevice *device) { ClutterActor **grab_actor; ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); switch (priv->device_type) { case CLUTTER_POINTER_DEVICE: case CLUTTER_TABLET_DEVICE: grab_actor = &device->pointer_grab_actor; break; case CLUTTER_KEYBOARD_DEVICE: grab_actor = &device->keyboard_grab_actor; break; default: return; } if (*grab_actor == NULL) return; g_signal_handlers_disconnect_by_func (*grab_actor, G_CALLBACK (on_grab_actor_destroy), device); *grab_actor = NULL; } /** * clutter_input_device_get_grabbed_actor: * @device: a #ClutterInputDevice * * Retrieves a pointer to the #ClutterActor currently grabbing all * the events coming from @device. * * Return value: (transfer none): a #ClutterActor, or %NULL * * Since: 1.10 */ ClutterActor * clutter_input_device_get_grabbed_actor (ClutterInputDevice *device) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); switch (priv->device_type) { case CLUTTER_POINTER_DEVICE: case CLUTTER_TABLET_DEVICE: return device->pointer_grab_actor; case CLUTTER_KEYBOARD_DEVICE: return device->keyboard_grab_actor; default: g_critical ("Only pointer and keyboard devices can grab an actor"); } return NULL; } static void on_grab_sequence_actor_destroy (ClutterActor *actor, ClutterInputDevice *device) { ClutterEventSequence *sequence = g_hash_table_lookup (device->inv_sequence_grab_actors, actor); if (sequence != NULL) { g_hash_table_remove (device->sequence_grab_actors, sequence); g_hash_table_remove (device->inv_sequence_grab_actors, actor); } } /** * clutter_input_device_sequence_grab: * @device: a #ClutterInputDevice * @sequence: a #ClutterEventSequence * @actor: a #ClutterActor * * Acquires a grab on @actor for the given @device and the given touch * @sequence. * * Any touch event coming from @device and from @sequence will be * delivered to @actor, bypassing the usual event delivery mechanism, * until the grab is released by calling * clutter_input_device_sequence_ungrab(). * * The grab is client-side: even if the windowing system used by the Clutter * backend has the concept of "device grabs", Clutter will not use them. * * Since: 1.12 */ void clutter_input_device_sequence_grab (ClutterInputDevice *device, ClutterEventSequence *sequence, ClutterActor *actor) { ClutterActor *grab_actor; g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); if (device->sequence_grab_actors == NULL) { grab_actor = NULL; device->sequence_grab_actors = g_hash_table_new (NULL, NULL); device->inv_sequence_grab_actors = g_hash_table_new (NULL, NULL); } else { grab_actor = g_hash_table_lookup (device->sequence_grab_actors, sequence); } if (grab_actor != NULL) { g_signal_handlers_disconnect_by_func (grab_actor, G_CALLBACK (on_grab_sequence_actor_destroy), device); g_hash_table_remove (device->sequence_grab_actors, sequence); g_hash_table_remove (device->inv_sequence_grab_actors, grab_actor); } g_hash_table_insert (device->sequence_grab_actors, sequence, actor); g_hash_table_insert (device->inv_sequence_grab_actors, actor, sequence); g_signal_connect (actor, "destroy", G_CALLBACK (on_grab_sequence_actor_destroy), device); } /** * clutter_input_device_sequence_ungrab: * @device: a #ClutterInputDevice * @sequence: a #ClutterEventSequence * * Releases the grab on the @device for the given @sequence, if one is * in place. * * Since: 1.12 */ void clutter_input_device_sequence_ungrab (ClutterInputDevice *device, ClutterEventSequence *sequence) { ClutterActor *grab_actor; g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); if (device->sequence_grab_actors == NULL) return; grab_actor = g_hash_table_lookup (device->sequence_grab_actors, sequence); if (grab_actor == NULL) return; g_signal_handlers_disconnect_by_func (grab_actor, G_CALLBACK (on_grab_sequence_actor_destroy), device); g_hash_table_remove (device->sequence_grab_actors, sequence); g_hash_table_remove (device->inv_sequence_grab_actors, grab_actor); if (g_hash_table_size (device->sequence_grab_actors) == 0) { g_hash_table_destroy (device->sequence_grab_actors); device->sequence_grab_actors = NULL; g_hash_table_destroy (device->inv_sequence_grab_actors); device->inv_sequence_grab_actors = NULL; } } /** * clutter_input_device_sequence_get_grabbed_actor: * @device: a #ClutterInputDevice * @sequence: a #ClutterEventSequence * * Retrieves a pointer to the #ClutterActor currently grabbing the * touch events coming from @device given the @sequence. * * Return value: (transfer none): a #ClutterActor, or %NULL * * Since: 1.12 */ ClutterActor * clutter_input_device_sequence_get_grabbed_actor (ClutterInputDevice *device, ClutterEventSequence *sequence) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); if (device->sequence_grab_actors == NULL) return NULL; return g_hash_table_lookup (device->sequence_grab_actors, sequence); } /** * clutter_input_device_get_vendor_id: * @device: a physical #ClutterInputDevice * * Gets the vendor ID of this device. * * Returns: the vendor ID * * Since: 1.22 */ const gchar * clutter_input_device_get_vendor_id (ClutterInputDevice *device) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); g_return_val_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_LOGICAL, NULL); return priv->vendor_id; } /** * clutter_input_device_get_product_id: * @device: a physical #ClutterInputDevice * * Gets the product ID of this device. * * Returns: the product ID * * Since: 1.22 */ const gchar * clutter_input_device_get_product_id (ClutterInputDevice *device) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); g_return_val_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_LOGICAL, NULL); return priv->product_id; } gint clutter_input_device_get_n_rings (ClutterInputDevice *device) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); return priv->n_rings; } gint clutter_input_device_get_n_strips (ClutterInputDevice *device) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); return priv->n_strips; } gint clutter_input_device_get_n_mode_groups (ClutterInputDevice *device) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); g_return_val_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE, 0); return priv->n_mode_groups; } gint clutter_input_device_get_n_buttons (ClutterInputDevice *device) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); g_return_val_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE, 0); return priv->n_buttons; } gint clutter_input_device_get_group_n_modes (ClutterInputDevice *device, gint group) { ClutterInputDeviceClass *device_class; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); g_return_val_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE, 0); g_return_val_if_fail (group >= 0, 0); device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device); if (device_class->get_group_n_modes) return device_class->get_group_n_modes (device, group); return 0; } gboolean clutter_input_device_is_mode_switch_button (ClutterInputDevice *device, guint group, guint button) { ClutterInputDeviceClass *device_class; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); g_return_val_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE, FALSE); device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device); if (device_class->is_mode_switch_button) return device_class->is_mode_switch_button (device, group, button); return FALSE; } gint clutter_input_device_get_mode_switch_button_group (ClutterInputDevice *device, guint button) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); gint group; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), -1); g_return_val_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE, -1); for (group = 0; group < priv->n_mode_groups; group++) { if (clutter_input_device_is_mode_switch_button (device, group, button)) return group; } return -1; } int clutter_input_device_get_pad_feature_group (ClutterInputDevice *device, ClutterInputDevicePadFeature feature, int n_feature) { ClutterInputDeviceClass *device_class; device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device); if (!device_class->get_pad_feature_group) return 0; return CLUTTER_INPUT_DEVICE_GET_CLASS (device)->get_pad_feature_group (device, feature, n_feature); } const gchar * clutter_input_device_get_device_node (ClutterInputDevice *device) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); return priv->node_path; } gboolean clutter_input_device_is_grouped (ClutterInputDevice *device, ClutterInputDevice *other_device) { g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (other_device), FALSE); return CLUTTER_INPUT_DEVICE_GET_CLASS (device)->is_grouped (device, other_device); } /** * clutter_input_device_get_seat: * @device: a #ClutterInputDevice * * Returns the seat the device belongs to * * Returns: (transfer none): the device seat **/ ClutterSeat * clutter_input_device_get_seat (ClutterInputDevice *device) { ClutterInputDevicePrivate *priv = clutter_input_device_get_instance_private (device); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); return priv->seat; }