[Xfce4-commits] [apps/xfdashboard] 02/03: Adding support to animate actor when it will be shown or hidden

noreply at xfce.org noreply at xfce.org
Mon Apr 6 15:05:41 CEST 2020


This is an automated email from the git hooks/post-receive script.

n   o   m   a   d       p   u   s   h   e   d       a       c   o   m   m   i   t       t   o       b   r   a   n   c   h       m   a   s   t   e   r   
   in repository apps/xfdashboard.

commit 04c149e68df56cf576285f118b020a5b490a3040
Author: Stephan Haller <nomad at froevel.de>
Date:   Mon Apr 6 12:16:48 2020 +0200

    Adding support to animate actor when it will be shown or hidden
---
 data/themes/xfdashboard/animations.xml |  21 +++
 libxfdashboard/actor.c                 | 180 +++++++++++++++------
 libxfdashboard/animation.c             | 146 +++++++++++++----
 libxfdashboard/animation.h             |  19 +--
 libxfdashboard/collapse-box.c          |   3 +-
 libxfdashboard/theme-animation.c       | 173 +++++++++++++++-----
 libxfdashboard/transition-group.c      | 281 +++++++++++++++------------------
 libxfdashboard/window-tracker.c        |   2 +-
 8 files changed, 537 insertions(+), 288 deletions(-)

diff --git a/data/themes/xfdashboard/animations.xml b/data/themes/xfdashboard/animations.xml
index d049f70..6b52419 100644
--- a/data/themes/xfdashboard/animations.xml
+++ b/data/themes/xfdashboard/animations.xml
@@ -22,4 +22,25 @@
 			</apply>
 		</timeline>
 	</trigger>
+
+	<trigger id="view-visible" sender="XfdashboardView" signal="show">
+		<timeline delay="0" duration="1" mode="linear">
+			<apply>
+				<property name="opacity" from="0" to="0" />
+			</apply>
+		</timeline>
+		<timeline delay="500" duration="500" mode="linear">
+			<apply>
+				<property name="opacity" from="0" to="255" />
+			</apply>
+		</timeline>
+	</trigger>
+
+	<trigger id="view-hidden" sender="XfdashboardView" signal="hide">
+		<timeline delay="0" duration="500" mode="linear">
+			<apply>
+				<property name="opacity" to="0" />
+			</apply>
+		</timeline>
+	</trigger>
 </animations>
diff --git a/libxfdashboard/actor.c b/libxfdashboard/actor.c
index 3f122b7..9073ebc 100644
--- a/libxfdashboard/actor.c
+++ b/libxfdashboard/actor.c
@@ -57,6 +57,8 @@ struct _XfdashboardActorPrivate
 	gchar					*stylePseudoClasses;
 
 	/* Instance related */
+	gboolean				inDestruction;
+
 	GHashTable				*lastThemeStyleSet;
 	gboolean				forceStyleRevalidation;
 
@@ -89,8 +91,9 @@ static GParamSpec* XfdashboardActorProperties[PROP_LAST]={ 0, };
 typedef struct _XfdashboardActorAnimationEntry		XfdashboardActorAnimationEntry;
 struct _XfdashboardActorAnimationEntry
 {
-	gchar					*signal;
-	XfdashboardAnimation	*animation;
+	gboolean									inDestruction;
+	gchar										*signal;
+	XfdashboardAnimation						*animation;
 };
 
 #define XFDASHBOARD_ACTOR_PARAM_SPEC_REF		(_xfdashboard_actor_param_spec_ref_quark())
