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
This commit is contained in:
Emmanuele Bassi 2012-06-24 12:07:40 +01:00
parent 0e4c6d0a87
commit 721caece5d
2 changed files with 97 additions and 20 deletions

View File

@ -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
*/

View File

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