/* Set source actor */
static void _xfdashboard_drag_action_set_source(XfdashboardDragAction *self, ClutterActor *inSource)
{
	XfdashboardDragActionPrivate	*priv;

	g_return_if_fail(XFDASHBOARD_IS_DRAG_ACTION(self));
	g_return_if_fail(inSource==NULL || CLUTTER_IS_ACTOR(inSource));

	priv=self->priv;

	/* Release old source actor */
	if(priv->source)
	{
		/* Unset style */
		if(XFDASHBOARD_IS_ACTOR(priv->source))
		{
			xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(priv->source), "current-drag-source");
		}

		/* Release actor */
		g_object_unref(priv->source);
		priv->source=NULL;
	}

	/* Set new source actor */
	if(inSource)
	{
		/* Set actor */
		priv->source=CLUTTER_ACTOR(g_object_ref(inSource));
	}
}
/* Drag of an actor to this view as drop target begins */
static gboolean _xfdashboard_workspace_selector_on_drop_begin(XfdashboardLiveWorkspace *self,
																XfdashboardDragAction *inDragAction,
																gpointer inUserData)
{
	ClutterActor					*dragSource;
	ClutterActor					*draggedActor;
	gboolean						canHandle;

	g_return_val_if_fail(XFDASHBOARD_IS_LIVE_WORKSPACE(self), FALSE);
	g_return_val_if_fail(XFDASHBOARD_IS_DRAG_ACTION(inDragAction), FALSE);
	g_return_val_if_fail(XFDASHBOARD_IS_DROP_ACTION(inUserData), FALSE);

	canHandle=FALSE;

	/* Get source where dragging started and actor being dragged */
	dragSource=xfdashboard_drag_action_get_source(inDragAction);
	draggedActor=xfdashboard_drag_action_get_actor(inDragAction);

	/* Check if we can handle dragged actor from given source */
	if(XFDASHBOARD_IS_WINDOWS_VIEW(dragSource) &&
		XFDASHBOARD_IS_LIVE_WINDOW(draggedActor))
	{
		canHandle=TRUE;
	}

	if(XFDASHBOARD_IS_APPLICATION_BUTTON(draggedActor))
	{
		canHandle=TRUE;
	}

	/* Return TRUE if we can handle dragged actor in this drop target
	 * otherwise FALSE
	 */
	return(canHandle);
}
/* Find drop target at position */
static XfdashboardDropAction* _xfdashboard_drag_action_find_drop_traget_at_coord(XfdashboardDragAction *self,
																					gfloat inStageX,
																					gfloat inStageY)
{
	XfdashboardDragActionPrivate	*priv;
	GSList							*list;

	g_return_val_if_fail(XFDASHBOARD_IS_DRAG_ACTION(self), NULL);

	priv=self->priv;

	/* Iterate through list and return first drop target in list
	 * where coordinates fit in
	 */
	for(list=priv->targets; list; list=g_slist_next(list))
	{
		ClutterActorMeta			*actorMeta=CLUTTER_ACTOR_META(list->data);
		ClutterActor				*actor=clutter_actor_meta_get_actor(actorMeta);
		gfloat						x, y, w, h;

		/* Get position and size of actor in stage coordinates */
		clutter_actor_get_transformed_position(actor, &x, &y);
		clutter_actor_get_transformed_size(actor, &w, &h);

		/* If given stage coordinates fit in actor we found it */
		if(inStageX>=x && inStageX<(x+w) &&
			inStageY>=y && inStageY<(y+h))
		{
			return(XFDASHBOARD_DROP_ACTION(actorMeta));
		}
	}

	/* If we get here no drop target was found */
	return(NULL);
}
/* Get last motion delta coordinates */
void xfdashboard_drag_action_get_motion_delta(XfdashboardDragAction *self, gfloat *outDeltaX, gfloat *outDeltaY)
{
	g_return_if_fail(XFDASHBOARD_IS_DRAG_ACTION(self));

	if(outDeltaX) *outDeltaX=self->priv->lastDeltaX;
	if(outDeltaY) *outDeltaY=self->priv->lastDeltaY;
}
/* Allocation of a drop target changed */
static void _xfdashboard_drag_on_drop_target_allocation_changed(XfdashboardDragAction *self,
																ClutterActorBox *inBox,
																ClutterAllocationFlags inFlags,
																gpointer inUserData)
{
	g_return_if_fail(XFDASHBOARD_IS_DRAG_ACTION(self));

	/* Resort list as overlapping of actors might have changed */
	_xfdashboard_drag_action_sort_targets(self);
}
/* Drag handle has changed so unset styles on old handle and set style on new one */
static void _xfdashboard_drag_action_on_drag_handle_changed(XfdashboardDragAction *self,
															GParamSpec *inSpec,
															gpointer inUserData)
{
	XfdashboardDragActionPrivate	*priv;
	gchar							*styleClass;

	g_return_if_fail(XFDASHBOARD_IS_DRAG_ACTION(self));

	priv=self->priv;

	/* Unset styles on current drag handle */
	if(priv->dragHandle &&
		XFDASHBOARD_IS_ACTOR(priv->dragHandle))
	{
		/* Unset style */
		if(priv->source)
		{
			styleClass=g_strdup_printf("drag-source-%s", G_OBJECT_TYPE_NAME(priv->source));
			xfdashboard_stylable_remove_class(XFDASHBOARD_STYLABLE(priv->dragHandle), styleClass);
			g_free(styleClass);
		}

		styleClass=g_strdup_printf("drag-actor-%s", G_OBJECT_TYPE_NAME(priv->actor));
		xfdashboard_stylable_remove_class(XFDASHBOARD_STYLABLE(priv->dragHandle), styleClass);
		g_free(styleClass);

		xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(priv->dragHandle), "drag-handle");

		/* Forget drag handle */
		priv->dragHandle=NULL;
	}

	/* Remember new drag handle and set styles */
	priv->dragHandle=clutter_drag_action_get_drag_handle(CLUTTER_DRAG_ACTION(self));
	if(priv->dragHandle &&
		XFDASHBOARD_IS_ACTOR(priv->dragHandle))
	{
		/* Set style */
		if(priv->source)
		{
			styleClass=g_strdup_printf("drag-source-%s", G_OBJECT_TYPE_NAME(priv->source));
			xfdashboard_stylable_add_class(XFDASHBOARD_STYLABLE(priv->dragHandle), styleClass);
			g_free(styleClass);
		}

		styleClass=g_strdup_printf("drag-actor-%s", G_OBJECT_TYPE_NAME(priv->actor));
		xfdashboard_stylable_add_class(XFDASHBOARD_STYLABLE(priv->dragHandle), styleClass);
		g_free(styleClass);

		xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(priv->dragHandle), "drag-handle");
	}

}
static void _xfdashboard_drag_action_sort_targets(XfdashboardDragAction *self)
{
	XfdashboardDragActionPrivate	*priv;

	g_return_if_fail(XFDASHBOARD_IS_DRAG_ACTION(self));

	priv=self->priv;

	/* Sort targets */
	priv->targets=g_slist_sort(priv->targets, _xfdashboard_drag_action_sort_targets_callback);
}
/* Dragged actor was dropped on this drop target */
static void _xfdashboard_workspace_selector_on_drop_drop(XfdashboardLiveWorkspace *self,
															XfdashboardDragAction *inDragAction,
															gfloat inX,
															gfloat inY,
															gpointer inUserData)
{
	ClutterActor						*draggedActor;

	g_return_if_fail(XFDASHBOARD_IS_LIVE_WORKSPACE(self));
	g_return_if_fail(XFDASHBOARD_IS_DRAG_ACTION(inDragAction));
	g_return_if_fail(XFDASHBOARD_IS_DROP_ACTION(inUserData));

	/* Get dragged actor */
	draggedActor=xfdashboard_drag_action_get_actor(inDragAction);

	/* Check if dragged actor is a window so move window to workspace */
	if(XFDASHBOARD_IS_LIVE_WINDOW(draggedActor))
	{
		XfdashboardWindowTrackerWindow	*window;

		/* Get window */
		window=xfdashboard_live_window_get_window(XFDASHBOARD_LIVE_WINDOW(draggedActor));
		g_return_if_fail(window);

		/* Move window to workspace */
		xfdashboard_window_tracker_window_move_to_workspace(window, xfdashboard_live_workspace_get_workspace(self));
	}

	/* Check if dragged actor is a application button so launch app at workspace */
	if(XFDASHBOARD_IS_APPLICATION_BUTTON(draggedActor))
	{
		XfdashboardApplicationButton	*button;
		GAppLaunchContext				*context;

		/* Get application button */
		button=XFDASHBOARD_APPLICATION_BUTTON(draggedActor);

		/* Launch application at workspace where application button was dropped */
		context=xfdashboard_create_app_context(xfdashboard_live_workspace_get_workspace(self));
		xfdashboard_application_button_execute(button, context);
		g_object_unref(context);
	}
}
/* A known "motion actor" is going to be destroyed. Do not swap parameters for
 * usual use of g_signal_connect_swapped to reuse this function for g_slist_foreach.
 */