@@ -110,6 +113,15 @@ static void _xfdashboard_actor_animation_entry_free(XfdashboardActorAnimationEnt
 {
 	g_return_if_fail(inData);
 
+	/* Do not free anything if this entry is already in destruction */
+	if(inData->inDestruction) return;
+
+	/* Set flag that this data will be freed now as this function could
+	 * be called recursive (e.g. by other signal handlers) resulting
+	 * in double-free.
+	 */
+	inData->inDestruction=TRUE;
+
 	/* Release allocated resources */
 	if(inData->animation) g_object_unref(inData->animation);
 	if(inData->signal) g_free(inData->signal);
@@ -243,7 +255,8 @@ static void _xfdashboard_actor_on_mapped_changed(GObject *inObject,
 			}
 
 			/* Start animation */
-			xfdashboard_animation_run(priv->firstTimeMappedAnimation, _xfdashboard_actor_first_time_created_animation_done, self);
+			g_signal_connect_after(priv->firstTimeMappedAnimation, "animation-done", G_CALLBACK(_xfdashboard_actor_first_time_created_animation_done), self);
+			xfdashboard_animation_run(priv->firstTimeMappedAnimation);
 			XFDASHBOARD_DEBUG(self, ANIMATION,
 									"Found and starting animation '%s' for created signal at actor %s",
 									xfdashboard_animation_get_id(priv->firstTimeMappedAnimation),
@@ -822,30 +835,26 @@ static void _xfdashboard_actor_animation_done(XfdashboardAnimation *inAnimation,
 			 * to NULL to avoid unreffing an already disposed or finalized
 			 * object instance.
 			 */
+			priv->animations=g_slist_remove_link(priv->animations, iter);
+
 			data->animation=NULL;
 			_xfdashboard_actor_animation_entry_free(data);
-			priv->animations=g_slist_delete_link(priv->animations, iter);
-
-			/* An animation with equal pointer can be stored only once, so
-			 * stop further iteration.
-			 */
-			break;
+			g_slist_free_1(iter);
 		}
 	}
 }
 
 /* Remove animations for signal and (pseudo-)class */
-static void _xfdashboard_actor_remove_animation(XfdashboardStylable *inStylable,
+static void _xfdashboard_actor_remove_animation(XfdashboardActor *self,
 												const gchar *inAnimationSignal)
 {
-	XfdashboardActor				*self;
 	XfdashboardActorPrivate			*priv;
 	GSList							*iter;
 	XfdashboardActorAnimationEntry	*data;
 
-	g_return_if_fail(XFDASHBOARD_IS_ACTOR(inStylable));
+	g_return_if_fail(XFDASHBOARD_IS_ACTOR(self));
+	g_return_if_fail(inAnimationSignal && *inAnimationSignal);
 
-	self=XFDASHBOARD_ACTOR(inStylable);
 	priv=self->priv;
 
 	/* Iterate through list of animation and lookup animation for signal. If an
@@ -875,29 +884,30 @@ static void _xfdashboard_actor_remove_animation(XfdashboardStylable *inStylable,
 }
 
 /* Lookup animations for signal and (pseudo-)class and run animation at actor */
-static void _xfdashboard_actor_add_animation(XfdashboardStylable *inStylable,
-												const gchar *inAnimationSignal)
+static XfdashboardAnimation* _xfdashboard_actor_add_animation(XfdashboardActor *self,
+																const gchar *inAnimationSignal)
 {
-	XfdashboardActor				*self;
 	XfdashboardActorPrivate			*priv;
 	XfdashboardAnimation			*animation;
 	XfdashboardActorAnimationEntry	*data;
 
-	g_return_if_fail(XFDASHBOARD_IS_ACTOR(inStylable));
+	g_return_val_if_fail(XFDASHBOARD_IS_ACTOR(self), NULL);
+	g_return_val_if_fail(inAnimationSignal && *inAnimationSignal, NULL);
 
-	self=XFDASHBOARD_ACTOR(inStylable);
 	priv=self->priv;
 
+	/* Do not lookup and add animations if actor is in destruction now */
+	if(priv->inDestruction) return(NULL);
+
 	/* Lookup animation for signal-(pseudo-)class combination and if any found
 	 * (i.e. has an ID) add it to list of animations of actor and run it.
 	 */
 	animation=xfdashboard_animation_new(XFDASHBOARD_ACTOR(self), inAnimationSignal);
-	if(!xfdashboard_animation_get_id(animation))
+	if(xfdashboard_animation_is_empty(animation))
 	{
-		/* Empty or invalid animation, so release allocated resources and return */
+		/* Release animation and return NULL */
 		g_object_unref(animation);
-
-		return;
+		return(NULL);
 	}
 
 	/* Check for duplicate animation */
@@ -907,10 +917,9 @@ static void _xfdashboard_actor_add_animation(XfdashboardStylable *inStylable,
 								"Duplicate animation found for signal '%s'",
 								inAnimationSignal);
 
-		/* Release allocated resources */
+		/* Release animation and return NULL */
 		g_object_unref(animation);
-
-		return;
+		return(NULL);
 	}
 
 	/* Create animation entry data and add to list of animations */
@@ -921,10 +930,9 @@ static void _xfdashboard_actor_add_animation(XfdashboardStylable *inStylable,
 					xfdashboard_animation_get_id(animation),
 					inAnimationSignal);
 
-		/* Release allocated resources */
+		/* Release animation and return NULL */
 		g_object_unref(animation);
-
-		return;
+		return(NULL);
 	}
 
 	data->signal=g_strdup(inAnimationSignal);
@@ -933,11 +941,14 @@ static void _xfdashboard_actor_add_animation(XfdashboardStylable *inStylable,
 	priv->animations=g_slist_prepend(priv->animations, data);
 
 	/* Start animation */
-	xfdashboard_animation_run(animation, _xfdashboard_actor_animation_done, self);
+	g_signal_connect_after(animation, "animation-done", G_CALLBACK(_xfdashboard_actor_animation_done), self);
+	xfdashboard_animation_run(animation);
 	XFDASHBOARD_DEBUG(self, ANIMATION,
 							"Found and starting animation '%s' for signal '%s'",
 							xfdashboard_animation_get_id(animation),
 							inAnimationSignal);
+
+	return(animation);
 }
 
 /* Signal handler for "class-added" signal of stylable interface */
@@ -949,12 +960,12 @@ static void _xfdashboard_actor_stylable_class_added(XfdashboardStylable *inStyla
 
 	/* Remove any animation that was added when this class was removed */
 	animationSignal=g_strdup_printf("class-removed:%s", inClass);
-	_xfdashboard_actor_remove_animation(inStylable, animationSignal);
+	_xfdashboard_actor_remove_animation(XFDASHBOARD_ACTOR(inStylable), animationSignal);
 	g_free(animationSignal);
 
 	/* Create animation for this class added */
 	animationSignal=g_strdup_printf("class-added:%s", inClass);
-	_xfdashboard_actor_add_animation(inStylable, animationSignal);
+	_xfdashboard_actor_add_animation(XFDASHBOARD_ACTOR(inStylable), animationSignal);
 	g_free(animationSignal);
 }
 
@@ -967,12 +978,12 @@ static void _xfdashboard_actor_stylable_class_removed(XfdashboardStylable *inSty
 
 	/* Remove any animation that was added when this class was added */
 	animationSignal=g_strdup_printf("class-added:%s", inClass);
-	_xfdashboard_actor_remove_animation(inStylable, animationSignal);
+	_xfdashboard_actor_remove_animation(XFDASHBOARD_ACTOR(inStylable), animationSignal);
 	g_free(animationSignal);
 
 	/* Create animation for this class removed */
 	animationSignal=g_strdup_printf("class-removed:%s", inClass);
-	_xfdashboard_actor_add_animation(inStylable, animationSignal);
+	_xfdashboard_actor_add_animation(XFDASHBOARD_ACTOR(inStylable), animationSignal);
 	g_free(animationSignal);
 }
 
@@ -985,12 +996,12 @@ static void _xfdashboard_actor_stylable_pseudo_class_added(XfdashboardStylable *
 
 	/* Remove any animation that was added when this pseudo-class was removed */
 	animationSignal=g_strdup_printf("pseudo-class-removed:%s", inClass);
-	_xfdashboard_actor_remove_animation(inStylable, animationSignal);
+	_xfdashboard_actor_remove_animation(XFDASHBOARD_ACTOR(inStylable), animationSignal);
 	g_free(animationSignal);
 
 	/* Create animation for this pseudo-class added */
 	animationSignal=g_strdup_printf("pseudo-class-added:%s", inClass);
-	_xfdashboard_actor_add_animation(inStylable, animationSignal);
+	_xfdashboard_actor_add_animation(XFDASHBOARD_ACTOR(inStylable), animationSignal);
 	g_free(animationSignal);
 }
 
@@ -1003,12 +1014,12 @@ static void _xfdashboard_actor_stylable_pseudo_class_removed(XfdashboardStylable
 
 	/* Remove any animation that was added when this pseudo-class was added */
 	animationSignal=g_strdup_printf("pseudo-class-added:%s", inClass);
-	_xfdashboard_actor_remove_animation(inStylable, animationSignal);
+	_xfdashboard_actor_remove_animation(XFDASHBOARD_ACTOR(inStylable), animationSignal);
 	g_free(animationSignal);
 
 	/* Create animation for this pseudo-class removed */
 	animationSignal=g_strdup_printf("pseudo-class-removed:%s", inClass);
-	_xfdashboard_actor_add_animation(inStylable, animationSignal);
+	_xfdashboard_actor_add_animation(XFDASHBOARD_ACTOR(inStylable), animationSignal);
 	g_free(animationSignal);
 }
 
@@ -1125,7 +1136,64 @@ static void _xfdashboard_actor_parent_set(ClutterActor *inActor, ClutterActor *i
 	_xfdashboard_actor_invalidate_recursive(CLUTTER_ACTOR(self));
 }
 
-/* Actor is shown */
+/* Actor will be shown */
+static XfdashboardAnimation* _xfdashboard_actor_replace_animation(XfdashboardActor *self,
+																	const gchar *inOldSignal,
+																	const gchar *inNewSignal)
+{
+	XfdashboardActorPrivate				*priv;
+	XfdashboardAnimation				*oldAnimation;
+	XfdashboardAnimation				*newAnimation;
+	GSList								*iter;
+	XfdashboardActorAnimationEntry		*data;
+
+	g_return_val_if_fail(XFDASHBOARD_IS_ACTOR(self), NULL);
+	g_return_val_if_fail(inOldSignal && *inOldSignal, NULL);
+	g_return_val_if_fail(inNewSignal && *inNewSignal, NULL);
+
+	priv=self->priv;
+	oldAnimation=NULL;
+	newAnimation=NULL;
+
+	/* Iterate through list of animation and lookup animation for old signal */
+	for(iter=priv->animations; iter; iter=g_slist_next(iter))
+	{
+		/* Get animation entry at iterator */
+		data=(XfdashboardActorAnimationEntry*)iter->data;
+		if(!data) continue;
+
+		/* Check if animation entry matches the signal to lookup */
+		if(g_strcmp0(data->signal, inOldSignal)!=0) continue;
+
+		/* Found animation, so stop further iterations */
+		oldAnimation=data->animation;
+	}
+
+	/* Get animation for new signal to replace old one */
+	newAnimation=_xfdashboard_actor_add_animation(self, inNewSignal);
+
+	/* If an animation for old signal, stop it */
+	if(oldAnimation)
+	{
+		/* If no new animation will be started, ensure old one completes
+		 * before it will be removed.
+		 */
+		if(!newAnimation ||
+			!xfdashboard_animation_get_id(newAnimation))
+		{
+			xfdashboard_animation_ensure_complete(oldAnimation);
+		}
+
+		/* Stop old animation by unreffing object instance which calls the
+		 * done callback _xfdashboard_actor_animation_done() of animation.
+		 */
+		g_object_unref(oldAnimation);
+	}
+
+	/* Return new animation which replaced old one */
+	return(newAnimation);
+}
+
 static void _xfdashboard_actor_show(ClutterActor *inActor)
 {
 	XfdashboardActor		*self;
@@ -1149,29 +1217,47 @@ static void _xfdashboard_actor_show(ClutterActor *inActor)
 	{
 		xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(self), "hover");
 	}
+
+	/* Stop any animation started for "hiding" actor which may be still running,
+	 * and lookup the one should be run when actor gets visible */
+	_xfdashboard_actor_replace_animation(self, "hide", "show");
 }
 
-/* Actor is hidden */
-static void _xfdashboard_actor_hide(ClutterActor *inActor)
+/* Actor will be hidden */
+static void _xfdashboard_actor_hide_on_animation_done(XfdashboardActor *inActor, gpointer inUserData)
 {
-	XfdashboardActor		*self;
 	ClutterActorClass		*parentClass;
 
 	g_return_if_fail(XFDASHBOARD_IS_ACTOR(inActor));
 
-	self=XFDASHBOARD_ACTOR(inActor);
-
-	/* Call parent's virtual function */
+	/* Call parent's virtual function to hide actor */
 	parentClass=CLUTTER_ACTOR_CLASS(xfdashboard_actor_parent_class);
 	if(parentClass->hide)
 	{
-		parentClass->hide(inActor);
+		parentClass->hide(CLUTTER_ACTOR(inActor));
 	}
+}
+
+static void _xfdashboard_actor_hide(ClutterActor *inActor)
+{
+	XfdashboardActor		*self;
+	XfdashboardAnimation	*animation;
+
+	g_return_if_fail(XFDASHBOARD_IS_ACTOR(inActor));
+
+	self=XFDASHBOARD_ACTOR(inActor);
 
 	/* Actor is hidden now so remove pseudo-class ":hover" because pointer cannot
 	 * be in an actor hidden.
 	 */
 	xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(self), "hover");
+
+	/* Stop any animation started for "showing" actor which may be still running,
+	 * and lookup the one should be run when actor gets hidden.
+	 */
+	animation=_xfdashboard_actor_replace_animation(self, "show", "hide");
+	if(animation) g_signal_connect_swapped(animation, "animation-done", G_CALLBACK(_xfdashboard_actor_hide_on_animation_done), self);
+		else _xfdashboard_actor_hide_on_animation_done(self, NULL);
 }
 
 /* IMPLEMENTATION: GObject */
