From 721caece5d518dafd2e91cf4191262c83fe1812e Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Sun, 24 Jun 2012 12:07:40 +0100 Subject: [PATCH] drag-action: Add ::drag-progress signal Overriding the default behaviour of ClutterDragAction::drag-motion is currently a pain; you either need to subclass the ClutterDragAction and override the class closure for the signal, or you need to connect to the signal and call g_signal_stop_emission_by_name() - neither option being particularly nice or clean. The established pattern for these cases would be to have a boolean return value on the ::drag-motion signal, but we cannot do that without breaking ABI. To solve the issue in a backward compatible way, we should introduce a new signal, ::drag-progress, with a boolean return value. If the signal emission chain returns TRUE, the ::drag-motion signal will be emitted, and the default behaviour will be honoured; if the signal emission chain returns FALSE, instead, the ::drag-motion signal will not be emitted. https://bugzilla.gnome.org/show_bug.cgi?id=679451 --- clutter/clutter-drag-action.c | 84 ++++++++++++++++++++++++++++++++--- clutter/clutter-drag-action.h | 33 +++++++------- 2 files changed, 97 insertions(+), 20 deletions(-) diff --git a/clutter/clutter-drag-action.c b/clutter/clutter-drag-action.c index c89fd7959..cdb7952f9 100644 --- a/clutter/clutter-drag-action.c +++ b/clutter/clutter-drag-action.c @@ -132,6 +132,7 @@ static GParamSpec *drag_props[PROP_LAST] = { NULL, }; enum { DRAG_BEGIN, + DRAG_PROGRESS, DRAG_MOTION, DRAG_END, @@ -214,6 +215,7 @@ emit_drag_motion (ClutterDragAction *action, ClutterActor *drag_handle = NULL; gfloat delta_x, delta_y; gfloat motion_x, motion_y; + gboolean can_emit_drag_motion = TRUE; clutter_event_get_coords (event, &priv->last_motion_x, &priv->last_motion_y); priv->last_motion_state = clutter_event_get_state (event); @@ -269,9 +271,17 @@ emit_drag_motion (ClutterDragAction *action, return; } - g_signal_emit (action, drag_signals[DRAG_MOTION], 0, + g_signal_emit (action, drag_signals[DRAG_PROGRESS], 0, actor, - delta_x, delta_y); + delta_x, delta_y, + &can_emit_drag_motion); + + if (can_emit_drag_motion) + { + g_signal_emit (action, drag_signals[DRAG_MOTION], 0, + actor, + delta_x, delta_y); + } } static void @@ -494,6 +504,15 @@ clutter_drag_action_set_actor (ClutterActorMeta *meta, CLUTTER_ACTOR_META_CLASS (clutter_drag_action_parent_class)->set_actor (meta, actor); } +static gboolean +clutter_drag_action_real_drag_progress (ClutterDragAction *action, + ClutterActor *actor, + gfloat delta_x, + gfloat delta_y) +{ + return TRUE; +} + static void clutter_drag_action_real_drag_motion (ClutterDragAction *action, ClutterActor *actor, @@ -621,6 +640,20 @@ clutter_drag_action_dispose (GObject *gobject) G_OBJECT_CLASS (clutter_drag_action_parent_class)->dispose (gobject); } +static gboolean +drag_progress_accum (GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer user_data) +{ + gboolean continue_emission; + + continue_emission = g_value_get_boolean (handler_return); + g_value_set_boolean (return_accu, continue_emission); + + return continue_emission; +} + static void clutter_drag_action_class_init (ClutterDragActionClass *klass) { @@ -631,6 +664,7 @@ clutter_drag_action_class_init (ClutterDragActionClass *klass) meta_class->set_actor = clutter_drag_action_set_actor; + klass->drag_progress = clutter_drag_action_real_drag_progress; klass->drag_motion = clutter_drag_action_real_drag_motion; /** @@ -762,6 +796,46 @@ clutter_drag_action_class_init (ClutterDragActionClass *klass) G_TYPE_FLOAT, CLUTTER_TYPE_MODIFIER_TYPE); + /** + * ClutterDragAction::drag-progress: + * @action: the #ClutterDragAction that emitted the signal + * @actor: the #ClutterActor attached to the action + * @delta_x: the X component of the distance between the press event + * that began the dragging and the current position of the pointer, + * as of the latest motion event + * @delta_y: the Y component of the distance between the press event + * that began the dragging and the current position of the pointer, + * as of the latest motion event + * + * The ::drag-progress signal is emitted for each motion event after + * the #ClutterDragAction::drag-begin signal has been emitted. + * + * The components of the distance between the press event and the + * latest motion event are computed in the actor's coordinate space, + * to take into account eventual transformations. If you want the + * stage coordinates of the latest motion event you can use + * clutter_drag_action_get_motion_coords(). + * + * The default handler will emit #ClutterDragAction::drag-motion, + * if #ClutterDragAction::drag-progress emission returns %TRUE. + * + * Return value: %TRUE if the drag should continue, and %FALSE + * if it should be stopped. + * + * Since: 1.12 + */ + drag_signals[DRAG_PROGRESS] = + g_signal_new (I_("drag-progress"), + CLUTTER_TYPE_DRAG_ACTION, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ClutterDragActionClass, drag_progress), + drag_progress_accum, NULL, + _clutter_marshal_BOOLEAN__OBJECT_FLOAT_FLOAT, + G_TYPE_BOOLEAN, 3, + CLUTTER_TYPE_ACTOR, + G_TYPE_FLOAT, + G_TYPE_FLOAT); + /** * ClutterDragAction::drag-motion: * @action: the #ClutterDragAction that emitted the signal @@ -785,9 +859,9 @@ clutter_drag_action_class_init (ClutterDragActionClass *klass) * The default handler of the signal will call clutter_actor_move_by() * either on @actor or, if set, of #ClutterDragAction:drag-handle using * the @delta_x and @delta_y components of the dragging motion. If you - * want to override the default behaviour, you can connect to this - * signal and call g_signal_stop_emission_by_name() from within your - * callback. + * want to override the default behaviour, you can connect to the + * #ClutterDragAction::drag-progress signal and return %FALSE from the + * handler. * * Since: 1.4 */ diff --git a/clutter/clutter-drag-action.h b/clutter/clutter-drag-action.h index 4cec1211f..5ef5fac17 100644 --- a/clutter/clutter-drag-action.h +++ b/clutter/clutter-drag-action.h @@ -78,27 +78,30 @@ struct _ClutterDragActionClass ClutterActionClass parent_class; /*< public >*/ - void (* drag_begin) (ClutterDragAction *action, - ClutterActor *actor, - gfloat event_x, - gfloat event_y, - ClutterModifierType modifiers); - void (* drag_motion) (ClutterDragAction *action, - ClutterActor *actor, - gfloat delta_x, - gfloat delta_y); - void (* drag_end) (ClutterDragAction *action, - ClutterActor *actor, - gfloat event_x, - gfloat event_y, - ClutterModifierType modifiers); + void (* drag_begin) (ClutterDragAction *action, + ClutterActor *actor, + gfloat event_x, + gfloat event_y, + ClutterModifierType modifiers); + void (* drag_motion) (ClutterDragAction *action, + ClutterActor *actor, + gfloat delta_x, + gfloat delta_y); + void (* drag_end) (ClutterDragAction *action, + ClutterActor *actor, + gfloat event_x, + gfloat event_y, + ClutterModifierType modifiers); + gboolean (* drag_progress) (ClutterDragAction *action, + ClutterActor *actor, + gfloat delta_x, + gfloat delta_y); /*< private >*/ void (* _clutter_drag_action1) (void); void (* _clutter_drag_action2) (void); void (* _clutter_drag_action3) (void); void (* _clutter_drag_action4) (void); - void (* _clutter_drag_action5) (void); }; GType clutter_drag_action_get_type (void) G_GNUC_CONST;