From 436ec5bd00a6e0095dc1fdb2a820fe020808d26b Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Wed, 22 Apr 2020 15:24:32 +0200 Subject: [PATCH] EActivityBar: Unset timeout_id without recursive call to g_source_remove() That could happen with e_activity_bar_set_activity() being called when the timeout_id is set and when the activity in question had the last reference help by the timeout source, because it caused a repeated call of e_activity_base_set_activity() in the destroy callback on the activity. --- src/e-util/e-activity-bar.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/e-util/e-activity-bar.c b/src/e-util/e-activity-bar.c index e3cf5c9134..2cd53e5dfc 100644 --- a/src/e-util/e-activity-bar.c +++ b/src/e-util/e-activity-bar.c @@ -61,6 +61,25 @@ typedef struct _EActivityBarTimeoutData { EActivity *activity; } EActivityBarTimeoutData; +/* This is needed, because the scheduled timeout can hold the last + reference to the 'activity', which means removing the source will + free it, which in turn calls e_activity_bar_set_activity() with NULL, + which would call g_source_remove() again, with the same timeout id. +*/ +static void +activity_bar_unset_timeout_id (EActivityBar *bar) +{ + guint timeout_id; + + g_return_if_fail (E_IS_ACTIVITY_BAR (bar)); + + timeout_id = bar->priv->timeout_id; + bar->priv->timeout_id = 0; + + if (timeout_id) + g_source_remove (timeout_id); +} + static void activity_bar_timeout_data_free (gpointer ptr) { @@ -101,8 +120,7 @@ activity_bar_feedback (EActivityBar *bar) if (state != E_ACTIVITY_CANCELLED && state != E_ACTIVITY_COMPLETED) return; - if (bar->priv->timeout_id > 0) - g_source_remove (bar->priv->timeout_id); + activity_bar_unset_timeout_id (bar); data = g_slice_new0 (EActivityBarTimeoutData); @@ -267,12 +285,7 @@ activity_bar_dispose (GObject *object) priv = E_ACTIVITY_BAR_GET_PRIVATE (object); - if (priv->timeout_id > 0) { - guint timeout_id = priv->timeout_id; - - priv->timeout_id = 0; - g_source_remove (timeout_id); - } + activity_bar_unset_timeout_id (E_ACTIVITY_BAR (object)); if (priv->activity != NULL) { g_signal_handlers_disconnect_matched ( @@ -388,10 +401,7 @@ e_activity_bar_set_activity (EActivityBar *bar, if (activity != NULL) g_return_if_fail (E_IS_ACTIVITY (activity)); - if (bar->priv->timeout_id > 0) { - g_source_remove (bar->priv->timeout_id); - bar->priv->timeout_id = 0; - } + activity_bar_unset_timeout_id (bar); if (bar->priv->activity != NULL) { g_signal_handlers_disconnect_matched (