@@ -1182,6 +1268,9 @@ static void _xfdashboard_actor_dispose(GObject *inObject)
 	XfdashboardActor			*self=XFDASHBOARD_ACTOR(inObject);
 	XfdashboardActorPrivate		*priv=self->priv;
 
+	/* Set flag that actor will be destructed */
+	priv->inDestruction=TRUE;
+
 	/* Release allocated variables */
 	if(priv->effects)
 	{
@@ -1370,6 +1459,7 @@ void xfdashboard_actor_init(XfdashboardActor *self)
 	priv=self->priv=xfdashboard_actor_get_instance_private(self);
 
 	/* Set up default values */
+	priv->inDestruction=FALSE;
 	priv->canFocus=FALSE;
 	priv->effects=NULL;
 	priv->styleClasses=NULL;
diff --git a/libxfdashboard/animation.c b/libxfdashboard/animation.c
index 387a228..f5500e4 100644
--- a/libxfdashboard/animation.c
+++ b/libxfdashboard/animation.c
@@ -71,9 +71,7 @@ struct _XfdashboardAnimationPrivate
 
 	/* Instance related */
 	GSList								*entries;
-
-	XfdashboardAnimationDoneCallback	doneCallback;
-	gpointer							doneUserData;
+	gboolean							inDestruction;
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE(XfdashboardAnimation,
@@ -92,6 +90,15 @@ enum
 
 static GParamSpec* XfdashboardAnimationProperties[PROP_LAST]={ 0, };
 
+/* Signals */
+enum
+{
+	SIGNAL_ANIMIATION_DONE,
+
+	SIGNAL_LAST
+};
+
+static guint XfdashboardAnimationSignals[SIGNAL_LAST]={ 0, };
 
 /* IMPLEMENTATION: Private variables and methods */
 
@@ -229,12 +236,16 @@ static void _xfdashboard_animation_entry_free(XfdashboardAnimationEntry *inData)
 	g_return_if_fail(inData);
 
 	/* Release allocated resources */
-	if(inData->newFrameSignalID) g_signal_handler_disconnect(inData->transition, inData->newFrameSignalID);
-	if(inData->transitionStoppedID) g_signal_handler_disconnect(inData->transition, inData->transitionStoppedID);
-	if(inData->actorDestroyID) g_signal_handler_disconnect(inData->actor, inData->actorDestroyID);
-	if(inData->transition) g_object_unref(inData->transition);
+	if(inData->transition)
+	{
+		if(inData->newFrameSignalID) g_signal_handler_disconnect(inData->transition, inData->newFrameSignalID);
+		if(inData->transitionStoppedID) g_signal_handler_disconnect(inData->transition, inData->transitionStoppedID);
+		clutter_timeline_stop(CLUTTER_TIMELINE(inData->transition));
+		g_object_unref(inData->transition);
+	}
 	if(inData->actor)
 	{
+		if(inData->actorDestroyID) g_signal_handler_disconnect(inData->actor, inData->actorDestroyID);
 		clutter_actor_remove_transition(inData->actor, inData->self->priv->id);
 		g_object_unref(inData->actor);
 	}
@@ -458,17 +469,30 @@ static void _xfdashboard_animation_dispose(GObject *inObject)
 						"Destroying animation '%s'",
 						priv->id);
 
-	/* Call done callback first before any private data is destroyed */
-	if(priv->doneCallback)
+	if(!priv->inDestruction)
 	{
-		/* Call done callback function */
-		(priv->doneCallback)(self, priv->doneUserData);
+		priv->inDestruction=TRUE;
 
-		/* Unset done callback data */
-		priv->doneCallback=NULL;
-		priv->doneUserData=NULL;
+		/* Emit 'animation-done' signal*/
+		g_signal_emit(self, XfdashboardAnimationSignals[SIGNAL_ANIMIATION_DONE], 0);
 	}
 
+	/* Call parent's class dispose method */
+	G_OBJECT_CLASS(xfdashboard_animation_parent_class)->dispose(inObject);
+}
+
+/* Finalize this object */
+static void _xfdashboard_animation_finalize(GObject *inObject)
+{
+	XfdashboardAnimation			*self=XFDASHBOARD_ANIMATION(inObject);
+	XfdashboardAnimationPrivate		*priv=self->priv;
+
+	XFDASHBOARD_DEBUG(self, ANIMATION,
+						"Destroying animation '%s'",
+						priv->id);
+
+	g_assert(priv->inDestruction);
+
 	/* Release our allocated variables
 	 * Order is important as the ID MUST be released at last!
 	 */
@@ -485,7 +509,7 @@ static void _xfdashboard_animation_dispose(GObject *inObject)
 	}
 
 	/* Call parent's class dispose method */
