diff --git a/libxapp/xapp-status-icon.c b/libxapp/xapp-status-icon.c index 6450862..64f03db 100644 --- a/libxapp/xapp-status-icon.c +++ b/libxapp/xapp-status-icon.c @@ -120,6 +120,45 @@ static void use_gtk_status_icon (XAppStatusIcon *self); static void remove_icon_path_from_bus (XAppStatusIcon *self); static void hide_and_defer_unref_status_icon (XAppStatusIcon *self, GtkStatusIcon *status_icon); +/* Async callbacks must not keep the icon alive: the SnItem owning it may be + * removed while the call is in flight. A weak ref lets the callback detect + * that case instead of dereferencing freed memory. */ +typedef struct +{ + GWeakRef icon; +} XAppStatusIconAsyncRef; + +static XAppStatusIconAsyncRef * +xapp_status_icon_async_ref_new (XAppStatusIcon *icon) +{ + XAppStatusIconAsyncRef *async_ref = g_new0 (XAppStatusIconAsyncRef, 1); + + g_weak_ref_init (&async_ref->icon, G_OBJECT (icon)); + + return async_ref; +} + +static XAppStatusIcon * +xapp_status_icon_async_ref_get (XAppStatusIconAsyncRef *async_ref) +{ + XAppStatusIcon *icon = g_weak_ref_get (&async_ref->icon); + + if (icon == NULL) + { + g_weak_ref_clear (&async_ref->icon); + g_free (async_ref); + } + + return icon; +} + +static void +xapp_status_icon_async_ref_free (XAppStatusIconAsyncRef *async_ref) +{ + g_weak_ref_clear (&async_ref->icon); + g_free (async_ref); +} + static void cancellable_reset (XAppStatusIcon *self) { @@ -1326,7 +1365,8 @@ on_list_names_completed (GObject *source, GAsyncResult *res, gpointer user_data) { - XAppStatusIcon *self = XAPP_STATUS_ICON(user_data); + XAppStatusIconAsyncRef *async_ref = user_data; + XAppStatusIcon *self; GVariant *result; GVariantIter *iter; gchar *str; @@ -1338,6 +1378,18 @@ on_list_names_completed (GObject *source, result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), res, &error); + self = xapp_status_icon_async_ref_get (async_ref); + + if (self == NULL) + { + if (error != NULL) + g_error_free (error); + + if (result != NULL) + g_variant_unref (result); + + return; + } if (error != NULL) { @@ -1352,6 +1404,8 @@ on_list_names_completed (GObject *source, } g_error_free (error); + g_object_unref (self); + xapp_status_icon_async_ref_free (async_ref); return; } @@ -1380,6 +1434,8 @@ on_list_names_completed (GObject *source, else { connect_with_status_applet (self); + g_object_unref (self); + xapp_status_icon_async_ref_free (async_ref); return; } @@ -1388,6 +1444,9 @@ on_list_names_completed (GObject *source, { use_gtk_status_icon (self); } + + g_object_unref (self); + xapp_status_icon_async_ref_free (async_ref); } static void @@ -1409,7 +1468,7 @@ look_for_status_applet (XAppStatusIcon *self) 3000, /* 3 secs */ self->priv->cancellable, on_list_names_completed, - self); + xapp_status_icon_async_ref_new (self)); } static void