object: use weakref when advancing current transition
Fixes reference count leak when activating an object and transition fails
This commit is contained in:
@@ -143,6 +143,7 @@ struct _WpObjectPrivate
|
|||||||
WpObjectFeatures ft_active;
|
WpObjectFeatures ft_active;
|
||||||
GQueue *transitions; // element-type: WpFeatureActivationTransition*
|
GQueue *transitions; // element-type: WpFeatureActivationTransition*
|
||||||
GSource *idle_advnc_source;
|
GSource *idle_advnc_source;
|
||||||
|
GWeakRef ongoing_transition;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -161,6 +162,7 @@ wp_object_init (WpObject * self)
|
|||||||
|
|
||||||
g_weak_ref_init (&priv->core, NULL);
|
g_weak_ref_init (&priv->core, NULL);
|
||||||
priv->transitions = g_queue_new ();
|
priv->transitions = g_queue_new ();
|
||||||
|
g_weak_ref_init (&priv->ongoing_transition, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -189,6 +191,7 @@ wp_object_finalize (GObject * object)
|
|||||||
g_warn_if_fail (g_queue_is_empty (priv->transitions));
|
g_warn_if_fail (g_queue_is_empty (priv->transitions));
|
||||||
g_clear_pointer (&priv->transitions, g_queue_free);
|
g_clear_pointer (&priv->transitions, g_queue_free);
|
||||||
g_clear_pointer (&priv->idle_advnc_source, g_source_unref);
|
g_clear_pointer (&priv->idle_advnc_source, g_source_unref);
|
||||||
|
g_weak_ref_clear (&priv->ongoing_transition);
|
||||||
g_weak_ref_clear (&priv->core);
|
g_weak_ref_clear (&priv->core);
|
||||||
|
|
||||||
/* everything must have been deactivated in dispose() */
|
/* everything must have been deactivated in dispose() */
|
||||||
@@ -309,17 +312,24 @@ static gboolean
|
|||||||
wp_object_advance_transitions (WpObject * self)
|
wp_object_advance_transitions (WpObject * self)
|
||||||
{
|
{
|
||||||
WpObjectPrivate *priv = wp_object_get_instance_private (self);
|
WpObjectPrivate *priv = wp_object_get_instance_private (self);
|
||||||
WpTransition *t;
|
|
||||||
|
|
||||||
/* clear before advancing; a transition may need to schedule
|
/* clear before advancing; a transition may need to schedule
|
||||||
a new call to wp_object_advance_transitions() */
|
a new call to wp_object_advance_transitions() */
|
||||||
g_clear_pointer (&priv->idle_advnc_source, g_source_unref);
|
g_clear_pointer (&priv->idle_advnc_source, g_source_unref);
|
||||||
|
|
||||||
while ((t = g_queue_peek_head (priv->transitions))) {
|
while (TRUE) {
|
||||||
wp_transition_advance (t);
|
g_autoptr (WpTransition) t = g_weak_ref_get (&priv->ongoing_transition);
|
||||||
if (!wp_transition_get_completed (t))
|
if (t) {
|
||||||
|
wp_transition_advance (t);
|
||||||
|
if (!wp_transition_get_completed (t))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_queue_is_empty (priv->transitions))
|
||||||
break;
|
break;
|
||||||
g_object_unref (g_queue_pop_head (priv->transitions));
|
|
||||||
|
g_weak_ref_set (&priv->ongoing_transition,
|
||||||
|
g_queue_pop_head (priv->transitions));
|
||||||
}
|
}
|
||||||
|
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
@@ -382,7 +392,7 @@ wp_object_activate_closure (WpObject * self,
|
|||||||
wp_transition_set_source_tag (transition, wp_object_activate);
|
wp_transition_set_source_tag (transition, wp_object_activate);
|
||||||
wp_transition_set_data (transition, GUINT_TO_POINTER (features), NULL);
|
wp_transition_set_data (transition, GUINT_TO_POINTER (features), NULL);
|
||||||
|
|
||||||
g_queue_push_tail (priv->transitions, g_object_ref (transition));
|
g_queue_push_tail (priv->transitions, transition);
|
||||||
|
|
||||||
if (!priv->idle_advnc_source) {
|
if (!priv->idle_advnc_source) {
|
||||||
wp_core_idle_add (core, &priv->idle_advnc_source,
|
wp_core_idle_add (core, &priv->idle_advnc_source,
|
||||||
@@ -454,6 +464,7 @@ wp_object_update_features (WpObject * self, WpObjectFeatures activated,
|
|||||||
|
|
||||||
WpObjectPrivate *priv = wp_object_get_instance_private (self);
|
WpObjectPrivate *priv = wp_object_get_instance_private (self);
|
||||||
guint old_ft = priv->ft_active;
|
guint old_ft = priv->ft_active;
|
||||||
|
g_autoptr (WpTransition) t = NULL;
|
||||||
|
|
||||||
priv->ft_active |= activated;
|
priv->ft_active |= activated;
|
||||||
priv->ft_active &= ~deactivated;
|
priv->ft_active &= ~deactivated;
|
||||||
@@ -464,7 +475,8 @@ wp_object_update_features (WpObject * self, WpObjectFeatures activated,
|
|||||||
g_object_notify (G_OBJECT (self), "active-features");
|
g_object_notify (G_OBJECT (self), "active-features");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_queue_is_empty (priv->transitions) && !priv->idle_advnc_source) {
|
t = g_weak_ref_get (&priv->ongoing_transition);
|
||||||
|
if ((t || !g_queue_is_empty (priv->transitions)) && !priv->idle_advnc_source) {
|
||||||
g_autoptr (WpCore) core = g_weak_ref_get (&priv->core);
|
g_autoptr (WpCore) core = g_weak_ref_get (&priv->core);
|
||||||
g_return_if_fail (core != NULL);
|
g_return_if_fail (core != NULL);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user