-	G_OBJECT_CLASS(xfdashboard_animation_parent_class)->dispose(inObject);
+	G_OBJECT_CLASS(xfdashboard_animation_parent_class)->finalize(inObject);
 }
 
 /* Set/get properties */
@@ -540,9 +564,30 @@ void xfdashboard_animation_class_init(XfdashboardAnimationClass *klass)
 	klass->add_animation=_xfdashboard_animation_real_add_animation;
 
 	gobjectClass->dispose=_xfdashboard_animation_dispose;
+	gobjectClass->finalize=_xfdashboard_animation_finalize;
 	gobjectClass->set_property=_xfdashboard_animation_set_property;
 	gobjectClass->get_property=_xfdashboard_animation_get_property;
 
+	/* Define signals */
+	/**
+	 * XfdashboardAnimation::animation-done:
+	 * @self: The animation
+	 *
+	 * The ::animation-done signal is emitted when the animation
+	 * will be destroyed, i.e. either the animation has completed
+	 * or was removed while running.
+	 */
+	XfdashboardAnimationSignals[SIGNAL_ANIMIATION_DONE]=
+		g_signal_new("animation-done",
+						G_TYPE_FROM_CLASS(klass),
+						G_SIGNAL_RUN_CLEANUP,
+						G_STRUCT_OFFSET(XfdashboardAnimationClass, animation_done),
+						NULL,
+						NULL,
+						g_cclosure_marshal_VOID__VOID,
+						G_TYPE_NONE,
+						0);
+
 	/* Define properties */
 	/**
 	 * XfdashboardAnimation:id:
@@ -571,6 +616,7 @@ void xfdashboard_animation_init(XfdashboardAnimation *self)
 	/* Set up default values */
 	priv->id=NULL;
 	priv->entries=NULL;
+	priv->inDestruction=FALSE;
 }
 
 
@@ -629,19 +675,29 @@ const gchar* xfdashboard_animation_get_id(XfdashboardAnimation *self)
 }
 
 /**
+ * xfdashboard_animation_is_empty:
+ * @self: A #XfdashboardAnimation
+ *
+ * Dertermines if animation at @self has any transitions.
+ *
+ * Return value: FALSE if animation contains transition or TRUE if empty.
+ */
+gboolean xfdashboard_animation_is_empty(XfdashboardAnimation *self)
+{
+	g_return_val_if_fail(XFDASHBOARD_IS_ANIMATION(self), TRUE);
+
+	return(self->priv->entries ? FALSE : TRUE);
+}
+
+/**
  * xfdashboard_animation_run:
  * @self: A #XfdashboardAnimation
- * @inCallback: Function to call when animation is destroyed
- * @inUserData: Data to pass to callback function
  *
- * Starts the animation of @self. The callback function @inCallback
- * with this animation and the user-data at @inUserData is called
- * when the animation is destroyed, either is has reached the end
- * of its timeline or was stopped before.
+ * Starts the animation of @self. It emits the ::done signal
+ * when the animation is destroyed, either is has reached the
+ * end of its timeline or was stopped before.
  */
