3d37602c54
This does two things to frown upon: - Modifies ClutterEvent structs, while the effort is to have those completely opaque, and readonly after creation from the input thread side. - Stores state in the ClutterInputDevice struct, event though those are also considered static after creation, managed by the input thread, etc. Stop doing that. This makes all events just forwarded as-is in the ClutterStage/clutter-main.c code. Handling of click count sounds like material for a ClutterGestureAction (or perhaps ClutterClickAction), all of both callers now do it in place at the moment, while gestures lack a better state tracking and management. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2024>
1024 lines
27 KiB
C
1024 lines
27 KiB
C
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
|
|
*/
|
|
|
|
/**
|
|
* 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 <math.h>
|
|
|
|
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;
|
|
}
|