From abcf1d589f29ba7914d5648bb9814ad26c13cd83 Mon Sep 17 00:00:00 2001 From: Emanuele Aina Date: Mon, 15 Oct 2012 23:37:38 +0200 Subject: [PATCH] gesture-action: Let subclasses override the GestureTriggerEdge handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let gesture subclasses override how the drag threshold should be handled: • CLUTTER_GESTURE_TRIGGER_NONE tells GestureAction that the gesture must begin immediately and there's no drag limit that will cause its cancellation; • CLUTTER_GESTURE_TRIGGER_AFTER is the default GestureAction behaviour, where it needs to wait until the drag threshold has been exceeded before considering the gesture valid; • CLUTTER_GESTURE_TRIGGER_BEFORE will make GestureAction cancel the gesture once the drag exceed the configured threshold. For example, ZoomAction and RotateAction could set CLUTTER_GESTURE_TRIGGER_NONE since the use of two fingers makes the begin of the action more self-evident, while an hypothetical Tap gesture may use CLUTTER_GESTURE_TRIGGER_BEFORE to cancel the tap if the pointer moves too much. https://bugzilla.gnome.org/show_bug.cgi?id=685028 --- clutter/Makefile.am | 1 + clutter/clutter-gesture-action-private.h | 59 ++++++++++ clutter/clutter-gesture-action.c | 141 +++++++++++++++-------- 3 files changed, 153 insertions(+), 48 deletions(-) create mode 100644 clutter/clutter-gesture-action-private.h diff --git a/clutter/Makefile.am b/clutter/Makefile.am index 100c1f551..70a4792c4 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -226,6 +226,7 @@ source_h_priv = \ $(srcdir)/clutter-event-translator.h \ $(srcdir)/clutter-event-private.h \ $(srcdir)/clutter-flatten-effect.h \ + $(srcdir)/clutter-gesture-action-private.h \ $(srcdir)/clutter-id-pool.h \ $(srcdir)/clutter-master-clock.h \ $(srcdir)/clutter-model-private.h \ diff --git a/clutter/clutter-gesture-action-private.h b/clutter/clutter-gesture-action-private.h new file mode 100644 index 000000000..d3eb8659a --- /dev/null +++ b/clutter/clutter-gesture-action-private.h @@ -0,0 +1,59 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2012 Collabora Ltd.. + * + * 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 . + */ + +#ifndef __CLUTTER_GESTURE_ACTION_PRIVATE_H__ +#define __CLUTTER_GESTURE_ACTION_PRIVATE_H__ + +#include + +G_BEGIN_DECLS + +/*< private > + * ClutterGestureTriggerEdge: + * @CLUTTER_GESTURE_TRIGGER_NONE: Tell #ClutterGestureAction that + * the gesture must begin immediately and there's no drag limit that + * will cause its cancellation; + * @CLUTTER_GESTURE_TRIGGER_AFTER: Tell #ClutterGestureAction that + * it needs to wait until the drag threshold has been exceeded before + * considering that the gesture has begun; + * @CLUTTER_GESTURE_TRIGGER_BEFORE: Tell #ClutterGestureAction that + * the gesture must begin immegiately and that it must be cancelled + * once the drag exceed the configured threshold. + * + * Enum passed to the _clutter_gesture_action_set_threshold_trigger_edge() + * function. + * + * Since: 1.14 + */ +typedef enum +{ + CLUTTER_GESTURE_TRIGGER_EDGE_NONE = 0, + CLUTTER_GESTURE_TRIGGER_EDGE_AFTER, + CLUTTER_GESTURE_TRIGGER_EDGE_BEFORE +} ClutterGestureTriggerEdge; + + +void _clutter_gesture_action_set_threshold_trigger_edge (ClutterGestureAction *action, + ClutterGestureTriggerEdge edge); + +G_END_DECLS + +#endif /* __CLUTTER_GESTURE_ACTION_PRIVATE_H__ */ diff --git a/clutter/clutter-gesture-action.c b/clutter/clutter-gesture-action.c index 4c9460b23..310bf9a73 100644 --- a/clutter/clutter-gesture-action.c +++ b/clutter/clutter-gesture-action.c @@ -87,7 +87,7 @@ #include "config.h" #endif -#include "clutter-gesture-action.h" +#include "clutter-gesture-action-private.h" #include "clutter-debug.h" #include "clutter-enum-types.h" @@ -122,6 +122,8 @@ struct _ClutterGestureActionPrivate guint actor_capture_id; gulong stage_capture_id; + ClutterGestureTriggerEdge edge; + guint in_gesture : 1; }; @@ -209,6 +211,15 @@ gesture_unregister_point (ClutterGestureAction *action, gint position) g_array_remove_index (priv->points, position); } +static gint +gesture_get_threshold (ClutterGestureAction *action) +{ + gint threshold; + ClutterSettings *settings = clutter_settings_get_default (); + g_object_get (settings, "dnd-drag-threshold", &threshold, NULL); + return threshold; +} + static void cancel_gesture (ClutterGestureAction *action) { @@ -227,6 +238,38 @@ cancel_gesture (ClutterGestureAction *action) g_signal_emit (action, gesture_signals[GESTURE_CANCEL], 0, actor); } +static gboolean +begin_gesture (ClutterGestureAction *action, + ClutterActor *actor) +{ + ClutterGestureActionPrivate *priv = action->priv; + 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, @@ -234,7 +277,7 @@ stage_captured_event_cb (ClutterActor *stage, { ClutterGestureActionPrivate *priv = action->priv; ClutterActor *actor; - gint position; + gint position, drag_threshold; gboolean return_value; GesturePoint *point; gfloat motion_x, motion_y; @@ -272,40 +315,18 @@ stage_captured_event_cb (ClutterActor *stage, if (priv->points->len < priv->requested_nb_points) return CLUTTER_EVENT_PROPAGATE; + drag_threshold = gesture_get_threshold (action); + if (!priv->in_gesture) { - gint drag_threshold; - ClutterSettings *settings = clutter_settings_get_default (); + /* Wait until the drag threshold has been exceeded + * before starting _TRIGGER_EDGE_AFTER gestures. */ + if (priv->edge == CLUTTER_GESTURE_TRIGGER_EDGE_AFTER && + (fabsf (point->press_y - motion_y) < drag_threshold) && + (fabsf (point->press_x - motion_x) < drag_threshold)) + return CLUTTER_EVENT_PROPAGATE; - g_object_get (settings, - "dnd-drag-threshold", &drag_threshold, - NULL); - - if ((ABS (point->press_y - motion_y) >= drag_threshold) || - (ABS (point->press_x - motion_x) >= drag_threshold)) - { - priv->in_gesture = TRUE; - - if (!CLUTTER_GESTURE_ACTION_GET_CLASS (action)->gesture_prepare (action, actor)) - { - cancel_gesture (action); - return CLUTTER_EVENT_PROPAGATE; - } - - /* clutter_gesture_action_cancel() may have been called during - * gesture_prepare(), check that the gesture is still active. */ - if (!priv->in_gesture) - return CLUTTER_EVENT_PROPAGATE; - - g_signal_emit (action, gesture_signals[GESTURE_BEGIN], 0, actor, - &return_value); - if (!return_value) - { - cancel_gesture (action); - return CLUTTER_EVENT_PROPAGATE; - } - } - else + if (!begin_gesture(action, actor)) return CLUTTER_EVENT_PROPAGATE; } @@ -325,6 +346,16 @@ stage_captured_event_cb (ClutterActor *stage, 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. */ + if (priv->edge == CLUTTER_GESTURE_TRIGGER_EDGE_BEFORE && + ((fabsf (point->press_y - motion_y) > drag_threshold) || + (fabsf (point->press_x - motion_x) > drag_threshold))) + { + cancel_gesture (action); + return CLUTTER_EVENT_PROPAGATE; + } break; case CLUTTER_BUTTON_RELEASE: @@ -400,6 +431,11 @@ actor_captured_event_cb (ClutterActor *actor, G_CALLBACK (stage_captured_event_cb), action); + /* Start the gesture immediately if the gesture has no + * _TRIGGER_EDGE_AFTER drag threshold. */ + if (priv->edge != CLUTTER_GESTURE_TRIGGER_EDGE_AFTER) + begin_gesture (action, actor); + return CLUTTER_EVENT_PROPAGATE; } @@ -448,6 +484,26 @@ default_event_handler (ClutterGestureAction *action, return TRUE; } + +/*< private > + * _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 can be called by #ClutterGestureAction subclasses that needs + * to change the %CLUTTER_GESTURE_TRIGGER_EDGE_AFTER default. + * + * Since: 1.14 + */ +void +_clutter_gesture_action_set_threshold_trigger_edge (ClutterGestureAction *action, + ClutterGestureTriggerEdge edge) +{ + action->priv->edge = edge; +} + static void clutter_gesture_action_class_init (ClutterGestureActionClass *klass) { @@ -562,6 +618,7 @@ clutter_gesture_action_init (ClutterGestureAction *self) self->priv->points = g_array_sized_new (FALSE, TRUE, sizeof (GesturePoint), 3); self->priv->requested_nb_points = 1; + self->priv->edge = CLUTTER_GESTURE_TRIGGER_EDGE_AFTER; } /** @@ -812,18 +869,15 @@ clutter_gesture_action_set_n_touch_points (ClutterGestureAction *action, if (priv->points->len < priv->requested_nb_points) cancel_gesture (action); } - else + 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)); - ClutterSettings *settings = clutter_settings_get_default (); gint i, drag_threshold; - g_object_get (settings, - "dnd-drag-threshold", &drag_threshold, - NULL); + drag_threshold = gesture_get_threshold (action); for (i = 0; i < priv->points->len; i++) { @@ -832,16 +886,7 @@ clutter_gesture_action_set_n_touch_points (ClutterGestureAction *action, if ((ABS (point->press_y - point->last_motion_y) >= drag_threshold) || (ABS (point->press_x - point->last_motion_x) >= drag_threshold)) { - gboolean return_value; - - priv->in_gesture = TRUE; - - g_signal_emit (action, gesture_signals[GESTURE_BEGIN], 0, actor, - &return_value); - - if (!return_value) - cancel_gesture (action); - + begin_gesture (action, actor); break; } }