static void _xfdashboard_drag_action_on_motion_actor_destroyed(gpointer inActor,
																gpointer inUserData)
{
	XfdashboardDragAction			*self;
	XfdashboardDragActionPrivate	*priv;
	ClutterActor					*actor;

	g_return_if_fail(CLUTTER_IS_ACTOR(inActor));
	g_return_if_fail(XFDASHBOARD_IS_DRAG_ACTION(inUserData));

	actor=CLUTTER_ACTOR(inActor);
	self=XFDASHBOARD_DRAG_ACTION(inUserData);
	priv=self->priv;

	/* Disconnect signal */
	g_signal_handlers_disconnect_by_func(actor, G_CALLBACK(_xfdashboard_drag_action_on_motion_actor_destroyed), self);

	/* Remove from list */
	priv->lastMotionActors=g_slist_remove(priv->lastMotionActors, actor);
}
/* The dragged actor is going to be destroy. Cancel drag action */
static void _xfdashboard_drag_action_on_dragged_actor_destroyed(XfdashboardDragAction *self,
																gpointer inUserData)
{
	XfdashboardDragActionPrivate	*priv;
	gfloat							x, y;

	g_return_if_fail(XFDASHBOARD_IS_DRAG_ACTION(self));

	priv=self->priv;
	x=y=0.0f;

	/* Remove signal from dragged actor although it is going to be destroyed now */
	g_signal_handler_disconnect(priv->actor, priv->actorDestroySignalID);
	priv->actorDestroySignalID=0;

	/* Mark drag action being cancelled */
	priv->dragCancelled=TRUE;

	/* Emit "drag-end" signal */
	clutter_drag_action_get_motion_coords(CLUTTER_DRAG_ACTION(self), &x, &y);
	g_signal_emit_by_name(self, "drag-end", priv->actor, x, y, 0, NULL);
}
/* Get source actor where drag began */
ClutterActor* xfdashboard_drag_action_get_source(XfdashboardDragAction *self)
{
	g_return_val_if_fail(XFDASHBOARD_IS_DRAG_ACTION(self), NULL);

	return(self->priv->source);
}
/* Dragging of actor ended */
static void _xfdashboard_drag_action_drag_end(ClutterDragAction *inAction,
												ClutterActor *inActor,
												gfloat inStageX,
												gfloat inStageY,
												ClutterModifierType inModifiers)
{
	XfdashboardDragAction				*self;
	XfdashboardDragActionPrivate		*priv;
	ClutterDragActionClass				*dragActionClass;
	GSList								*list;
	XfdashboardDropAction				*dropTarget;
	gfloat								dropX, dropY;
	gboolean							canDrop;

	g_return_if_fail(XFDASHBOARD_IS_DRAG_ACTION(inAction));

	self=XFDASHBOARD_DRAG_ACTION(inAction);
	priv=self->priv;
	dragActionClass=CLUTTER_DRAG_ACTION_CLASS(xfdashboard_drag_action_parent_class);
	canDrop=FALSE;
	dropTarget=NULL;

	/* Hold a reference on ourselve as ClutterAction as the actor where we are bound to
	 * may be destroyed in this function. We need to keep alive this action until
	 * function ends.
	 */
	g_object_ref(self);

	/* Unset styles */
	if(priv->source && XFDASHBOARD_IS_ACTOR(priv->source))
	{
		xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(priv->source), "drag-source");
	}

	if(XFDASHBOARD_IS_ACTOR(priv->actor))
	{
		xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(priv->actor), "dragged");
	}

	if(priv->dragHandle &&
		XFDASHBOARD_IS_ACTOR(priv->dragHandle))
	{
		gchar							*styleClass;

		if(priv->source)
		{
			styleClass=g_strdup_printf("drag-source-%s", G_OBJECT_TYPE_NAME(priv->source));
			xfdashboard_stylable_remove_class(XFDASHBOARD_STYLABLE(priv->dragHandle), styleClass);
			g_free(styleClass);
		}

		styleClass=g_strdup_printf("drag-actor-%s", G_OBJECT_TYPE_NAME(priv->actor));
		xfdashboard_stylable_remove_class(XFDASHBOARD_STYLABLE(priv->dragHandle), styleClass);
		g_free(styleClass);

		xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(priv->dragHandle), "drag-handle");

		priv->dragHandle=NULL;
	}

	if(priv->dragHandleChangedID)
	{
		g_signal_handler_disconnect(self, priv->dragHandleChangedID);
		priv->dragHandleChangedID=0;
	}

	/* Remove 'destroy' signal on dragged actor */
	if(priv->actorDestroySignalID)
	{
		g_signal_handler_disconnect(priv->actor, priv->actorDestroySignalID);
		priv->actorDestroySignalID=0;
	}

	/* Remove our listerners for allocation changes */
	for(list=priv->targets; list; list=g_slist_next(list))
	{
		XfdashboardDropAction			*target=XFDASHBOARD_DROP_ACTION(list->data);
		ClutterActorMeta				*actorMeta=CLUTTER_ACTOR_META(target);
		ClutterActor					*actor=clutter_actor_meta_get_actor(actorMeta);

		g_signal_handlers_disconnect_by_func(actor, G_CALLBACK(_xfdashboard_drag_on_drop_target_allocation_changed), self);
	}

	/* Find drop target at stage coordinate if dragged actor was not destroyed */
	if(!priv->dragCancelled) dropTarget=_xfdashboard_drag_action_find_drop_traget_at_coord(self, inStageX, inStageY);

	/* If drop target was found check if we are allowed to drop on it. */
	if(dropTarget)
	{
		/* Transform event coordinates relative to drop target */
		_xfdashboard_drag_action_transform_stage_point(dropTarget,
														inStageX, inStageY,
														&dropX, &dropY);

		/* Ask drop target if we are allowed to drop dragged actor on it */
		g_signal_emit_by_name(dropTarget, "can-drop", self, dropX, dropY, &canDrop);
	}

	/* If we cannot drop the draggged actor emit "drag-cancel" on dragged actor */
	if(!canDrop) g_signal_emit_by_name(inAction, "drag-cancel", priv->actor, inStageX, inStageY, NULL);

	/* Iterate through list of drop targets to emit the "end" signal to the ones
	* on which the dragged actor will not be drop (either they were not the target
	* or it did not allow to drop on it). The real drop target gets the "drop"
	* signal.
	*/
	for(list=priv->targets; list; list=g_slist_next(list))
	{
		XfdashboardDropAction			*target=XFDASHBOARD_DROP_ACTION(list->data);

		if(canDrop && target && target==dropTarget)
		{
			g_signal_emit_by_name(dropTarget, "drop", self, dropX, dropY, NULL);
		}
			else
			{
				g_signal_emit_by_name(target, "end", self, NULL);
			}
	}

	/* Call parent's class method at last */
	if(dragActionClass->drag_end) dragActionClass->drag_end(inAction, inActor, inStageX, inStageY, inModifiers);

	/* Forget dragged actor as dragging has ended now */
	priv->actor=NULL;

	/* Free list of drop targets and unref each drop target */
	if(priv->targets) g_slist_free_full(priv->targets, g_object_unref);
	priv->targets=NULL;

	/* Free list of actor we crossed by motion */
	if(priv->lastMotionActors)
	{
		g_slist_foreach(priv->lastMotionActors, _xfdashboard_drag_action_on_motion_actor_destroyed, self);
		if(priv->lastMotionActors) g_slist_free(priv->lastMotionActors);
		priv->lastMotionActors=NULL;
	}

	/* Reset variables */
	priv->lastDropTarget=NULL;

	/* Release the reference we took at function beginning */
	g_object_unref(self);
}
/* Dragged actor moved */
static void _xfdashboard_drag_action_drag_motion(ClutterDragAction *inAction,
													ClutterActor *inActor,
													gfloat inDeltaX,
													gfloat inDeltaY)
{
	XfdashboardDragAction				*self;
	XfdashboardDragActionPrivate		*priv;
	ClutterDragActionClass				*dragActionClass;
	gfloat								stageX, stageY;
	XfdashboardDropAction				*dropTarget;
	gfloat								dropX, dropY;
	const ClutterEvent					*event;

	g_return_if_fail(XFDASHBOARD_IS_DRAG_ACTION(inAction));

	self=XFDASHBOARD_DRAG_ACTION(inAction);
	priv=self->priv;
	dragActionClass=CLUTTER_DRAG_ACTION_CLASS(xfdashboard_drag_action_parent_class);

	/* Call parent's class method */
	if(dragActionClass->drag_motion) dragActionClass->drag_motion(inAction, inActor, inDeltaX, inDeltaY);

	/* Remember motion delta coordinates */
	priv->lastDeltaX=inDeltaX;
	priv->lastDeltaY=inDeltaY;

	/* Get event coordinates relative to stage */
	clutter_drag_action_get_motion_coords(inAction, &stageX, &stageY);

	/* Find drop target at stage coordinate */
	dropTarget=_xfdashboard_drag_action_find_drop_traget_at_coord(self, stageX, stageY);

	/* If found drop target is not the same as the last one emit "drag-leave"
	 * signal at last drop target and "drag-enter" in new drop target
	 */
	if(priv->lastDropTarget!=dropTarget)
	{
		/* Emit "drag-leave" signal on last drop target */
		if(priv->lastDropTarget)
		{
			g_signal_emit_by_name(priv->lastDropTarget, "drag-leave", self, NULL);
			priv->lastDropTarget=NULL;
		}

		/* Check if new drop target is active and emit "drag-enter" signal */
		if(dropTarget)
		{
			ClutterActorMeta			*actorMeta=CLUTTER_ACTOR_META(dropTarget);
			ClutterActor				*dropActor=clutter_actor_meta_get_actor(actorMeta);

			if(clutter_actor_meta_get_enabled(actorMeta) &&
				clutter_actor_is_visible(dropActor) &&
				clutter_actor_get_reactive(dropActor))
			{
				g_signal_emit_by_name(dropTarget, "drag-enter", self, NULL);
				priv->lastDropTarget=dropTarget;
			}
		}
	}

	/* Transform event coordinates relative to last drop target which
	 * should be the drop target under pointer device if it is active
	 * and emit "drag-motion" signal
	 */
	if(priv->lastDropTarget)
	{
		dropX=dropY=0.0f;
		_xfdashboard_drag_action_transform_stage_point(priv->lastDropTarget,
														stageX, stageY,
														&dropX, &dropY);
		g_signal_emit_by_name(priv->lastDropTarget, "drag-motion", self, dropX, dropY, NULL);
	}

	/* We are derived from ClutterDragAction and this one disables stage motion
	 * so no "enter-event", "motion-event" and "leave-event" will be emitted while
	 * dragging. We need to do it on our own.
	 */
	event=clutter_get_current_event();
	if(event && clutter_event_type(event)==CLUTTER_MOTION)
	{
		GSList							*list, *next;
		ClutterStage					*stage;
		ClutterActor					*motionActor;
		gboolean						newMotionActor;
		ClutterActor					*actor;
		gfloat							x, y, w, h;
		gboolean						result;
		ClutterEvent					*actorEvent;

		/* Get stage where event happened */
		stage=clutter_event_get_stage(event);
		if(stage)
		{
			/* Get actor under pointer */
			newMotionActor=TRUE;
			motionActor=clutter_stage_get_actor_at_pos(stage,
														CLUTTER_PICK_REACTIVE,
														stageX, stageY);

			/* Iterate through list of crossed actors so far and check if pointer
			 * is still inside. If pointer is outside of an actor emit "leave-event".
			 * For each actor the pointer is still inside emit this "motion-event".
			 * Also check if actor under pointer is already is list to prevent
			 * "enter-event" to be emitted more than once.
			 */
			list=priv->lastMotionActors;
			while(list)
			{
				/* Get next entry now as this entry might get deleted */
				next=g_slist_next(list);

				/* Get actor from entry */
				actor=CLUTTER_ACTOR(list->data);

				/* Actor must be one same stage where event happened */
				if(clutter_actor_get_stage(actor)!=CLUTTER_ACTOR(stage)) continue;

				/* Get position and size of actor in stage coordinates */
				clutter_actor_get_transformed_position(actor, &x, &y);
				clutter_actor_get_transformed_size(actor, &w, &h);

				/* Check if pointer is still inside actor */
				if(stageX>=x && stageX<(x+w) &&
					stageY>=y && stageY<(y+h))
				{

					/* Check if actor is the "new" motion actor. If so set flag. */
					if(actor==motionActor) newMotionActor=FALSE;

					/* Emit "motion-event" */
					actorEvent=clutter_event_copy(event);
					actorEvent->motion.source=actor;

					g_signal_emit_by_name(actor, "motion-event", actorEvent, &result);

					clutter_event_free(actorEvent);
				}
					/* Pointer is not inside actor anymore so remove actor from list
					 * of last known "motion actors" and send "leave-event"
					 */
					else
					{
						/* Disconnect signal */
						g_signal_handlers_disconnect_by_func(actor, G_CALLBACK(_xfdashboard_drag_action_on_motion_actor_destroyed), self);

						/* Remove from list */
						priv->lastMotionActors=g_slist_remove_link(priv->lastMotionActors, list);
						g_slist_free_1(list);

						/* Create and emit "leave-event" */
						actorEvent=clutter_event_new(CLUTTER_LEAVE);
						actorEvent->crossing.time=event->motion.time;
						actorEvent->crossing.flags=event->motion.flags;
						actorEvent->crossing.stage=event->motion.stage;
						actorEvent->crossing.source=actor;

						actorEvent->crossing.x=event->motion.x;
						actorEvent->crossing.y=event->motion.y;
						actorEvent->crossing.device=event->motion.device;
						actorEvent->crossing.related=event->motion.source;

						g_signal_emit_by_name(actor, "leave-event", actorEvent, &result);

						clutter_event_free(actorEvent);
					}

				/* Proceed with next actor */
				list=next;
			}

			/* We have an actor under pointer and was not seen while iterating
			 * through list of all last known "motion actors" then add this actor
			 * to list and emit "enter-event" and also all parent actors because
			 * if pointer is inside their child then it is also inside them.
			 */
			if(motionActor && newMotionActor)
			{
				while(motionActor)
				{
					/* Avoid duplicates */
					if(!g_slist_find(priv->lastMotionActors, motionActor))
					{
						/* Add to list */
						priv->lastMotionActors=g_slist_append(priv->lastMotionActors, motionActor);

						/* Create and emit "enter-event" */
						actorEvent=clutter_event_new(CLUTTER_ENTER);
						actorEvent->crossing.time=event->motion.time;
						actorEvent->crossing.flags=event->motion.flags;
						actorEvent->crossing.stage=event->motion.stage;
						actorEvent->crossing.source=event->motion.source;

						actorEvent->crossing.x=event->motion.x;
						actorEvent->crossing.y=event->motion.y;
						actorEvent->crossing.device=event->motion.device;
						actorEvent->crossing.related=motionActor;

						g_signal_emit_by_name(motionActor, "enter-event", actorEvent, &result);

						clutter_event_free(actorEvent);

						/* To prevent emiting these motion events on actors being
						 * destroyed while drag is in progress we connect to 'destroy'
						 * signal of each "motion actor" added to list. The signal
						 * handler will be removed either on actor's destruction by
						 * signal handler's callback, when pointer leaves actor or on
						 * end of drag.
						 */
						g_signal_connect(motionActor, "destroy", G_CALLBACK(_xfdashboard_drag_action_on_motion_actor_destroyed), self);
					}

					/* Get parent */
					motionActor=clutter_actor_get_parent(motionActor);
				}
			}
		}
	}
}
/* Dragging of actor begins */
static void _xfdashboard_drag_action_drag_begin(ClutterDragAction *inAction,
												ClutterActor *inActor,
												gfloat inStageX,
												gfloat inStageY,
												ClutterModifierType inModifiers)
{
	XfdashboardDragAction				*self;
	XfdashboardDragActionPrivate		*priv;
	ClutterDragActionClass				*dragActionClass;
	GSList								*list;

	g_return_if_fail(XFDASHBOARD_IS_DRAG_ACTION(inAction));

	self=XFDASHBOARD_DRAG_ACTION(inAction);
	priv=self->priv;
	dragActionClass=CLUTTER_DRAG_ACTION_CLASS(xfdashboard_drag_action_parent_class);

	/* Call parent's class method */
	if(dragActionClass->drag_begin) dragActionClass->drag_begin(inAction, inActor, inStageX, inStageY, inModifiers);

	/* Remember dragged actor while dragging and listen to possible 'destroy' signal emissions */
	priv->actor=inActor;
	priv->actorDestroySignalID=g_signal_connect_swapped(priv->actor, "destroy", G_CALLBACK(_xfdashboard_drag_action_on_dragged_actor_destroyed), self);

	/* Get list of drop targets. It is a new list with all current
	 * drop targets already reffed. So the drop targets will be valid
	 * while dragging
	 */
	priv->targets=xfdashboard_drop_action_get_targets();

	/* Emit "begin" signal on all drop targets to determine if they
	 * can handle dragged actor and to prepare them for dragging.
	 * All targets returning TRUE (and therefore telling us they
	 * can handle dragged actor and are prepared for drag'n'drop)
	 * will be sorted.
	 */
	list=priv->targets;
	while(list)
	{
		XfdashboardDropAction			*dropTarget=XFDASHBOARD_DROP_ACTION(list->data);
		gboolean						canHandle=FALSE;

		g_signal_emit_by_name(dropTarget, "begin", self, &canHandle);
		if(!canHandle)
		{
			GSList						*next;

			/* Drop target cannot handle dragged actor so unref it and
			 * remove it from list of drop targets
			 */
			next=g_slist_next(list);
			priv->targets=g_slist_remove_link(priv->targets, list);
			g_object_unref(list->data);
			g_slist_free_1(list);
			list=next;
		}
			else list=g_slist_next(list);
	}
	_xfdashboard_drag_action_sort_targets(self);

	/* We should listen to allocation changes for each actor which
	 * is an active drop target.
	 */
	for(list=priv->targets; list; list=g_slist_next(list))
	{
		XfdashboardDropAction			*dropTarget=XFDASHBOARD_DROP_ACTION(list->data);
		ClutterActorMeta				*actorMeta=CLUTTER_ACTOR_META(dropTarget);
		ClutterActor					*actor=clutter_actor_meta_get_actor(actorMeta);

		g_signal_connect_swapped(actor, "allocation-changed", G_CALLBACK(_xfdashboard_drag_on_drop_target_allocation_changed), self);
	}

	/* Setup for dragging */
	priv->dragCancelled=FALSE;
	priv->lastDropTarget=NULL;
	priv->lastMotionActors=NULL;

	/* Set styles */
	if(priv->source && XFDASHBOARD_IS_ACTOR(priv->source))
	{
		xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(priv->source), "drag-source");
	}

	if(XFDASHBOARD_IS_ACTOR(priv->actor))
	{
		xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(priv->actor), "dragged");
	}

	priv->dragHandle=clutter_drag_action_get_drag_handle(CLUTTER_DRAG_ACTION(self));
	if(priv->dragHandle &&
		XFDASHBOARD_IS_ACTOR(priv->dragHandle))
	{
		gchar							*styleClass;

		if(priv->source)
		{
			styleClass=g_strdup_printf("drag-source-%s", G_OBJECT_TYPE_NAME(priv->source));
			xfdashboard_stylable_add_class(XFDASHBOARD_STYLABLE(priv->dragHandle), styleClass);
			g_free(styleClass);
		}

		styleClass=g_strdup_printf("drag-actor-%s", G_OBJECT_TYPE_NAME(priv->actor));
		xfdashboard_stylable_add_class(XFDASHBOARD_STYLABLE(priv->dragHandle), styleClass);
		g_free(styleClass);

		xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(priv->dragHandle), "drag-handle");

		/* Get notified if drag handle changes */
		priv->dragHandleChangedID=g_signal_connect(self, "notify::drag-handle", G_CALLBACK(_xfdashboard_drag_action_on_drag_handle_changed), NULL);
	}
}