diff options
Diffstat (limited to 'clutter/clutter/clutter-gesture-action.c')
-rw-r--r-- | clutter/clutter/clutter-gesture-action.c | 1455 |
1 files changed, 0 insertions, 1455 deletions
diff --git a/clutter/clutter/clutter-gesture-action.c b/clutter/clutter/clutter-gesture-action.c deleted file mode 100644 index f938a549a..000000000 --- a/clutter/clutter/clutter-gesture-action.c +++ /dev/null @@ -1,1455 +0,0 @@ -/* - * Clutter. - * - * An OpenGL based 'interactive canvas' library. - * - * Copyright (C) 2010 Intel Corporation. - * Copyright (C) 2011 Robert Bosch Car Multimedia GmbH. - * Copyright (C) 2012 Intel Corporation. - * - * 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: - * Tomeu Vizoso <tomeu.vizoso@collabora.co.uk> - */ - -/** - * SECTION:clutter-gesture-action - * @Title: ClutterGestureAction - * @Short_Description: Action for gesture gestures - * - * #ClutterGestureAction is a sub-class of #ClutterAction that implements - * the logic for recognizing gesture gestures. It listens for low level events - * such as #ClutterButtonEvent and #ClutterMotionEvent on the stage to raise - * the #ClutterGestureAction::gesture-begin, #ClutterGestureAction::gesture-progress, - * and #ClutterGestureAction::gesture-end signals. - * - * To use #ClutterGestureAction you just need to apply it to a #ClutterActor - * using clutter_actor_add_action() and connect to the signals: - * - * |[<!-- language="C" --> - * ClutterAction *action = clutter_gesture_action_new (); - * - * clutter_actor_add_action (actor, action); - * - * g_signal_connect (action, "gesture-begin", G_CALLBACK (on_gesture_begin), NULL); - * g_signal_connect (action, "gesture-progress", G_CALLBACK (on_gesture_progress), NULL); - * g_signal_connect (action, "gesture-end", G_CALLBACK (on_gesture_end), NULL); - * ]| - * - * ## Creating Gesture actions - * - * A #ClutterGestureAction provides four separate states that can be - * used to recognize or ignore gestures when writing a new action class: - * - * - Prepare -> Cancel - * - Prepare -> Begin -> Cancel - * - Prepare -> Begin -> End - * - Prepare -> Begin -> Progress -> Cancel - * - Prepare -> Begin -> Progress -> End - * - * Each #ClutterGestureAction starts in the "prepare" state, and calls - * the #ClutterGestureActionClass.gesture_prepare() virtual function; this - * state can be used to reset the internal state of a #ClutterGestureAction - * subclass, but it can also immediately cancel a gesture without going - * through the rest of the states. - * - * The "begin" state follows the "prepare" state, and calls the - * #ClutterGestureActionClass.gesture_begin() virtual function. This state - * signals the start of a gesture recognizing process. From the "begin" state - * the gesture recognition process can successfully end, by going to the - * "end" state; it can continue in the "progress" state, in case of a - * continuous gesture; or it can be terminated, by moving to the "cancel" - * state. - * - * In case of continuous gestures, the #ClutterGestureAction will use - * the "progress" state, calling the #ClutterGestureActionClass.gesture_progress() - * virtual function; the "progress" state will continue until the end of the - * gesture, in which case the "end" state will be reached, or until the - * gesture is cancelled, in which case the "cancel" gesture will be used - * instead. - * - * Since: 1.8 - */ - -#include "clutter-build-config.h" - -#include "clutter-gesture-action-private.h" - -#include "clutter-debug.h" -#include "clutter-enum-types.h" -#include "clutter-marshal.h" -#include "clutter-private.h" - -#include <math.h> - -#define MAX_GESTURE_POINTS (10) -#define FLOAT_EPSILON (1e-15) - -typedef struct -{ - ClutterInputDevice *device; - ClutterEventSequence *sequence; - ClutterEvent *last_event; - - gfloat press_x, press_y; - gint64 last_motion_time; - gfloat last_motion_x, last_motion_y; - gint64 last_delta_time; - gfloat last_delta_x, last_delta_y; - gfloat release_x, release_y; -} GesturePoint; - -struct _ClutterGestureActionPrivate -{ - ClutterActor *stage; - - gint requested_nb_points; - GArray *points; - - gulong actor_capture_id; - gulong stage_capture_id; - - ClutterGestureTriggerEdge edge; - float distance_x, distance_y; - - guint in_gesture : 1; -}; - -enum -{ - PROP_0, - - PROP_N_TOUCH_POINTS, - PROP_THRESHOLD_TRIGGER_EDGE, - PROP_THRESHOLD_TRIGGER_DISTANCE_X, - PROP_THRESHOLD_TRIGGER_DISTANCE_Y, - - PROP_LAST -}; - -enum -{ - GESTURE_BEGIN, - GESTURE_PROGRESS, - GESTURE_END, - GESTURE_CANCEL, - - LAST_SIGNAL -}; - -static GParamSpec *gesture_props[PROP_LAST]; -static guint gesture_signals[LAST_SIGNAL] = { 0, }; - -G_DEFINE_TYPE_WITH_PRIVATE (ClutterGestureAction, clutter_gesture_action, CLUTTER_TYPE_ACTION) - -static GesturePoint * -gesture_register_point (ClutterGestureAction *action, ClutterEvent *event) -{ - ClutterGestureActionPrivate *priv = - clutter_gesture_action_get_instance_private (action); - GesturePoint *point = NULL; - - if (priv->points->len >= MAX_GESTURE_POINTS) - return NULL; - - g_array_set_size (priv->points, priv->points->len + 1); - point = &g_array_index (priv->points, GesturePoint, priv->points->len - 1); - - point->last_event = clutter_event_copy (event); - point->device = clutter_event_get_device (event); - - clutter_event_get_coords (event, &point->press_x, &point->press_y); - point->last_motion_x = point->press_x; - point->last_motion_y = point->press_y; - point->last_motion_time = clutter_event_get_time (event); - - point->last_delta_x = point->last_delta_y = 0; - point->last_delta_time = 0; - - if (clutter_event_type (event) != CLUTTER_BUTTON_PRESS) - point->sequence = clutter_event_get_event_sequence (event); - else - point->sequence = NULL; - - return point; -} - -static GesturePoint * -gesture_find_point (ClutterGestureAction *action, - ClutterEvent *event, - gint *position) -{ - ClutterGestureActionPrivate *priv = - clutter_gesture_action_get_instance_private (action); - GesturePoint *point = NULL; - ClutterEventType type = clutter_event_type (event); - ClutterInputDevice *device = clutter_event_get_device (event); - ClutterEventSequence *sequence = NULL; - gint i; - - if ((type != CLUTTER_BUTTON_PRESS) && - (type != CLUTTER_BUTTON_RELEASE) && - (type != CLUTTER_MOTION)) - sequence = clutter_event_get_event_sequence (event); - - for (i = 0; i < priv->points->len; i++) - { - if ((g_array_index (priv->points, GesturePoint, i).device == device) && - (g_array_index (priv->points, GesturePoint, i).sequence == sequence)) - { - if (position != NULL) - *position = i; - point = &g_array_index (priv->points, GesturePoint, i); - break; - } - } - - return point; -} - -static void -gesture_unregister_point (ClutterGestureAction *action, gint position) -{ - ClutterGestureActionPrivate *priv = - clutter_gesture_action_get_instance_private (action); - - if (priv->points->len == 0) - return; - - g_array_remove_index (priv->points, position); -} - -static void -gesture_update_motion_point (GesturePoint *point, - ClutterEvent *event) -{ - gfloat motion_x, motion_y; - gint64 _time; - - clutter_event_get_coords (event, &motion_x, &motion_y); - - clutter_event_free (point->last_event); - point->last_event = clutter_event_copy (event); - - point->last_delta_x = motion_x - point->last_motion_x; - point->last_delta_y = motion_y - point->last_motion_y; - point->last_motion_x = motion_x; - point->last_motion_y = motion_y; - - _time = clutter_event_get_time (event); - point->last_delta_time = _time - point->last_motion_time; - point->last_motion_time = _time; -} - -static void -gesture_update_release_point (GesturePoint *point, - ClutterEvent *event) -{ - gint64 _time; - - clutter_event_get_coords (event, &point->release_x, &point->release_y); - - clutter_event_free (point->last_event); - point->last_event = clutter_event_copy (event); - - /* Treat the release event as the continuation of the last motion, - * in case the user keeps the pointer still for a while before - * releasing it. */ - _time = clutter_event_get_time (event); - point->last_delta_time += _time - point->last_motion_time; -} - -static gint -gesture_get_default_threshold (void) -{ - gint threshold; - ClutterSettings *settings = clutter_settings_get_default (); - g_object_get (settings, "dnd-drag-threshold", &threshold, NULL); - return threshold; -} - -static gboolean -gesture_point_pass_threshold (ClutterGestureAction *action, - GesturePoint *point, - ClutterEvent *event) -{ - float threshold_x, threshold_y; - gfloat motion_x, motion_y; - - clutter_event_get_coords (event, &motion_x, &motion_y); - clutter_gesture_action_get_threshold_trigger_distance (action, &threshold_x, &threshold_y); - - if ((fabsf (point->press_y - motion_y) < threshold_y) && - (fabsf (point->press_x - motion_x) < threshold_x)) - return TRUE; - return FALSE; -} - -static void -gesture_point_unset (GesturePoint *point) -{ - clutter_event_free (point->last_event); -} - -static void -cancel_gesture (ClutterGestureAction *action) -{ - ClutterGestureActionPrivate *priv = - clutter_gesture_action_get_instance_private (action); - ClutterActor *actor; - - priv->in_gesture = FALSE; - - g_clear_signal_handler (&priv->stage_capture_id, priv->stage); - - actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); - g_signal_emit (action, gesture_signals[GESTURE_CANCEL], 0, actor); - - g_array_set_size (priv->points, 0); -} - -static gboolean -begin_gesture (ClutterGestureAction *action, - ClutterActor *actor) -{ - ClutterGestureActionPrivate *priv = - clutter_gesture_action_get_instance_private (action); - gboolean return_value; - - priv->in_gesture = TRUE; - - if (!CLUTTER_GESTURE_ACTION_GET_CLASS (action)->gesture_prepare (action, actor)) - { - cancel_gesture (action); - return FALSE; - } - - /* clutter_gesture_action_cancel() may have been called during - * gesture_prepare(), check that the gesture is still active. */ - if (!priv->in_gesture) - return FALSE; - - g_signal_emit (action, gesture_signals[GESTURE_BEGIN], 0, actor, - &return_value); - - if (!return_value) - { - cancel_gesture (action); - return FALSE; - } - - return TRUE; -} - -static gboolean -stage_captured_event_cb (ClutterActor *stage, - ClutterEvent *event, - ClutterGestureAction *action) -{ - ClutterGestureActionPrivate *priv = - clutter_gesture_action_get_instance_private (action); - ClutterActor *actor; - gint position; - float threshold_x, threshold_y; - gboolean return_value; - GesturePoint *point; - ClutterEventType event_type; - - event_type = clutter_event_type (event); - if (event_type != CLUTTER_TOUCH_CANCEL && - event_type != CLUTTER_TOUCH_UPDATE && - event_type != CLUTTER_TOUCH_END && - event_type != CLUTTER_MOTION && - event_type != CLUTTER_BUTTON_RELEASE) - return CLUTTER_EVENT_PROPAGATE; - - if ((point = gesture_find_point (action, event, &position)) == NULL) - return CLUTTER_EVENT_PROPAGATE; - - actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); - - switch (clutter_event_type (event)) - { - case CLUTTER_MOTION: - { - ClutterModifierType mods = clutter_event_get_state (event); - - /* we might miss a button-release event in case of grabs, - * so we need to check whether the button is still down - * during a motion event - */ - if (!(mods & CLUTTER_BUTTON1_MASK)) - { - cancel_gesture (action); - return CLUTTER_EVENT_PROPAGATE; - } - } - /* Follow same code path as a touch event update */ - - case CLUTTER_TOUCH_UPDATE: - if (!priv->in_gesture) - { - if (priv->points->len < priv->requested_nb_points) - { - gesture_update_motion_point (point, event); - return CLUTTER_EVENT_PROPAGATE; - } - - /* Wait until the drag threshold has been exceeded - * before starting _TRIGGER_EDGE_AFTER gestures. */ - if (priv->edge == CLUTTER_GESTURE_TRIGGER_EDGE_AFTER && - gesture_point_pass_threshold (action, point, event)) - { - gesture_update_motion_point (point, event); - return CLUTTER_EVENT_PROPAGATE; - } - - gesture_update_motion_point (point, event); - - if (!begin_gesture (action, actor)) - return CLUTTER_EVENT_PROPAGATE; - - if ((point = gesture_find_point (action, event, &position)) == NULL) - return CLUTTER_EVENT_PROPAGATE; - } - - gesture_update_motion_point (point, event); - - g_signal_emit (action, gesture_signals[GESTURE_PROGRESS], 0, actor, - &return_value); - if (!return_value) - { - cancel_gesture (action); - return CLUTTER_EVENT_PROPAGATE; - } - - /* Check if a _TRIGGER_EDGE_BEFORE gesture needs to be cancelled because - * the drag threshold has been exceeded. */ - clutter_gesture_action_get_threshold_trigger_distance (action, &threshold_x, &threshold_y); - if (priv->edge == CLUTTER_GESTURE_TRIGGER_EDGE_BEFORE && - ((fabsf (point->press_y - point->last_motion_y) > threshold_y) || - (fabsf (point->press_x - point->last_motion_x) > threshold_x))) - { - cancel_gesture (action); - return CLUTTER_EVENT_PROPAGATE; - } - break; - - case CLUTTER_BUTTON_RELEASE: - case CLUTTER_TOUCH_END: - { - gesture_update_release_point (point, event); - - if (priv->in_gesture && - ((priv->points->len - 1) < priv->requested_nb_points)) - { - priv->in_gesture = FALSE; - g_signal_emit (action, gesture_signals[GESTURE_END], 0, actor); - } - - gesture_unregister_point (action, position); - } - break; - - case CLUTTER_TOUCH_CANCEL: - { - gesture_update_release_point (point, event); - - if (priv->in_gesture) - { - priv->in_gesture = FALSE; - cancel_gesture (action); - } - - gesture_unregister_point (action, position); - } - break; - - default: - break; - } - - if (priv->points->len == 0) - g_clear_signal_handler (&priv->stage_capture_id, priv->stage); - - return CLUTTER_EVENT_PROPAGATE; -} - -static gboolean -actor_captured_event_cb (ClutterActor *actor, - ClutterEvent *event, - ClutterGestureAction *action) -{ - ClutterGestureActionPrivate *priv = - clutter_gesture_action_get_instance_private (action); - GesturePoint *point G_GNUC_UNUSED; - - if ((clutter_event_type (event) != CLUTTER_BUTTON_PRESS) && - (clutter_event_type (event) != CLUTTER_TOUCH_BEGIN)) - return CLUTTER_EVENT_PROPAGATE; - - if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (action))) - return CLUTTER_EVENT_PROPAGATE; - - point = gesture_register_point (action, event); - - if (priv->stage == NULL) - priv->stage = clutter_actor_get_stage (actor); - - if (priv->stage_capture_id == 0) - priv->stage_capture_id = - g_signal_connect_after (priv->stage, "captured-event", - G_CALLBACK (stage_captured_event_cb), - action); - - /* Start the gesture immediately if the gesture has no - * _TRIGGER_EDGE_AFTER drag threshold. */ - if ((priv->points->len >= priv->requested_nb_points) && - (priv->edge != CLUTTER_GESTURE_TRIGGER_EDGE_AFTER)) - begin_gesture (action, actor); - - return CLUTTER_EVENT_PROPAGATE; -} - -static void -clutter_gesture_action_set_actor (ClutterActorMeta *meta, - ClutterActor *actor) -{ - ClutterGestureActionPrivate *priv = - clutter_gesture_action_get_instance_private (CLUTTER_GESTURE_ACTION (meta)); - ClutterActorMetaClass *meta_class = - CLUTTER_ACTOR_META_CLASS (clutter_gesture_action_parent_class); - - if (priv->actor_capture_id != 0) - { - ClutterActor *old_actor = clutter_actor_meta_get_actor (meta); - - if (old_actor != NULL) - g_clear_signal_handler (&priv->actor_capture_id, old_actor); - - priv->actor_capture_id = 0; - } - - if (priv->stage_capture_id != 0) - { - if (priv->stage != NULL) - g_clear_signal_handler (&priv->stage_capture_id, priv->stage); - - priv->stage_capture_id = 0; - priv->stage = NULL; - } - - if (actor != NULL) - { - priv->actor_capture_id = - g_signal_connect (actor, "captured-event", - G_CALLBACK (actor_captured_event_cb), - meta); - } - - meta_class->set_actor (meta, actor); -} - -static void -clutter_gesture_action_set_enabled (ClutterActorMeta *meta, - gboolean is_enabled) -{ - ClutterActorMetaClass *meta_class = - CLUTTER_ACTOR_META_CLASS (clutter_gesture_action_parent_class); - ClutterGestureAction *gesture_action = CLUTTER_GESTURE_ACTION (meta); - ClutterGestureActionPrivate *priv = - clutter_gesture_action_get_instance_private (gesture_action); - - if (!is_enabled) - { - if (priv->in_gesture) - cancel_gesture (gesture_action); - else - g_array_set_size (priv->points, 0); - } - - meta_class->set_enabled (meta, is_enabled); -} - -static gboolean -default_event_handler (ClutterGestureAction *action, - ClutterActor *actor) -{ - return TRUE; -} - -static void -clutter_gesture_action_set_property (GObject *gobject, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - ClutterGestureAction *self = CLUTTER_GESTURE_ACTION (gobject); - ClutterGestureActionPrivate *priv = - clutter_gesture_action_get_instance_private (self); - - switch (prop_id) - { - case PROP_N_TOUCH_POINTS: - clutter_gesture_action_set_n_touch_points (self, g_value_get_int (value)); - break; - - case PROP_THRESHOLD_TRIGGER_EDGE: - clutter_gesture_action_set_threshold_trigger_edge (self, g_value_get_enum (value)); - break; - - case PROP_THRESHOLD_TRIGGER_DISTANCE_X: - clutter_gesture_action_set_threshold_trigger_distance (self, - g_value_get_float (value), - priv->distance_y); - break; - - case PROP_THRESHOLD_TRIGGER_DISTANCE_Y: - clutter_gesture_action_set_threshold_trigger_distance (self, - priv->distance_x, - g_value_get_float (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); - break; - } -} - -static void -clutter_gesture_action_get_property (GObject *gobject, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - ClutterGestureActionPrivate *priv = - clutter_gesture_action_get_instance_private (CLUTTER_GESTURE_ACTION (gobject)); - - switch (prop_id) - { - case PROP_N_TOUCH_POINTS: - g_value_set_int (value, priv->requested_nb_points); - break; - - case PROP_THRESHOLD_TRIGGER_EDGE: - g_value_set_enum (value, priv->edge); - break; - - case PROP_THRESHOLD_TRIGGER_DISTANCE_X: - if (priv->distance_x > 0.0) - g_value_set_float (value, priv->distance_x); - else - g_value_set_float (value, gesture_get_default_threshold ()); - break; - - case PROP_THRESHOLD_TRIGGER_DISTANCE_Y: - if (priv->distance_y > 0.0) - g_value_set_float (value, priv->distance_y); - else - g_value_set_float (value, gesture_get_default_threshold ()); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); - break; - } -} - -static void -clutter_gesture_action_finalize (GObject *gobject) -{ - ClutterGestureActionPrivate *priv = - clutter_gesture_action_get_instance_private (CLUTTER_GESTURE_ACTION (gobject)); - - g_array_unref (priv->points); - - G_OBJECT_CLASS (clutter_gesture_action_parent_class)->finalize (gobject); -} - -static void -clutter_gesture_action_class_init (ClutterGestureActionClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); - - gobject_class->finalize = clutter_gesture_action_finalize; - gobject_class->set_property = clutter_gesture_action_set_property; - gobject_class->get_property = clutter_gesture_action_get_property; - - meta_class->set_actor = clutter_gesture_action_set_actor; - meta_class->set_enabled = clutter_gesture_action_set_enabled; - - klass->gesture_begin = default_event_handler; - klass->gesture_progress = default_event_handler; - klass->gesture_prepare = default_event_handler; - - /** - * ClutterGestureAction:n-touch-points: - * - * Number of touch points to trigger a gesture action. - * - * Since: 1.16 - */ - gesture_props[PROP_N_TOUCH_POINTS] = - g_param_spec_int ("n-touch-points", - P_("Number touch points"), - P_("Number of touch points"), - 1, G_MAXINT, 1, - CLUTTER_PARAM_READWRITE); - - /** - * ClutterGestureAction:threshold-trigger-edge: - * - * The trigger edge to be used by the action to either emit the - * #ClutterGestureAction::gesture-begin signal or to emit the - * #ClutterGestureAction::gesture-cancel signal. - * - * Since: 1.18 - */ - gesture_props[PROP_THRESHOLD_TRIGGER_EDGE] = - g_param_spec_enum ("threshold-trigger-edge", - P_("Threshold Trigger Edge"), - P_("The trigger edge used by the action"), - CLUTTER_TYPE_GESTURE_TRIGGER_EDGE, - CLUTTER_GESTURE_TRIGGER_EDGE_NONE, - CLUTTER_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY); - - /** - * ClutterGestureAction:threshold-trigger-distance-x: - * - * The horizontal trigger distance to be used by the action to either - * emit the #ClutterGestureAction::gesture-begin signal or to emit - * the #ClutterGestureAction::gesture-cancel signal. - * - * A negative value will be interpreted as the default drag threshold. - * - * Since: 1.18 - */ - gesture_props[PROP_THRESHOLD_TRIGGER_DISTANCE_X] = - g_param_spec_float ("threshold-trigger-distance-x", - P_("Threshold Trigger Horizontal Distance"), - P_("The horizontal trigger distance used by the action"), - -1.0, G_MAXFLOAT, -1.0, - CLUTTER_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY); - - /** - * ClutterGestureAction:threshold-trigger-distance-y: - * - * The vertical trigger distance to be used by the action to either - * emit the #ClutterGestureAction::gesture-begin signal or to emit - * the #ClutterGestureAction::gesture-cancel signal. - * - * A negative value will be interpreted as the default drag threshold. - * - * Since: 1.18 - */ - gesture_props[PROP_THRESHOLD_TRIGGER_DISTANCE_Y] = - g_param_spec_float ("threshold-trigger-distance-y", - P_("Threshold Trigger Vertical Distance"), - P_("The vertical trigger distance used by the action"), - -1.0, G_MAXFLOAT, -1.0, - CLUTTER_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY); - - g_object_class_install_properties (gobject_class, - PROP_LAST, - gesture_props); - - /** - * ClutterGestureAction::gesture-begin: - * @action: the #ClutterGestureAction that emitted the signal - * @actor: the #ClutterActor attached to the @action - * - * The ::gesture_begin signal is emitted when the #ClutterActor to which - * a #ClutterGestureAction has been applied starts receiving a gesture. - * - * Return value: %TRUE if the gesture should start, and %FALSE if - * the gesture should be ignored. - * - * Since: 1.8 - */ - gesture_signals[GESTURE_BEGIN] = - g_signal_new (I_("gesture-begin"), - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ClutterGestureActionClass, gesture_begin), - _clutter_boolean_continue_accumulator, NULL, - _clutter_marshal_BOOLEAN__OBJECT, - G_TYPE_BOOLEAN, 1, - CLUTTER_TYPE_ACTOR); - - /** - * ClutterGestureAction::gesture-progress: - * @action: the #ClutterGestureAction that emitted the signal - * @actor: the #ClutterActor attached to the @action - * - * The ::gesture-progress signal is emitted for each motion event after - * the #ClutterGestureAction::gesture-begin signal has been emitted. - * - * Return value: %TRUE if the gesture should continue, and %FALSE if - * the gesture should be cancelled. - * - * Since: 1.8 - */ - gesture_signals[GESTURE_PROGRESS] = - g_signal_new (I_("gesture-progress"), - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ClutterGestureActionClass, gesture_progress), - _clutter_boolean_continue_accumulator, NULL, - _clutter_marshal_BOOLEAN__OBJECT, - G_TYPE_BOOLEAN, 1, - CLUTTER_TYPE_ACTOR); - - /** - * ClutterGestureAction::gesture-end: - * @action: the #ClutterGestureAction that emitted the signal - * @actor: the #ClutterActor attached to the @action - * - * The ::gesture-end signal is emitted at the end of the gesture gesture, - * when the pointer's button is released - * - * This signal is emitted if and only if the #ClutterGestureAction::gesture-begin - * signal has been emitted first. - * - * Since: 1.8 - */ - gesture_signals[GESTURE_END] = - g_signal_new (I_("gesture-end"), - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ClutterGestureActionClass, gesture_end), - NULL, NULL, NULL, - G_TYPE_NONE, 1, - CLUTTER_TYPE_ACTOR); - - /** - * ClutterGestureAction::gesture-cancel: - * @action: the #ClutterGestureAction that emitted the signal - * @actor: the #ClutterActor attached to the @action - * - * The ::gesture-cancel signal is emitted when the ongoing gesture gets - * cancelled from the #ClutterGestureAction::gesture-progress signal handler. - * - * This signal is emitted if and only if the #ClutterGestureAction::gesture-begin - * signal has been emitted first. - * - * Since: 1.8 - */ - gesture_signals[GESTURE_CANCEL] = - g_signal_new (I_("gesture-cancel"), - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ClutterGestureActionClass, gesture_cancel), - NULL, NULL, NULL, - G_TYPE_NONE, 1, - CLUTTER_TYPE_ACTOR); -} - -static void -clutter_gesture_action_init (ClutterGestureAction *self) -{ - ClutterGestureActionPrivate *priv = - clutter_gesture_action_get_instance_private (self); - - priv->points = g_array_sized_new (FALSE, TRUE, sizeof (GesturePoint), 3); - g_array_set_clear_func (priv->points, (GDestroyNotify) gesture_point_unset); - - priv->requested_nb_points = 1; - priv->edge = CLUTTER_GESTURE_TRIGGER_EDGE_NONE; -} - -/** - * clutter_gesture_action_new: - * - * Creates a new #ClutterGestureAction instance. - * - * Return value: the newly created #ClutterGestureAction - * - * Since: 1.8 - */ -ClutterAction * -clutter_gesture_action_new (void) -{ - return g_object_new (CLUTTER_TYPE_GESTURE_ACTION, NULL); -} - -/** - * clutter_gesture_action_get_press_coords: - * @action: a #ClutterGestureAction - * @point: the touch point index, with 0 being the first touch - * point received by the action - * @press_x: (out) (allow-none): return location for the press - * event's X coordinate - * @press_y: (out) (allow-none): return location for the press - * event's Y coordinate - * - * Retrieves the coordinates, in stage space, of the press event - * that started the dragging for a specific touch point. - * - * Since: 1.8 - */ -void -clutter_gesture_action_get_press_coords (ClutterGestureAction *action, - guint point, - gfloat *press_x, - gfloat *press_y) -{ - ClutterGestureActionPrivate *priv; - - g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); - - priv = clutter_gesture_action_get_instance_private (action); - - g_return_if_fail (priv->points->len > point); - - if (press_x) - *press_x = g_array_index (priv->points, - GesturePoint, - point).press_x; - - if (press_y) - *press_y = g_array_index (priv->points, - GesturePoint, - point).press_y; -} - -/** - * clutter_gesture_action_get_motion_coords: - * @action: a #ClutterGestureAction - * @point: the touch point index, with 0 being the first touch - * point received by the action - * @motion_x: (out) (allow-none): return location for the latest motion - * event's X coordinate - * @motion_y: (out) (allow-none): return location for the latest motion - * event's Y coordinate - * - * Retrieves the coordinates, in stage space, of the latest motion - * event during the dragging. - * - * Since: 1.8 - */ -void -clutter_gesture_action_get_motion_coords (ClutterGestureAction *action, - guint point, - gfloat *motion_x, - gfloat *motion_y) -{ - ClutterGestureActionPrivate *priv; - - g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); - - priv = clutter_gesture_action_get_instance_private (action); - - g_return_if_fail (priv->points->len > point); - - if (motion_x) - *motion_x = g_array_index (priv->points, - GesturePoint, - point).last_motion_x; - - if (motion_y) - *motion_y = g_array_index (priv->points, - GesturePoint, - point).last_motion_y; -} - -/** - * clutter_gesture_action_get_motion_delta: - * @action: a #ClutterGestureAction - * @point: the touch point index, with 0 being the first touch - * point received by the action - * @delta_x: (out) (allow-none): return location for the X axis - * component of the incremental motion delta - * @delta_y: (out) (allow-none): return location for the Y axis - * component of the incremental motion delta - * - * Retrieves the incremental delta since the last motion event - * during the dragging. - * - * Return value: the distance since last motion event - * - * Since: 1.12 - */ -gfloat -clutter_gesture_action_get_motion_delta (ClutterGestureAction *action, - guint point, - gfloat *delta_x, - gfloat *delta_y) -{ - ClutterGestureActionPrivate *priv; - gfloat d_x, d_y; - - g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), 0); - - priv = clutter_gesture_action_get_instance_private (action); - - g_return_val_if_fail (priv->points->len > point, 0); - - d_x = g_array_index (priv->points, - GesturePoint, - point).last_delta_x; - d_y = g_array_index (priv->points, - GesturePoint, - point).last_delta_y; - - if (delta_x) - *delta_x = d_x; - - if (delta_y) - *delta_y = d_y; - - return sqrt ((d_x * d_x) + (d_y * d_y)); -} - -/** - * clutter_gesture_action_get_release_coords: - * @action: a #ClutterGestureAction - * @point: the touch point index, with 0 being the first touch - * point received by the action - * @release_x: (out) (allow-none): return location for the X coordinate of - * the last release - * @release_y: (out) (allow-none): return location for the Y coordinate of - * the last release - * - * Retrieves the coordinates, in stage space, where the touch point was - * last released. - * - * Since: 1.8 - */ -void -clutter_gesture_action_get_release_coords (ClutterGestureAction *action, - guint point, - gfloat *release_x, - gfloat *release_y) -{ - ClutterGestureActionPrivate *priv; - - g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); - - priv = clutter_gesture_action_get_instance_private (action); - - g_return_if_fail (priv->points->len > point); - - if (release_x) - *release_x = g_array_index (priv->points, - GesturePoint, - point).release_x; - - if (release_y) - *release_y = g_array_index (priv->points, - GesturePoint, - point).release_y; -} - -/** - * clutter_gesture_action_get_velocity: - * @action: a #ClutterGestureAction - * @point: the touch point index, with 0 being the first touch - * point received by the action - * @velocity_x: (out) (allow-none): return location for the latest motion - * event's X velocity - * @velocity_y: (out) (allow-none): return location for the latest motion - * event's Y velocity - * - * Retrieves the velocity, in stage pixels per millisecond, of the - * latest motion event during the dragging. - * - * Since: 1.12 - */ -gfloat -clutter_gesture_action_get_velocity (ClutterGestureAction *action, - guint point, - gfloat *velocity_x, - gfloat *velocity_y) -{ - ClutterGestureActionPrivate *priv; - gfloat d_x, d_y, distance, velocity; - gint64 d_t; - - g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), 0); - - priv = clutter_gesture_action_get_instance_private (action); - - g_return_val_if_fail (priv->points->len > point, 0); - - distance = clutter_gesture_action_get_motion_delta (action, point, - &d_x, &d_y); - - d_t = g_array_index (priv->points, - GesturePoint, - point).last_delta_time; - - if (velocity_x) - *velocity_x = d_t > FLOAT_EPSILON ? d_x / d_t : 0; - - if (velocity_y) - *velocity_y = d_t > FLOAT_EPSILON ? d_y / d_t : 0; - - velocity = d_t > FLOAT_EPSILON ? distance / d_t : 0; - return velocity; -} - -/** - * clutter_gesture_action_get_n_touch_points: - * @action: a #ClutterGestureAction - * - * Retrieves the number of requested points to trigger the gesture. - * - * Return value: the number of points to trigger the gesture. - * - * Since: 1.12 - */ -gint -clutter_gesture_action_get_n_touch_points (ClutterGestureAction *action) -{ - ClutterGestureActionPrivate *priv; - - g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), 0); - - priv = clutter_gesture_action_get_instance_private (action); - - return priv->requested_nb_points; -} - -/** - * clutter_gesture_action_set_n_touch_points: - * @action: a #ClutterGestureAction - * @nb_points: a number of points - * - * Sets the number of points needed to trigger the gesture. - * - * Since: 1.12 - */ -void -clutter_gesture_action_set_n_touch_points (ClutterGestureAction *action, - gint nb_points) -{ - ClutterGestureActionPrivate *priv; - - g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); - g_return_if_fail (nb_points >= 1); - - priv = clutter_gesture_action_get_instance_private (action); - - if (priv->requested_nb_points == nb_points) - return; - - priv->requested_nb_points = nb_points; - - if (priv->in_gesture) - { - if (priv->points->len < priv->requested_nb_points) - cancel_gesture (action); - } - else if (priv->edge == CLUTTER_GESTURE_TRIGGER_EDGE_AFTER) - { - if (priv->points->len >= priv->requested_nb_points) - { - ClutterActor *actor = - clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action)); - gint i; - float threshold_x, threshold_y; - - clutter_gesture_action_get_threshold_trigger_distance (action, &threshold_x, &threshold_y); - - for (i = 0; i < priv->points->len; i++) - { - GesturePoint *point = &g_array_index (priv->points, GesturePoint, i); - - if ((fabsf (point->press_y - point->last_motion_y) >= threshold_y) || - (fabsf (point->press_x - point->last_motion_x) >= threshold_x)) - { - begin_gesture (action, actor); - break; - } - } - } - } - - g_object_notify_by_pspec (G_OBJECT (action), - gesture_props[PROP_N_TOUCH_POINTS]); -} - -/** - * clutter_gesture_action_get_n_current_points: - * @action: a #ClutterGestureAction - * - * Retrieves the number of points currently active. - * - * Return value: the number of points currently active. - * - * Since: 1.12 - */ -guint -clutter_gesture_action_get_n_current_points (ClutterGestureAction *action) -{ - ClutterGestureActionPrivate *priv; - - g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), 0); - - priv = clutter_gesture_action_get_instance_private (action); - - return priv->points->len; -} - -/** - * clutter_gesture_action_get_sequence: - * @action: a #ClutterGestureAction - * @point: index of a point currently active - * - * Retrieves the #ClutterEventSequence of a touch point. - * - * Return value: (transfer none): the #ClutterEventSequence of a touch point. - * - * Since: 1.12 - */ -ClutterEventSequence * -clutter_gesture_action_get_sequence (ClutterGestureAction *action, - guint point) -{ - ClutterGestureActionPrivate *priv; - - g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), NULL); - - priv = clutter_gesture_action_get_instance_private (action); - - g_return_val_if_fail (priv->points->len > point, NULL); - - return g_array_index (priv->points, GesturePoint, point).sequence; -} - -/** - * clutter_gesture_action_get_device: - * @action: a #ClutterGestureAction - * @point: the touch point index, with 0 being the first touch - * point received by the action - * - * Retrieves the #ClutterInputDevice of a touch point. - * - * Return value: (transfer none): the #ClutterInputDevice of a touch point. - * - * Since: 1.12 - */ -ClutterInputDevice * -clutter_gesture_action_get_device (ClutterGestureAction *action, - guint point) -{ - ClutterGestureActionPrivate *priv; - - g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), NULL); - - priv = clutter_gesture_action_get_instance_private (action); - - g_return_val_if_fail (priv->points->len > point, NULL); - - return g_array_index (priv->points, GesturePoint, point).device; -} - -/** - * clutter_gesture_action_get_last_event: - * @action: a #ClutterGestureAction - * @point: index of a point currently active - * - * Retrieves a reference to the last #ClutterEvent for a touch point. Call - * clutter_event_copy() if you need to store the reference somewhere. - * - * Return value: (transfer none): the last #ClutterEvent for a touch point. - * - * Since: 1.14 - */ -const ClutterEvent * -clutter_gesture_action_get_last_event (ClutterGestureAction *action, - guint point) -{ - GesturePoint *gesture_point; - ClutterGestureActionPrivate *priv; - - g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), NULL); - - priv = clutter_gesture_action_get_instance_private (action); - - g_return_val_if_fail (priv->points->len > point, NULL); - - gesture_point = &g_array_index (priv->points, GesturePoint, point); - - return gesture_point->last_event; -} - -/** - * clutter_gesture_action_cancel: - * @action: a #ClutterGestureAction - * - * Cancel a #ClutterGestureAction before it begins - * - * Since: 1.12 - */ -void -clutter_gesture_action_cancel (ClutterGestureAction *action) -{ - g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); - - cancel_gesture (action); -} - -/** - * clutter_gesture_action_set_threshold_trigger_edge: - * @action: a #ClutterGestureAction - * @edge: the %ClutterGestureTriggerEdge - * - * Sets the edge trigger for the gesture drag threshold, if any. - * - * This function should only be called by sub-classes of - * #ClutterGestureAction during their construction phase. - * - * Since: 1.18 - */ -void -clutter_gesture_action_set_threshold_trigger_edge (ClutterGestureAction *action, - ClutterGestureTriggerEdge edge) -{ - ClutterGestureActionPrivate *priv; - - g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); - - priv = clutter_gesture_action_get_instance_private (action); - - if (priv->edge == edge) - return; - - priv->edge = edge; - - g_object_notify_by_pspec (G_OBJECT (action), gesture_props[PROP_THRESHOLD_TRIGGER_EDGE]); -} - -/** - * clutter_gesture_action_get_threshold_trigger_edge: - * @action: a #ClutterGestureAction - * - * Retrieves the edge trigger of the gesture @action, as set using - * clutter_gesture_action_set_threshold_trigger_edge(). - * - * Return value: the edge trigger - * - * Since: 1.20 - */ -ClutterGestureTriggerEdge -clutter_gesture_action_get_threshold_trigger_edge (ClutterGestureAction *action) -{ - ClutterGestureActionPrivate *priv; - - g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), - CLUTTER_GESTURE_TRIGGER_EDGE_NONE); - - priv = clutter_gesture_action_get_instance_private (action); - - return priv->edge; -} - -/** - * clutter_gesture_action_get_threshold_trigger_egde: - * @action: a #ClutterGestureAction - * - * Retrieves the edge trigger of the gesture @action, as set using - * clutter_gesture_action_set_threshold_trigger_edge(). - * - * Return value: the edge trigger - * - * Since: 1.18 - * - * Deprecated: 1.20: Use clutter_gesture_action_get_threshold_trigger_edge() instead. - */ -ClutterGestureTriggerEdge -clutter_gesture_action_get_threshold_trigger_egde (ClutterGestureAction *action) -{ - return clutter_gesture_action_get_threshold_trigger_edge (action); -} - -/** - * clutter_gesture_action_set_threshold_trigger_distance: - * @action: a #ClutterGestureAction - * @x: the distance on the horizontal axis - * @y: the distance on the vertical axis - * - * Sets the threshold trigger distance for the gesture drag threshold, if any. - * - * This function should only be called by sub-classes of - * #ClutterGestureAction during their construction phase. - * - * Since: 1.18 - */ -void -clutter_gesture_action_set_threshold_trigger_distance (ClutterGestureAction *action, - float x, - float y) -{ - ClutterGestureActionPrivate *priv; - - g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); - - priv = clutter_gesture_action_get_instance_private (action); - - if (fabsf (x - priv->distance_x) > FLOAT_EPSILON) - { - priv->distance_x = x; - g_object_notify_by_pspec (G_OBJECT (action), gesture_props[PROP_THRESHOLD_TRIGGER_DISTANCE_X]); - } - - if (fabsf (y - priv->distance_y) > FLOAT_EPSILON) - { - priv->distance_y = y; - g_object_notify_by_pspec (G_OBJECT (action), gesture_props[PROP_THRESHOLD_TRIGGER_DISTANCE_Y]); - } -} - -/** - * clutter_gesture_action_get_threshold_trigger_distance: - * @action: a #ClutterGestureAction - * @x: (out) (allow-none): The return location for the horizontal distance, or %NULL - * @y: (out) (allow-none): The return location for the vertical distance, or %NULL - * - * Retrieves the threshold trigger distance of the gesture @action, - * as set using clutter_gesture_action_set_threshold_trigger_distance(). - * - * Since: 1.18 - */ -void -clutter_gesture_action_get_threshold_trigger_distance (ClutterGestureAction *action, - float *x, - float *y) -{ - ClutterGestureActionPrivate *priv; - - g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action)); - - priv = clutter_gesture_action_get_instance_private (action); - - if (x != NULL) - { - if (priv->distance_x > 0.0) - *x = priv->distance_x; - else - *x = gesture_get_default_threshold (); - } - if (y != NULL) - { - if (priv->distance_y > 0.0) - *y = priv->distance_y; - else - *y = gesture_get_default_threshold (); - } -} |