-void xfdashboard_animation_run(XfdashboardAnimation *self,
-								XfdashboardAnimationDoneCallback inCallback,
-								gpointer inUserData)
+void xfdashboard_animation_run(XfdashboardAnimation *self)
 {
 	XfdashboardAnimationPrivate		*priv;
 	GSList							*iter;
@@ -651,13 +707,6 @@ void xfdashboard_animation_run(XfdashboardAnimation *self,
 
 	priv=self->priv;
 
-	/* Store callback function and its user data which is called
-	 * in destruction function when animation is done, e.g.
-	 * animation completed or was removed before it completed.
-	 */
-	priv->doneCallback=inCallback;
-	priv->doneUserData=inUserData;
-
 	/* Add all transition to their actors now if any available ... */
 	if(priv->entries)
 	{
@@ -688,7 +737,40 @@ void xfdashboard_animation_run(XfdashboardAnimation *self,
 		 */
 		else
 		{
-			/* Destroy empty animation */
+			/* Destroy empty animation immediately */
 			g_object_unref(self);
 		}
 }
+
+/**
+ * xfdashboard_animation_ensure_complete:
+ * @self: A #XfdashboardAnimation
+ *
+ * Ensures that the animation at @self has reached the end
+ * of its timeline but will not destroy the animation. Its
+ * purpose is mainly to ensure the animation has completed
+ * before it gets destroyed by other parts of the application.
+ */
+void xfdashboard_animation_ensure_complete(XfdashboardAnimation *self)
+{
+	XfdashboardAnimationPrivate		*priv;
+	GSList							*iter;
+	XfdashboardAnimationEntry		*entry;
+	guint							duration;
+
+	g_return_if_fail(XFDASHBOARD_IS_ANIMATION(self));
+
+	priv=self->priv;
+
+	for(iter=priv->entries; iter; iter=g_slist_next(iter))
+	{
+		/* Get entry */
+		entry=(XfdashboardAnimationEntry*)iter->data;
+		if(!entry) continue;
+
+		/* Advance timeline to last frame */
+		duration=clutter_timeline_get_duration(CLUTTER_TIMELINE(entry->transition));
+		clutter_timeline_advance(CLUTTER_TIMELINE(entry->transition), duration);
+		g_signal_emit_by_name(entry->transition, "new-frame", 0, clutter_timeline_get_elapsed_time(CLUTTER_TIMELINE(entry->transition)));
+	}
+}
diff --git a/libxfdashboard/animation.h b/libxfdashboard/animation.h
index 9380e00..6f5b1a0 100644
--- a/libxfdashboard/animation.h
+++ b/libxfdashboard/animation.h
@@ -75,8 +75,7 @@ struct _XfdashboardAnimationClass
 	/*< public >*/
 	/* Virtual functions */
 	void (*add_animation)(XfdashboardAnimation *self, ClutterActor *inActor, ClutterTransition *inTransition);
-	void (*started)(XfdashboardAnimation *self);
-	void (*stopped)(XfdashboardAnimation *self);
+	void (*animation_done)(XfdashboardAnimation *self);
 };
 
 /* Public API */
@@ -86,19 +85,11 @@ XfdashboardAnimation* xfdashboard_animation_new(XfdashboardActor *inSender, cons
 
 const gchar* xfdashboard_animation_get_id(XfdashboardAnimation *self);
 
-/**
- * XfdashboardAnimationDoneCallback:
- * @inAnimation: The animation which completed
- * @inUserData: Data passed to the function, set with xfdashboard_animation_run()
- *
- * A callback called when animation, started by xfdashboard_animation_run(),
- * has completed and will be destroyed.
- */
-typedef void (*XfdashboardAnimationDoneCallback)(XfdashboardAnimation *inAnimation, gpointer inUserData);
+gboolean xfdashboard_animation_is_empty(XfdashboardAnimation *self);
+
+void xfdashboard_animation_run(XfdashboardAnimation *self);
 
-void xfdashboard_animation_run(XfdashboardAnimation *self,
-								XfdashboardAnimationDoneCallback inCallback,
-								gpointer inUserData);
+void xfdashboard_animation_ensure_complete(XfdashboardAnimation *self);
 
 G_END_DECLS
 
diff --git a/libxfdashboard/collapse-box.c b/libxfdashboard/collapse-box.c
index 3c1aa90..774e643 100644
--- a/libxfdashboard/collapse-box.c
+++ b/libxfdashboard/collapse-box.c
@@ -724,7 +724,8 @@ void xfdashboard_collapse_box_set_collapsed(XfdashboardCollapseBox *self, gboole
 		g_signal_emit(self, XfdashboardCollapseBoxSignals[SIGNAL_COLLAPSED_CHANGED], 0, priv->isCollapsed);
 
 		/* Start animation */
-		xfdashboard_animation_run(priv->expandCollapseAnimation, _xfdashboard_collapse_box_animation_done, self);
+		g_signal_connect(priv->expandCollapseAnimation, "animation-done", G_CALLBACK(_xfdashboard_collapse_box_animation_done), self);
+		xfdashboard_animation_run(priv->expandCollapseAnimation);
 	}
 }
 
diff --git a/libxfdashboard/theme-animation.c b/libxfdashboard/theme-animation.c
index 01d1bd4..67cf896 100644
--- a/libxfdashboard/theme-animation.c
+++ b/libxfdashboard/theme-animation.c
@@ -1689,6 +1689,7 @@ XfdashboardAnimation* xfdashboard_theme_animation_create(XfdashboardThemeAnimati
 	GSList													*iterTargets;
 	gint													counterTargets;
 	gboolean												animationEnabled;
+	GHashTable												*animationActorMap;
 #ifdef DEBUG
 	gboolean												doDebug=TRUE;
 #endif
@@ -1698,6 +1699,7 @@ XfdashboardAnimation* xfdashboard_theme_animation_create(XfdashboardThemeAnimati
 	g_return_val_if_fail(inSignal && *inSignal, NULL);
 
 	animation=NULL;
+	animationActorMap=NULL;
 
 	/* Create empty animation */
 	animation=g_object_new(XFDASHBOARD_TYPE_ANIMATION,
@@ -1768,6 +1770,9 @@ XfdashboardAnimation* xfdashboard_theme_animation_create(XfdashboardThemeAnimati
 						inSignal,
 						g_slist_length(spec->targets));
 
+	/* Create actor-animation-list-mapping via a hash-table */
+	animationActorMap=g_hash_table_new(g_direct_hash, g_direct_equal);
+
 	/* Iterate through animation targets of animation specification and create
 	 * property transition for each target and property found.
 	 */
@@ -1802,43 +1807,12 @@ XfdashboardAnimation* xfdashboard_theme_animation_create(XfdashboardThemeAnimati
 		{
 			GSList											*iterProperties;
 			ClutterActor									*actor;
-			ClutterTransition								*transitionGroup;
 			int												counterProperties;
 
 			/* Get actor */
 			actor=(ClutterActor*)iterActors->data;
 			if(!actor) continue;
 
-			/* Create transition group to collect property transitions at */
-			transitionGroup=xfdashboard_transition_group_new();
-			if(!transitionGroup)
-			{
-				g_critical(_("Cannot allocate memory for transition group of animation specification '%s'"),
-							spec->id);
-				
-				/* Release allocated resources */
-				g_slist_free(actors);
-				g_object_unref(animation);
-
-				return(NULL);
-			}
-
-			/* Clone timeline configuration from animation target */
-			clutter_timeline_set_duration(CLUTTER_TIMELINE(transitionGroup), clutter_timeline_get_duration(targets->timeline));
-			clutter_timeline_set_delay(CLUTTER_TIMELINE(transitionGroup), clutter_timeline_get_delay(targets->timeline));
-			clutter_timeline_set_progress_mode(CLUTTER_TIMELINE(transitionGroup), clutter_timeline_get_progress_mode(targets->timeline));
-			clutter_timeline_set_repeat_count(CLUTTER_TIMELINE(transitionGroup), clutter_timeline_get_repeat_count(targets->timeline));
-
-			XFDASHBOARD_DEBUG(self, ANIMATION,
-								"Created transition group at %p for %d properties for target #%d and actor #%d (%s@%p) of animation specification '%s'",
-								transitionGroup,
-								g_slist_length(targets->properties),
-								counterTargets,
-								counterActors,
-								G_OBJECT_TYPE_NAME(actor),
-								actor,
-								spec->id);
-
 			/* Iterate through properties and create a property transition
 			 * with cloned timeline from animation target. Determine "from"
 			 * value if missing in animation targets property specification
@@ -1993,6 +1967,7 @@ XfdashboardAnimation* xfdashboard_theme_animation_create(XfdashboardThemeAnimati
 				if(G_VALUE_TYPE(&fromValue)!=G_TYPE_INVALID)
 				{
 					ClutterTransition						*propertyTransition;
+					GSList									*animationList;
 
 					/* Create property transition */
 					propertyTransition=clutter_property_transition_new(propertyTargetSpec->name);
@@ -2010,6 +1985,12 @@ XfdashboardAnimation* xfdashboard_theme_animation_create(XfdashboardThemeAnimati
 						continue;
 					}
 
+					/* Clone timeline configuration from animation target */
+					clutter_timeline_set_duration(CLUTTER_TIMELINE(propertyTransition), clutter_timeline_get_duration(targets->timeline));
+					clutter_timeline_set_delay(CLUTTER_TIMELINE(propertyTransition), clutter_timeline_get_delay(targets->timeline));
+					clutter_timeline_set_progress_mode(CLUTTER_TIMELINE(propertyTransition), clutter_timeline_get_progress_mode(targets->timeline));
+					clutter_timeline_set_repeat_count(CLUTTER_TIMELINE(propertyTransition), clutter_timeline_get_repeat_count(targets->timeline));
+
 					/* Set "from" value */
 					clutter_transition_set_from_value(propertyTransition, &fromValue);
 
@@ -2019,11 +2000,11 @@ XfdashboardAnimation* xfdashboard_theme_animation_create(XfdashboardThemeAnimati
 						clutter_transition_set_to_value(propertyTransition, &toValue);
 					}
 
-					/* Add property transition to transition group */
-					xfdashboard_transition_group_add_transition(XFDASHBOARD_TRANSITION_GROUP(transitionGroup), propertyTransition);
+					/* Add animation to list of animations of target actor */
+					animationList=g_hash_table_lookup(animationActorMap, actor);
+					animationList=g_slist_prepend(animationList, propertyTransition);
+					g_hash_table_insert(animationActorMap, actor, animationList);
 
-					/* Release allocated resources */
-					g_object_unref(propertyTransition);
 					XFDASHBOARD_DEBUG(self, ANIMATION,
 										"Created transition for property '%s' at target #%d and actor #%d (%s@%p) of animation specification '%s'",
 										propertyTargetSpec->name,
@@ -2038,21 +2019,137 @@ XfdashboardAnimation* xfdashboard_theme_animation_create(XfdashboardThemeAnimati
 				g_value_unset(&fromValue);
 				g_value_unset(&toValue);
 			}
+		}
+
+		/* Release allocated resources */
+		g_slist_free(actors);
+	}
+
+	/* Now iterate through actor-animation-list-mapping, create a transition group for each actor
+	 * and add its animation to this newly created group.
+	 */
+	if(animationActorMap)
+	{
+		GHashTableIter										hashIter;
+		ClutterActor										*hashIterActor;
+		GSList												*hashIterList;
+
+		g_hash_table_iter_init(&hashIter, animationActorMap);
+		while(g_hash_table_iter_next(&hashIter, (gpointer*)&hashIterActor, (gpointer*)&hashIterList))
+		{
+			ClutterTransition								*transitionGroup;
+			GSList											*listIter;
+			guint											groupDuration;
+			gint											groupLoop;
+
+			/* Skip empty but warn */
+			if(!hashIterList)
+			{
+				g_critical(_("Empty animation list when creating animation for animation specification '%s'"),
+							spec->id);
+				continue;
+			}
+
+			/* Create transition group to collect property transitions at */
+			transitionGroup=xfdashboard_transition_group_new();
+			if(!transitionGroup)
+			{
+				g_critical(_("Cannot allocate memory for transition group of animation specification '%s'"),
+							spec->id);
+				
+				/* Release allocated resources */
+				g_hash_table_foreach(animationActorMap, g_slist_free, NULL);
+				g_hash_table_destroy(animationActorMap);
+				g_object_unref(animation);
+				if(spec) _xfdashboard_theme_animation_spec_unref(spec);
+
+				return(NULL);
+			}
+
+			XFDASHBOARD_DEBUG(self, ANIMATION,
+								"Created transition group at %p for %d properties for actor %s@%p of animation specification '%s'",
+								transitionGroup,
+								g_slist_length(hashIterList),
+								G_OBJECT_TYPE_NAME(hashIterActor),
+								hashIterActor,
+								spec->id);
+
+			/* Add animations to transition group */
+			groupDuration=0;
+			groupLoop=0;
+			for(listIter=hashIterList; listIter; listIter=g_slist_next(listIter))
+			{
+				ClutterTransition							*transition;
+				gint										transitionLoop;
+				guint										transitionDuration;
+
+				/* Get transition to add */
+				transition=(ClutterTransition*)listIter->data;
+				if(!transition) continue;
+
+				/* Adjust timeline values for transition group to play animation fully */
+				transitionDuration=clutter_timeline_get_delay(CLUTTER_TIMELINE(transition))+clutter_timeline_get_duration(CLUTTER_TIMELINE(transition));
+				if(transitionDuration>groupDuration) groupDuration=transitionDuration;
+
+				if(groupLoop>=0)
+				{
+					transitionLoop=clutter_timeline_get_repeat_count(CLUTTER_TIMELINE(transition));
+					if(transitionLoop>groupLoop) groupLoop=transitionLoop;
+				}
+
+				/* Add property transition to transition group */
+				xfdashboard_transition_group_add_transition(XFDASHBOARD_TRANSITION_GROUP(transitionGroup), transition);
+
+				XFDASHBOARD_DEBUG(self, ANIMATION,
+									"Added transition %s@%p (duration %u ms in %d loops) for actor %s@%p of animation specification '%s' to group %s@%p",
+									G_OBJECT_TYPE_NAME(transition),
+									transition,
+									transitionDuration,
+									transitionLoop,
+									G_OBJECT_TYPE_NAME(hashIterActor),
+									hashIterActor,
+									spec->id,
+									G_OBJECT_TYPE_NAME(transitionGroup),
+									transitionGroup);
+			}
+
+			/* Set up timeline configuration for transition group of target actor */
+			clutter_timeline_set_duration(CLUTTER_TIMELINE(transitionGroup), groupDuration);
+			clutter_timeline_set_delay(CLUTTER_TIMELINE(transitionGroup), 0);
+			clutter_timeline_set_progress_mode(CLUTTER_TIMELINE(transitionGroup), CLUTTER_LINEAR);
+			clutter_timeline_set_repeat_count(CLUTTER_TIMELINE(transitionGroup), groupLoop);
+
+			XFDASHBOARD_DEBUG(self, ANIMATION,
+								"Set up timeline of group %s@%p with duration of %u ms and %d loops for actor %s@%p",
+								G_OBJECT_TYPE_NAME(transitionGroup),
+								transitionGroup,
+								groupDuration,
+								groupLoop,
+								G_OBJECT_TYPE_NAME(hashIterActor),
+								hashIterActor);
 
 			/* Add transition group with collected property transitions
 			 * to actor.
 			 */
 			if(animationClass->add_animation)
 			{
-				animationClass->add_animation(animation, actor, transitionGroup);
+				animationClass->add_animation(animation, hashIterActor, transitionGroup);
+				XFDASHBOARD_DEBUG(self, ANIMATION,
+									"Added transition group %s@%p to actor %s@%p of animation specification '%s'",
+									G_OBJECT_TYPE_NAME(transitionGroup),
+									transitionGroup,
+									G_OBJECT_TYPE_NAME(hashIterActor),
+									hashIterActor,
+									spec->id);
 			}
 
 			/* Release allocated resources */
 			g_object_unref(transitionGroup);
+			g_slist_free_full(hashIterList, g_object_unref);
 		}
 
-		/* Release allocated resources */
-		g_slist_free(actors);
+		/* Destroy hash table */
+		g_hash_table_destroy(animationActorMap);
 	}
 
 	/* Release allocated resources */
diff --git a/libxfdashboard/transition-group.c b/libxfdashboard/transition-group.c
index 1723867..d4fe88f 100644
--- a/libxfdashboard/transition-group.c
+++ b/libxfdashboard/transition-group.c
@@ -81,7 +81,6 @@ struct _XfdashboardTransitionGroupPrivate
 
 	/* Instance related */
 	GHashTable							*transitions;
-	GList								*bindings;
 	XfdashboardTransitionActorSetFlags	flags;
 };
 
@@ -103,46 +102,6 @@ enum
 static GParamSpec* XfdashboardTransitionGroupProperties[PROP_LAST]={ 0, };
 
 
-/* IMPLEMENTATION: Private variables and methods */
-
-typedef struct _XfdashboardTransitionGroupBindingEntry		XfdashboardTransitionGroupBindingEntry;
-struct _XfdashboardTransitionGroupBindingEntry
-{
-	XfdashboardTransitionGroup	*self;
-	GBinding					*binding;
-};
-
-/* Property names to bind when transition is added */
-static const gchar *_xfdashboard_transition_group_bindable_properties[]=
-{
-	"auto-reverse",
-	"delay",
-	"duration",
-	"loop",
-	"progress-mode",
-	"repeat-count",
-	NULL
-};
-
-/* A binding entry is notified about its destruction */
-static void _xfdashboard_transition_group_binding_notified(gpointer inData)
-{
-	XfdashboardTransitionGroup					*self;
-	XfdashboardTransitionGroupPrivate			*priv;
-	XfdashboardTransitionGroupBindingEntry		*entry;
-
-	entry=(XfdashboardTransitionGroupBindingEntry*)inData;
-	self=entry->self;
-	priv=self->priv;
-
-	/* Remove binding from list */
-	priv->bindings=g_list_remove(priv->bindings, entry->binding);
-
-	/* Release allocated resources of entry */
-	g_free(inData);
-}
-
-
 /* IMPLEMENTATION: ClutterTimeline */
 
 /* Time at transition has elapsed, so advance all transitions as well */
@@ -153,19 +112,125 @@ static void _xfdashboard_transition_group_timeline_new_frame(ClutterTimeline *in
 	XfdashboardTransitionGroupPrivate	*priv;
 	GHashTableIter						iter;
 	gpointer							element;
+	gint								currentLoop;
+#ifdef DEBUG
+	gboolean							doDebug=TRUE;
+#endif
 
 	g_return_if_fail(XFDASHBOARD_IS_TRANSITION_GROUP(inTimeline));
 
 	self=XFDASHBOARD_TRANSITION_GROUP(inTimeline);
 	priv=self->priv;
 
+	/* Get current number of loop repeated */
+	currentLoop=clutter_timeline_get_repeat_count(inTimeline);
+
 	/* Iterate through transitions and advance their timeline */
+#ifdef DEBUG
+	if(doDebug)
+	{
+		ClutterAnimatable				*animatable;
+
+		animatable=clutter_transition_get_animatable(CLUTTER_TRANSITION(self));
+		XFDASHBOARD_DEBUG(self, ANIMATION,
+							"Processing 'new-frame' signal for %s@%p with state %s and timeline %u ms/%u ms for animatable actor %s@%p",
+							G_OBJECT_TYPE_NAME(self),
+							self,
+							clutter_timeline_is_playing(inTimeline) ? "PLAYING" : "STOPPED",
+							clutter_timeline_get_elapsed_time(inTimeline),
+							clutter_timeline_get_duration(inTimeline),
+							G_OBJECT_TYPE_NAME(animatable),
+							animatable);
+	}
+#endif
+
 	g_hash_table_iter_init(&iter, priv->transitions);
 	while(g_hash_table_iter_next(&iter, &element, NULL))
 	{
-		clutter_timeline_advance(CLUTTER_TIMELINE(element), clutter_timeline_get_elapsed_time(inTimeline));
-		g_signal_emit_by_name(element, "new-frame", 0, clutter_timeline_get_elapsed_time(inTimeline));
+		guint							maxDuration;
+		gint							maxLoop;
+
+		maxDuration=clutter_timeline_get_delay(CLUTTER_TIMELINE(element))+clutter_timeline_get_duration(CLUTTER_TIMELINE(element));
+		maxLoop=clutter_timeline_get_repeat_count(CLUTTER_TIMELINE(element));
+		if(((guint)inElapsed)<=maxDuration &&
+			(maxLoop<0 || currentLoop<=maxLoop))
+		{
+			clutter_timeline_advance(CLUTTER_TIMELINE(element), clutter_timeline_get_elapsed_time(inTimeline));
+			g_signal_emit_by_name(element, "new-frame", 0, clutter_timeline_get_elapsed_time(inTimeline));
+#ifdef DEBUG
+			if(doDebug)
+			{
+				const gchar				*propertyName=clutter_property_transition_get_property_name(CLUTTER_PROPERTY_TRANSITION(element));
+				ClutterInterval			*propertyInterval=clutter_transition_get_interval(CLUTTER_TRANSITION(element));
+				GValue					*fromValue=clutter_interval_peek_final_value(propertyInterval);
+				gchar					*fromValueString;
+				GValue					*toValue=clutter_interval_peek_final_value(propertyInterval);
+				gchar					*toValueString;
+				GValue					currentValue=G_VALUE_INIT;
+				gchar					*currentValueString;
+				ClutterAnimatable		*animatable;
+
+				animatable=clutter_transition_get_animatable(CLUTTER_TRANSITION(element));
+
+				g_value_init(&currentValue, clutter_interval_get_value_type(propertyInterval));
+				g_object_get_property(G_OBJECT(animatable), propertyName, &currentValue);
+
+				fromValueString=g_strdup_value_contents(fromValue);
+				toValueString=g_strdup_value_contents(toValue);
+				currentValueString=g_strdup_value_contents(&currentValue);
+
+				XFDASHBOARD_DEBUG(self, ANIMATION,
+									"Processing transition %s@%p with timeline %u ms/%u ms and loop of %d/%d, so set property '%s' to %s (from=%s, to=%s)",
+									G_OBJECT_TYPE_NAME(element),
+									element,
+									clutter_timeline_get_elapsed_time(CLUTTER_TIMELINE(element)),
+									maxDuration,
+									currentLoop,
+									maxLoop,
+									propertyName,
+									currentValueString,
+									fromValueString,
+									toValueString);
+
+				g_free(currentValueString);
+				g_free(toValueString);
+				g_free(fromValueString);
+				g_value_unset(&currentValue);
+			}
+#endif
+		}
+#ifdef DEBUG
+			else
+			{
+				if(doDebug)
+				{
+					XFDASHBOARD_DEBUG(self, ANIMATION,
+										"Skipping transition %s@%p because elapsed time of %u ms and loop %d is behind its duration of %u ms and max loop of %d",
+										G_OBJECT_TYPE_NAME(element),
+										element,
+										inElapsed,
+										currentLoop,
+										maxDuration,
+										maxLoop);
+				}
+			}
+#endif
+	}
+
+#ifdef DEBUG
+	if(doDebug)
+	{
+		ClutterAnimatable				*animatable;
+
+		animatable=clutter_transition_get_animatable(CLUTTER_TRANSITION(self));
+		XFDASHBOARD_DEBUG(self, ANIMATION,
+							"Processed 'new-frame' signal for %s@%p and animatable actor %s@%p",
+							G_OBJECT_TYPE_NAME(self),
+							self,
+							G_OBJECT_TYPE_NAME(animatable),
+							animatable);
 	}
+#endif
 }
 
 /* This transition group was started */
@@ -340,6 +405,20 @@ static void _xfdashboard_transition_group_transition_detached(ClutterTransition
 
 /* IMPLEMENTATION: GObject */
 
+/* Dispose this object */
+static void _xfdashboard_transition_group_dispose(GObject *inObject)
+{
+	XfdashboardTransitionGroup			*self=XFDASHBOARD_TRANSITION_GROUP(inObject);
+	ClutterAnimatable					*animatable;
+
+	/* Restore "*-set" properties */
+	animatable=clutter_transition_get_animatable(CLUTTER_TRANSITION(self));
+	if(animatable) _xfdashboard_transition_group_transition_detached(CLUTTER_TRANSITION(self), animatable);
+
+	/* Call parent's class dispose method */
+	G_OBJECT_CLASS(xfdashboard_transition_group_parent_class)->dispose(inObject);
+}
+
 /* Finalize this object */
 static void _xfdashboard_transition_group_finalize(GObject *inObject)
 {
@@ -347,24 +426,6 @@ static void _xfdashboard_transition_group_finalize(GObject *inObject)
 	XfdashboardTransitionGroupPrivate	*priv=self->priv;
 
 	/* Release our allocated variables */
-	if(priv->bindings)
-	{
-		GList							*iter;
-		GBinding						*binding;
-
-		for(iter=priv->bindings; iter; iter=g_list_next(iter))
-		{
-			/* Release valid bindings */
-			binding=(GBinding*)iter->data;
-			if(!binding) continue;
-
-			/* Unbind binding and release object */
-			g_object_unref(binding);
-		}
-		g_list_free(priv->bindings);
-		priv->bindings=NULL;
-	}
-
 	if(priv->transitions)
 	{
 		g_hash_table_unref(priv->transitions);
@@ -429,6 +490,7 @@ void xfdashboard_transition_group_class_init(XfdashboardTransitionGroupClass *kl
 	/* Override functions */
 	gobjectClass->set_property=_xfdashboard_transition_group_set_property;
 	gobjectClass->get_property=_xfdashboard_transition_group_get_property;
+	gobjectClass->dispose=_xfdashboard_transition_group_dispose;
 	gobjectClass->finalize=_xfdashboard_transition_group_finalize;
 
 	timelineClass->started=_xfdashboard_transition_group_timeline_started;
@@ -462,7 +524,6 @@ void xfdashboard_transition_group_init(XfdashboardTransitionGroup *self)
 											NULL,
 											(GDestroyNotify)g_object_unref,
 											NULL);
-	priv->bindings=NULL;
 }
 
 
@@ -502,43 +563,7 @@ void xfdashboard_transition_group_add_transition(XfdashboardTransitionGroup *sel
 	priv=self->priv;
 
 	/* Add and set up transition */
-	if(g_hash_table_add(priv->transitions, g_object_ref(inTransition)))
-	{
-		const gchar								**iter;
-		GBinding								*binding;
-		XfdashboardTransitionGroupBindingEntry	*entry;
-
-		/* Clone timeline configuration to transition and bind properties
-		 * to update them at added transition when this timeline changes
-		 * as this transition is new to this group.
-		 */
-		for(iter=_xfdashboard_transition_group_bindable_properties; *iter; iter++)
-		{
-			entry=g_new0(XfdashboardTransitionGroupBindingEntry, 1);
-			binding=g_object_bind_property_full(self, *iter,
-												inTransition, *iter,
-												G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE,
-												NULL,
-												NULL,
-												entry,
-												_xfdashboard_transition_group_binding_notified);
-
-			entry->self=self;
-			entry->binding=binding;
-
-			priv->bindings=g_list_prepend(priv->bindings, binding);
-
-			XFDASHBOARD_DEBUG(self, ANIMATION,
-								"Bind property '%s' from transition group %s@%p to actor %s@%p via %s@%p",
-								*iter,
-								G_OBJECT_TYPE_NAME(self),
-								self,
-								G_OBJECT_TYPE_NAME(inTransition),
-								inTransition,
-								G_OBJECT_TYPE_NAME(binding),
-								binding);
-		}
-	}
+	g_hash_table_add(priv->transitions, g_object_ref(inTransition));
 }
 
 /**
@@ -561,57 +586,6 @@ void xfdashboard_transition_group_remove_transition(XfdashboardTransitionGroup *
 
 	priv=self->priv;
 
-	/* First remove bindings to transition as long as a reference is held */
-	if(priv->bindings)
-	{
-		GList							*iter;
-		GList							*nextIter;
-
-		iter=priv->bindings;
-		while(iter)
-		{
-			GBinding					*binding;
-
-			/* Get next element to iterate */
-			nextIter=g_list_next(iter);
-
-			/* Get currently iterated binding */
-			binding=(GBinding*)(iter->data);
-			if(!binding)
-			{
-				iter=nextIter;
-				continue;
-			}
-
-			/* If binding's target refers to transition removed,
-			 * unbind it.
-			 */
-			if(g_binding_get_target(binding)==G_OBJECT(inTransition))
-			{
-				/* Remove binding from list */
-				priv->bindings=g_list_remove_link(priv->bindings, iter);
-
-				/* Unbind property binding */
-				XFDASHBOARD_DEBUG(self, ANIMATION,
-									"Unbinding property '%s' from transition group %s@%p at actor %s@%p via %s@%p",
-									g_binding_get_source_property(binding),
-									G_OBJECT_TYPE_NAME(self),
-									self,
-									G_OBJECT_TYPE_NAME(inTransition),
-									inTransition,
-									G_OBJECT_TYPE_NAME(binding),
-									binding);
-				g_binding_unbind(binding);
-
-				/* Free list element currently iterated */
-				g_list_free(iter);
-			}
-
-			/* Move to next element */
-			iter=nextIter;
-		}
-	}
-
 	/* Remove transition */
 	g_hash_table_remove(priv->transitions, inTransition);
 }
@@ -633,13 +607,6 @@ void xfdashboard_transition_group_remove_all(XfdashboardTransitionGroup *self)
 
 	priv=self->priv;
 
-	/* First remove all binding as long as a reference to transition is held */
-	if(priv->bindings)
-	{
-		g_list_free_full(priv->bindings, (GDestroyNotify)g_binding_unbind);
-		priv->bindings=NULL;
-	}
-
 	/* Remove all transitions */
 	g_hash_table_remove_all(priv->transitions);
 }
diff --git a/libxfdashboard/window-tracker.c b/libxfdashboard/window-tracker.c
index 21b0717..0f6c762 100644
--- a/libxfdashboard/window-tracker.c
+++ b/libxfdashboard/window-tracker.c
@@ -44,7 +44,6 @@ G_DEFINE_INTERFACE(XfdashboardWindowTracker,
 
 
 /* Signals */
-
 enum
 {
 	SIGNAL_WINDOW_STACKING_CHANGED,
@@ -78,6 +77,7 @@ enum
 
 static guint XfdashboardWindowTrackerSignals[SIGNAL_LAST]={ 0, };
 
+
 /* IMPLEMENTATION: Private variables and methods */
 #define XFDASHBOARD_WINDOWS_TRACKER_WARN_NOT_IMPLEMENTED(self, vfunc)  \
 	g_warning(_("Object of type %s does not implement required virtual function XfdashboardWindowTracker::%s"),\

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the Xfce4-commits mailing list