4 * An OpenGL based 'interactive canvas' library.
6 * Copyright (C) 2010 Intel Corporation.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
22 * Emmanuele Bassi <ebassi@linux.intel.com>
26 * SECTION:clutter-drag-action
27 * @Title: ClutterDragAction
28 * @Short_Description: Action enabling dragging on actors
30 * #ClutterDragAction is a sub-class of #ClutterAction that implements
31 * all the necessary logic for dragging actors.
33 * The simplest usage of #ClutterDragAction consists in adding it to
34 * a #ClutterActor and setting it as reactive; for instance, the following
38 * clutter_actor_add_action (actor, clutter_drag_action_new ());
39 * clutter_actor_set_reactive (actor, TRUE);
42 * will automatically result in the actor moving to follow the pointer
43 * whenever the pointer's button is pressed over the actor and moved
46 * The #ClutterDragAction will signal the begin and the end of a dragging
47 * through the #ClutterDragAction::drag-begin and #ClutterDragAction::drag-end
48 * signals, respectively. Each pointer motion during a drag will also result
49 * in the #ClutterDragAction::drag-motion signal to be emitted.
51 * It is also possible to set another #ClutterActor as the dragged actor
52 * by calling clutter_drag_action_set_drag_handle() from within a handle
53 * of the #ClutterDragAction::drag-begin signal. The drag handle must be
54 * parented and exist between the emission of #ClutterDragAction::drag-begin
55 * and #ClutterDragAction::drag-end.
57 * <example id="drag-action-example">
58 * <title>A simple draggable actor</title>
60 * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-drag.c">
61 * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
64 * <para>The example program above allows dragging the rectangle around
65 * the stage using a #ClutterDragAction. When pressing the
66 * <keycap>Shift</keycap> key the actor that is going to be dragged is a
67 * separate rectangle, and when the drag ends, the original rectangle will
68 * be animated to the final coordinates.</para>
71 * #ClutterDragAction is available since Clutter 1.4
78 #include "clutter-drag-action.h"
80 #include "clutter-debug.h"
81 #include "clutter-enum-types.h"
82 #include "clutter-marshal.h"
83 #include "clutter-private.h"
84 #include "clutter-stage-private.h"
86 struct _ClutterDragActionPrivate
90 gint x_drag_threshold;
91 gint y_drag_threshold;
92 ClutterActor *drag_handle;
93 ClutterDragAxis drag_axis;
95 ClutterInputDevice *device;
96 gulong button_press_id;
101 ClutterModifierType press_state;
103 gfloat last_motion_x;
104 gfloat last_motion_y;
105 ClutterModifierType last_motion_state;
106 ClutterInputDevice *last_motion_device;
108 gfloat transformed_press_x;
109 gfloat transformed_press_y;
111 guint emit_delayed_press : 1;
113 guint motion_events_enabled : 1;
120 PROP_X_DRAG_THRESHOLD,
121 PROP_Y_DRAG_THRESHOLD,
128 static GParamSpec *drag_props[PROP_LAST] = { NULL, };
139 static guint drag_signals[LAST_SIGNAL] = { 0, };
141 /* forward declaration */
142 static gboolean on_captured_event (ClutterActor *stage,
144 ClutterDragAction *action);
146 G_DEFINE_TYPE (ClutterDragAction, clutter_drag_action, CLUTTER_TYPE_ACTION);
149 get_drag_threshold (ClutterDragAction *action,
153 ClutterDragActionPrivate *priv = action->priv;
154 ClutterSettings *settings = clutter_settings_get_default ();
155 gint x_res, y_res, default_threshold;
157 g_object_get (settings, "dnd-drag-threshold", &default_threshold, NULL);
159 if (priv->x_drag_threshold < 0)
160 x_res = default_threshold;
162 x_res = priv->x_drag_threshold;
164 if (priv->y_drag_threshold < 0)
165 y_res = default_threshold;
167 y_res = priv->y_drag_threshold;
169 if (x_threshold != NULL)
170 *x_threshold = x_res;
172 if (y_threshold != NULL)
173 *y_threshold = y_res;
177 emit_drag_begin (ClutterDragAction *action,
181 ClutterDragActionPrivate *priv = action->priv;
183 if (priv->stage != NULL)
185 clutter_stage_set_motion_events_enabled (priv->stage, FALSE);
186 _clutter_stage_add_drag_actor (priv->stage,
187 clutter_event_get_device (event),
188 priv->drag_handle != NULL
193 g_signal_emit (action, drag_signals[DRAG_BEGIN], 0,
195 priv->press_x, priv->press_y,
200 emit_drag_motion (ClutterDragAction *action,
204 ClutterDragActionPrivate *priv = action->priv;
205 ClutterActor *drag_handle = NULL;
206 gfloat delta_x, delta_y;
207 gfloat motion_x, motion_y;
209 clutter_event_get_coords (event, &priv->last_motion_x, &priv->last_motion_y);
210 priv->last_motion_state = clutter_event_get_state (event);
211 priv->last_motion_device = clutter_event_get_device (event);
213 if (priv->drag_handle != NULL && !priv->emit_delayed_press)
214 drag_handle = priv->drag_handle;
218 motion_x = motion_y = 0.0f;
219 clutter_actor_transform_stage_point (drag_handle,
222 &motion_x, &motion_y);
224 delta_x = delta_y = 0.0f;
226 switch (priv->drag_axis)
228 case CLUTTER_DRAG_AXIS_NONE:
229 delta_x = motion_x - priv->transformed_press_x;
230 delta_y = motion_y - priv->transformed_press_y;
233 case CLUTTER_DRAG_X_AXIS:
234 delta_x = motion_x - priv->transformed_press_x;
237 case CLUTTER_DRAG_Y_AXIS:
238 delta_y = motion_y - priv->transformed_press_y;
242 g_assert_not_reached ();
246 if (priv->emit_delayed_press)
248 gint x_drag_threshold, y_drag_threshold;
250 get_drag_threshold (action, &x_drag_threshold, &y_drag_threshold);
252 if (ABS (delta_x) >= x_drag_threshold ||
253 ABS (delta_y) >= y_drag_threshold)
255 priv->emit_delayed_press = FALSE;
257 emit_drag_begin (action, actor, event);
263 g_signal_emit (action, drag_signals[DRAG_MOTION], 0,
269 emit_drag_end (ClutterDragAction *action,
273 ClutterDragActionPrivate *priv = action->priv;
275 /* if we have an event, update our own state, otherwise we'll
276 * just use the currently stored state when emitting the ::drag-end
281 clutter_event_get_coords (event, &priv->last_motion_x, &priv->last_motion_y);
282 priv->last_motion_state = clutter_event_get_state (event);
283 priv->last_motion_device = clutter_event_get_device (event);
286 /* we might not have emitted ::drag-begin yet */
287 if (!priv->emit_delayed_press)
288 g_signal_emit (action, drag_signals[DRAG_END], 0,
290 priv->last_motion_x, priv->last_motion_y,
291 priv->last_motion_state);
293 /* disconnect the capture */
294 if (priv->capture_id != 0)
296 g_signal_handler_disconnect (priv->stage, priv->capture_id);
297 priv->capture_id = 0;
300 clutter_stage_set_motion_events_enabled (priv->stage,
301 priv->motion_events_enabled);
303 if (priv->last_motion_device != NULL)
304 _clutter_stage_remove_drag_actor (priv->stage, priv->last_motion_device);
306 priv->in_drag = FALSE;
310 on_captured_event (ClutterActor *stage,
312 ClutterDragAction *action)
314 ClutterDragActionPrivate *priv = action->priv;
317 actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action));
320 return CLUTTER_EVENT_PROPAGATE;
322 if (clutter_event_get_device (event) != priv->device)
323 return CLUTTER_EVENT_PROPAGATE;
325 switch (clutter_event_type (event))
329 ClutterModifierType mods = clutter_event_get_state (event);
331 /* we might miss a button-release event in case of grabs,
332 * so we need to check whether the button is still down
333 * during a motion event
335 if (mods & CLUTTER_BUTTON1_MASK)
336 emit_drag_motion (action, actor, event);
338 emit_drag_end (action, actor, event);
342 case CLUTTER_BUTTON_RELEASE:
344 emit_drag_end (action, actor, event);
350 return CLUTTER_EVENT_STOP;
357 return CLUTTER_EVENT_PROPAGATE;
361 on_button_press (ClutterActor *actor,
363 ClutterDragAction *action)
365 ClutterDragActionPrivate *priv = action->priv;
367 if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (action)))
368 return CLUTTER_EVENT_PROPAGATE;
370 /* dragging is only performed using the primary button */
371 if (clutter_event_get_button (event) != CLUTTER_BUTTON_PRIMARY)
372 return CLUTTER_EVENT_PROPAGATE;
374 if (priv->stage == NULL)
375 priv->stage = CLUTTER_STAGE (clutter_actor_get_stage (actor));
377 clutter_event_get_coords (event, &priv->press_x, &priv->press_y);
378 priv->press_state = clutter_event_get_state (event);
380 priv->device = clutter_event_get_device (event);
382 priv->last_motion_x = priv->press_x;
383 priv->last_motion_y = priv->press_y;
385 priv->transformed_press_x = priv->press_x;
386 priv->transformed_press_y = priv->press_y;
387 clutter_actor_transform_stage_point (actor, priv->press_x, priv->press_y,
388 &priv->transformed_press_x,
389 &priv->transformed_press_y);
391 priv->motion_events_enabled =
392 clutter_stage_get_motion_events_enabled (priv->stage);
394 if (priv->x_drag_threshold == 0 || priv->y_drag_threshold == 0)
395 emit_drag_begin (action, actor, event);
397 priv->emit_delayed_press = TRUE;
399 priv->in_drag = TRUE;
400 priv->capture_id = g_signal_connect_after (priv->stage, "captured-event",
401 G_CALLBACK (on_captured_event),
404 return CLUTTER_EVENT_PROPAGATE;
408 clutter_drag_action_set_actor (ClutterActorMeta *meta,
411 ClutterDragActionPrivate *priv = CLUTTER_DRAG_ACTION (meta)->priv;
413 if (priv->button_press_id != 0)
415 ClutterActor *old_actor;
417 old_actor = clutter_actor_meta_get_actor (meta);
418 if (old_actor != NULL)
419 g_signal_handler_disconnect (old_actor, priv->button_press_id);
421 priv->button_press_id = 0;
424 if (priv->capture_id != 0)
426 if (priv->stage != NULL)
427 g_signal_handler_disconnect (priv->stage, priv->capture_id);
429 priv->capture_id = 0;
433 clutter_drag_action_set_drag_handle (CLUTTER_DRAG_ACTION (meta), NULL);
435 priv->in_drag = FALSE;
438 priv->button_press_id = g_signal_connect (actor, "button-press-event",
439 G_CALLBACK (on_button_press),
442 CLUTTER_ACTOR_META_CLASS (clutter_drag_action_parent_class)->set_actor (meta, actor);
446 clutter_drag_action_real_drag_motion (ClutterDragAction *action,
451 ClutterActor *drag_handle;
453 if (action->priv->drag_handle != NULL)
454 drag_handle = action->priv->drag_handle;
458 clutter_actor_move_by (drag_handle, delta_x, delta_y);
462 clutter_drag_action_set_property (GObject *gobject,
467 ClutterDragAction *action = CLUTTER_DRAG_ACTION (gobject);
468 ClutterDragActionPrivate *priv = action->priv;
472 case PROP_X_DRAG_THRESHOLD:
473 clutter_drag_action_set_drag_threshold (action,
474 g_value_get_int (value),
475 priv->y_drag_threshold);
478 case PROP_Y_DRAG_THRESHOLD:
479 clutter_drag_action_set_drag_threshold (action,
480 priv->x_drag_threshold,
481 g_value_get_int (value));
484 case PROP_DRAG_HANDLE:
485 clutter_drag_action_set_drag_handle (action, g_value_get_object (value));
489 clutter_drag_action_set_drag_axis (action, g_value_get_enum (value));
493 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
498 clutter_drag_action_get_property (GObject *gobject,
503 ClutterDragActionPrivate *priv = CLUTTER_DRAG_ACTION (gobject)->priv;
507 case PROP_X_DRAG_THRESHOLD:
511 get_drag_threshold (CLUTTER_DRAG_ACTION (gobject), &threshold, NULL);
512 g_value_set_int (value, threshold);
516 case PROP_Y_DRAG_THRESHOLD:
520 get_drag_threshold (CLUTTER_DRAG_ACTION (gobject), NULL, &threshold);
521 g_value_set_int (value, threshold);
525 case PROP_DRAG_HANDLE:
526 g_value_set_object (value, priv->drag_handle);
530 g_value_set_enum (value, priv->drag_axis);
534 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
539 clutter_drag_action_dispose (GObject *gobject)
541 ClutterDragActionPrivate *priv = CLUTTER_DRAG_ACTION (gobject)->priv;
543 if (priv->capture_id != 0)
545 if (priv->stage != NULL)
546 g_signal_handler_disconnect (priv->stage, priv->capture_id);
548 priv->capture_id = 0;
552 if (priv->button_press_id != 0)
556 actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (gobject));
558 g_signal_handler_disconnect (actor, priv->button_press_id);
560 priv->button_press_id = 0;
563 clutter_drag_action_set_drag_handle (CLUTTER_DRAG_ACTION (gobject), NULL);
565 G_OBJECT_CLASS (clutter_drag_action_parent_class)->dispose (gobject);
569 clutter_drag_action_class_init (ClutterDragActionClass *klass)
571 ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
572 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
574 g_type_class_add_private (klass, sizeof (ClutterDragActionPrivate));
576 meta_class->set_actor = clutter_drag_action_set_actor;
578 klass->drag_motion = clutter_drag_action_real_drag_motion;
581 * ClutterDragAction:x-drag-threshold:
583 * The horizontal threshold, in pixels, that the cursor must travel
584 * in order to begin a drag action.
586 * When set to a positive value, #ClutterDragAction will only emit
587 * #ClutterDragAction::drag-begin if the pointer has moved
588 * horizontally at least of the given amount of pixels since
589 * the button press event.
591 * When set to -1, #ClutterDragAction will use the default threshold
592 * stored in the #ClutterSettings:dnd-drag-threshold property of
595 * When read, this property will always return a valid drag
596 * threshold, either as set or the default one.
600 drag_props[PROP_X_DRAG_THRESHOLD] =
601 g_param_spec_int ("x-drag-threshold",
602 P_("Horizontal Drag Threshold"),
603 P_("The horizontal amount of pixels required to start dragging"),
606 CLUTTER_PARAM_READWRITE);
609 * ClutterDragAction:y-drag-threshold:
611 * The vertical threshold, in pixels, that the cursor must travel
612 * in order to begin a drag action.
614 * When set to a positive value, #ClutterDragAction will only emit
615 * #ClutterDragAction::drag-begin if the pointer has moved
616 * vertically at least of the given amount of pixels since
617 * the button press event.
619 * When set to -1, #ClutterDragAction will use the value stored
620 * in the #ClutterSettings:dnd-drag-threshold property of
623 * When read, this property will always return a valid drag
624 * threshold, either as set or the default one.
628 drag_props[PROP_Y_DRAG_THRESHOLD] =
629 g_param_spec_int ("y-drag-threshold",
630 P_("Vertical Drag Threshold"),
631 P_("The vertical amount of pixels required to start dragging"),
634 CLUTTER_PARAM_READWRITE);
637 * ClutterDragAction:drag-handle:
639 * The #ClutterActor that is effectively being dragged
641 * A #ClutterDragAction will, be default, use the #ClutterActor that
642 * has been attached to the action; it is possible to create a
643 * separate #ClutterActor and use it instead.
645 * Setting this property has no effect on the #ClutterActor argument
646 * passed to the #ClutterDragAction signals
650 drag_props[PROP_DRAG_HANDLE] =
651 g_param_spec_object ("drag-handle",
653 P_("The actor that is being dragged"),
655 CLUTTER_PARAM_READWRITE);
658 * ClutterDragAction:drag-axis:
660 * Constraints the dragging action to the specified axis
664 drag_props[PROP_DRAG_AXIS] =
665 g_param_spec_enum ("drag-axis",
667 P_("Constraints the dragging to an axis"),
668 CLUTTER_TYPE_DRAG_AXIS,
669 CLUTTER_DRAG_AXIS_NONE,
670 CLUTTER_PARAM_READWRITE);
672 gobject_class->set_property = clutter_drag_action_set_property;
673 gobject_class->get_property = clutter_drag_action_get_property;
674 gobject_class->dispose = clutter_drag_action_dispose;
675 g_object_class_install_properties (gobject_class,
680 * ClutterDragAction::drag-begin:
681 * @action: the #ClutterDragAction that emitted the signal
682 * @actor: the #ClutterActor attached to the action
683 * @event_x: the X coordinate (in stage space) of the press event
684 * @event_y: the Y coordinate (in stage space) of the press event
685 * @modifiers: the modifiers of the press event
687 * The ::drag-begin signal is emitted when the #ClutterDragAction
688 * starts the dragging
690 * The emission of this signal can be delayed by using the
691 * #ClutterDragAction:x-drag-threshold and
692 * #ClutterDragAction:y-drag-threshold properties
696 drag_signals[DRAG_BEGIN] =
697 g_signal_new (I_("drag-begin"),
698 CLUTTER_TYPE_DRAG_ACTION,
700 G_STRUCT_OFFSET (ClutterDragActionClass, drag_begin),
702 _clutter_marshal_VOID__OBJECT_FLOAT_FLOAT_FLAGS,
707 CLUTTER_TYPE_MODIFIER_TYPE);
710 * ClutterDragAction::drag-motion
711 * @action: the #ClutterDragAction that emitted the signal
712 * @actor: the #ClutterActor attached to the action
713 * @delta_x: the X component of the distance between the press event
714 * that began the dragging and the current position of the pointer,
715 * as of the latest motion event
716 * @delta_y: the Y component of the distance between the press event
717 * that began the dragging and the current position of the pointer,
718 * as of the latest motion event
720 * The ::drag-motion signal is emitted for each motion event after
721 * the #ClutterDragAction::drag-begin signal has been emitted.
723 * The components of the distance between the press event and the
724 * latest motion event are computed in the actor's coordinate space,
725 * to take into account eventual transformations. If you want the
726 * stage coordinates of the latest motion event you can use
727 * clutter_drag_action_get_motion_coords().
729 * The default handler of the signal will call clutter_actor_move_by()
730 * either on @actor or, if set, of #ClutterDragAction:drag-handle using
731 * the @delta_x and @delta_y components of the dragging motion. If you
732 * want to override the default behaviour, you can connect to this
733 * signal and call g_signal_stop_emission_by_name() from within your
738 drag_signals[DRAG_MOTION] =
739 g_signal_new (I_("drag-motion"),
740 CLUTTER_TYPE_DRAG_ACTION,
742 G_STRUCT_OFFSET (ClutterDragActionClass, drag_motion),
744 _clutter_marshal_VOID__OBJECT_FLOAT_FLOAT,
751 * ClutterDragAction::drag-end:
752 * @action: the #ClutterDragAction that emitted the signal
753 * @actor: the #ClutterActor attached to the action
754 * @event_x: the X coordinate (in stage space) of the release event
755 * @event_y: the Y coordinate (in stage space) of the release event
756 * @modifiers: the modifiers of the release event
758 * The ::drag-end signal is emitted at the end of the dragging,
759 * when the pointer button's is released
761 * This signal is emitted if and only if the #ClutterDragAction::drag-begin
762 * signal has been emitted first
766 drag_signals[DRAG_END] =
767 g_signal_new (I_("drag-end"),
768 CLUTTER_TYPE_DRAG_ACTION,
770 G_STRUCT_OFFSET (ClutterDragActionClass, drag_end),
772 _clutter_marshal_VOID__OBJECT_FLOAT_FLOAT_FLAGS,
777 CLUTTER_TYPE_MODIFIER_TYPE);
781 clutter_drag_action_init (ClutterDragAction *self)
783 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_DRAG_ACTION,
784 ClutterDragActionPrivate);
788 * clutter_drag_action_new:
790 * Creates a new #ClutterDragAction instance
792 * Return value: the newly created #ClutterDragAction
797 clutter_drag_action_new (void)
799 return g_object_new (CLUTTER_TYPE_DRAG_ACTION, NULL);
803 * clutter_drag_action_set_drag_threshold:
804 * @action: a #ClutterDragAction
805 * @x_threshold: a distance on the horizontal axis, in pixels, or
806 * -1 to use the default drag threshold from #ClutterSettings
807 * @y_threshold: a distance on the vertical axis, in pixels, or
808 * -1 to use the default drag threshold from #ClutterSettings
810 * Sets the horizontal and vertical drag thresholds that must be
811 * cleared by the pointer before @action can begin the dragging.
813 * If @x_threshold or @y_threshold are set to -1 then the default
814 * drag threshold stored in the #ClutterSettings:dnd-drag-threshold
815 * property of #ClutterSettings will be used.
820 clutter_drag_action_set_drag_threshold (ClutterDragAction *action,
824 ClutterDragActionPrivate *priv;
827 g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action));
829 self = G_OBJECT (action);
832 g_object_freeze_notify (self);
834 if (priv->x_drag_threshold != x_threshold)
836 priv->x_drag_threshold = x_threshold;
838 g_object_notify_by_pspec (self, drag_props[PROP_X_DRAG_THRESHOLD]);
841 if (priv->y_drag_threshold != y_threshold)
843 priv->y_drag_threshold = y_threshold;
845 g_object_notify_by_pspec (self, drag_props[PROP_Y_DRAG_THRESHOLD]);
848 g_object_thaw_notify (self);
852 * clutter_drag_action_get_drag_threshold:
853 * @action: a #ClutterDragAction
854 * @x_threshold: (out): return location for the horizontal drag
855 * threshold value, in pixels
856 * @y_threshold: (out): return location for the vertical drag
857 * threshold value, in pixels
859 * Retrieves the values set by clutter_drag_action_set_drag_threshold().
861 * If the #ClutterDragAction:x-drag-threshold property or the
862 * #ClutterDragAction:y-drag-threshold property have been set to -1 then
863 * this function will return the default drag threshold value as stored
864 * by the #ClutterSettings:dnd-drag-threshold property of #ClutterSettings.
869 clutter_drag_action_get_drag_threshold (ClutterDragAction *action,
875 g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action));
877 get_drag_threshold (action, &x_res, &y_res);
879 if (x_threshold != NULL)
880 *x_threshold = x_res;
882 if (y_threshold != NULL)
883 *y_threshold = y_res;
887 on_drag_handle_destroy (ClutterActor *actor,
888 ClutterDragAction *action)
890 ClutterDragActionPrivate *priv = action->priv;
892 /* make sure we reset the state */
894 emit_drag_end (action, actor, NULL);
896 priv->drag_handle = NULL;
900 * clutter_drag_action_set_drag_handle:
901 * @action: a #ClutterDragAction
902 * @handle: (allow-none): a #ClutterActor, or %NULL to unset
904 * Sets the actor to be used as the drag handle.
909 clutter_drag_action_set_drag_handle (ClutterDragAction *action,
910 ClutterActor *handle)
912 ClutterDragActionPrivate *priv;
914 g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action));
915 g_return_if_fail (handle == NULL || CLUTTER_IS_ACTOR (handle));
919 if (priv->drag_handle == handle)
922 if (priv->drag_handle != NULL)
923 g_signal_handlers_disconnect_by_func (priv->drag_handle,
924 G_CALLBACK (on_drag_handle_destroy),
927 priv->drag_handle = handle;
929 if (priv->drag_handle != NULL)
930 g_signal_connect (priv->drag_handle, "destroy",
931 G_CALLBACK (on_drag_handle_destroy),
934 g_object_notify_by_pspec (G_OBJECT (action), drag_props[PROP_DRAG_HANDLE]);
938 * clutter_drag_action_get_drag_handle:
939 * @action: a #ClutterDragAction
941 * Retrieves the drag handle set by clutter_drag_action_set_drag_handle()
943 * Return value: (transfer none): a #ClutterActor, used as the drag
944 * handle, or %NULL if none was set
949 clutter_drag_action_get_drag_handle (ClutterDragAction *action)
951 g_return_val_if_fail (CLUTTER_IS_DRAG_ACTION (action), NULL);
953 return action->priv->drag_handle;
957 * clutter_drag_action_set_drag_axis:
958 * @action: a #ClutterDragAction
959 * @axis: the axis to constraint the dragging to
961 * Restricts the dragging action to a specific axis
966 clutter_drag_action_set_drag_axis (ClutterDragAction *action,
967 ClutterDragAxis axis)
969 ClutterDragActionPrivate *priv;
971 g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action));
972 g_return_if_fail (axis >= CLUTTER_DRAG_AXIS_NONE &&
973 axis <= CLUTTER_DRAG_Y_AXIS);
977 if (priv->drag_axis == axis)
980 priv->drag_axis = axis;
982 g_object_notify_by_pspec (G_OBJECT (action), drag_props[PROP_DRAG_AXIS]);
986 * clutter_drag_action_get_drag_axis:
987 * @action: a #ClutterDragAction
989 * Retrieves the axis constraint set by clutter_drag_action_set_drag_axis()
991 * Return value: the axis constraint
996 clutter_drag_action_get_drag_axis (ClutterDragAction *action)
998 g_return_val_if_fail (CLUTTER_IS_DRAG_ACTION (action),
999 CLUTTER_DRAG_AXIS_NONE);
1001 return action->priv->drag_axis;
1005 * clutter_drag_action_get_press_coords:
1006 * @action: a #ClutterDragAction
1007 * @press_x: (out): return location for the press event's X coordinate
1008 * @press_y: (out): return location for the press event's Y coordinate
1010 * Retrieves the coordinates, in stage space, of the press event
1011 * that started the dragging
1016 clutter_drag_action_get_press_coords (ClutterDragAction *action,
1020 g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action));
1023 *press_x = action->priv->press_x;
1026 *press_y = action->priv->press_y;
1030 * clutter_drag_action_get_motion_coords:
1031 * @action: a #ClutterDragAction
1032 * @motion_x: (out): return location for the latest motion
1033 * event's X coordinate
1034 * @motion_y: (out): return location for the latest motion
1035 * event's Y coordinate
1037 * Retrieves the coordinates, in stage space, of the latest motion
1038 * event during the dragging
1043 clutter_drag_action_get_motion_coords (ClutterDragAction *action,
1047 g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action));
1050 *motion_x = action->priv->last_motion_x;
1053 *motion_y = action->priv->last_motion_y;