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;
}
}