From: Matthew Barnes Date: Sat, 9 Feb 2013 21:48:43 +0000 (-0500) Subject: ECalClient: Use g_bus_watch_name_on_connection(). X-Git-Tag: upstream/3.7.91~191 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=071047d9f26fa0a3b9226898fe63910b2501f232;p=platform%2Fupstream%2Fevolution-data-server.git ECalClient: Use g_bus_watch_name_on_connection(). g_bus_watch_name_on_connection() handles "NameOwnerChanged" signals as well as "closed" signals from the GDBusConnection. In the event the bus name vanishes, we schedule an idle callback on the client's GMainContext to emit a "backend-died" signal. Also while we're at it, call the close() method asynchronously from dispose() so we don't block. --- diff --git a/calendar/libecal/e-cal-client.c b/calendar/libecal/e-cal-client.c index 5ba5d81..48e7c30 100644 --- a/calendar/libecal/e-cal-client.c +++ b/calendar/libecal/e-cal-client.c @@ -54,9 +54,9 @@ typedef struct _ConnectClosure ConnectClosure; typedef struct _RunInThreadClosure RunInThreadClosure; struct _ECalClientPrivate { - EDBusCalendar *dbus_proxy; GMainContext *main_context; - guint gone_signal_id; + EDBusCalendar *dbus_proxy; + guint name_watcher_id; ECalClientSourceType source_type; icaltimezone *default_zone; @@ -350,87 +350,46 @@ set_proxy_gone_error (GError **error) } static volatile gint active_cal_clients = 0; -static guint cal_connection_closed_id = 0; +static guint cal_factory_watcher_id = 0; static EDBusCalendarFactory *cal_factory = NULL; static GRecMutex cal_factory_lock; #define LOCK_FACTORY() g_rec_mutex_lock (&cal_factory_lock) #define UNLOCK_FACTORY() g_rec_mutex_unlock (&cal_factory_lock) -static void gdbus_cal_factory_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, gpointer user_data); - static void -gdbus_cal_factory_disconnect (GDBusConnection *connection) +cal_factory_disconnect (void) { LOCK_FACTORY (); - if (!connection && cal_factory) - connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory)); - - if (connection && cal_connection_closed_id) { - g_dbus_connection_signal_unsubscribe (connection, cal_connection_closed_id); - g_signal_handlers_disconnect_by_func (connection, gdbus_cal_factory_closed_cb, NULL); + if (cal_factory_watcher_id > 0) { + g_bus_unwatch_name (cal_factory_watcher_id); + cal_factory_watcher_id = 0; } - if (cal_factory != NULL) - g_object_unref (cal_factory); - - cal_connection_closed_id = 0; - cal_factory = NULL; + g_clear_object (&cal_factory); UNLOCK_FACTORY (); } static void -gdbus_cal_factory_closed_cb (GDBusConnection *connection, - gboolean remote_peer_vanished, - GError *error, - gpointer user_data) -{ - GError *err = NULL; - - LOCK_FACTORY (); - - gdbus_cal_factory_disconnect (connection); - - if (error) - unwrap_dbus_error (g_error_copy (error), &err); - - if (err) { - g_debug ("GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message); - g_error_free (err); - } else if (active_cal_clients > 0) { - g_debug ("GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : ""); - } - - UNLOCK_FACTORY (); -} - -static void -gdbus_cal_factory_connection_gone_cb (GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) +cal_factory_name_vanished_cb (GDBusConnection *connection, + const gchar *name, + gpointer user_data) { - /* signal subscription takes care of correct parameters, - * thus just do what is to be done here */ - gdbus_cal_factory_closed_cb (connection, TRUE, NULL, user_data); + cal_factory_disconnect (); } static gboolean -gdbus_cal_factory_activate (GCancellable *cancellable, - GError **error) +cal_factory_activate (GCancellable *cancellable, + GError **error) { - GDBusConnection *connection; + GDBusProxy *proxy; + gboolean success = TRUE; LOCK_FACTORY (); - if (G_LIKELY (cal_factory != NULL)) { - UNLOCK_FACTORY (); - return TRUE; - } + if (G_LIKELY (cal_factory != NULL)) + goto exit; cal_factory = e_dbus_calendar_factory_proxy_new_for_bus_sync ( G_BUS_TYPE_SESSION, @@ -440,28 +399,24 @@ gdbus_cal_factory_activate (GCancellable *cancellable, cancellable, error); if (cal_factory == NULL) { - UNLOCK_FACTORY (); - return FALSE; + success = FALSE; + goto exit; } - connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory)); - cal_connection_closed_id = g_dbus_connection_signal_subscribe ( - connection, - NULL, /* sender */ - "org.freedesktop.DBus", /* interface */ - "NameOwnerChanged", /* member */ - "/org/freedesktop/DBus", /* object_path */ - "org.gnome.evolution.dataserver.Calendar", /* arg0 */ - G_DBUS_SIGNAL_FLAGS_NONE, - gdbus_cal_factory_connection_gone_cb, NULL, NULL); - - g_signal_connect ( - connection, "closed", - G_CALLBACK (gdbus_cal_factory_closed_cb), NULL); + proxy = G_DBUS_PROXY (cal_factory); + + cal_factory_watcher_id = g_bus_watch_name_on_connection ( + g_dbus_proxy_get_connection (proxy), + g_dbus_proxy_get_name (proxy), + G_BUS_NAME_WATCHER_FLAGS_NONE, + (GBusNameAppearedCallback) NULL, + (GBusNameVanishedCallback) cal_factory_name_vanished_cb, + NULL, (GDestroyNotify) NULL); +exit: UNLOCK_FACTORY (); - return TRUE; + return success; } static gpointer @@ -565,72 +520,16 @@ cal_client_run_in_dbus_thread (GSimpleAsyncResult *simple, g_main_context_unref (main_context); } -static void gdbus_cal_client_disconnect (ECalClient *client); - -/* - * Called when the calendar server dies. - */ -static void -gdbus_cal_client_closed_cb (GDBusConnection *connection, - gboolean remote_peer_vanished, - GError *error, - ECalClient *client) -{ - GError *err = NULL; - - g_assert (E_IS_CAL_CLIENT (client)); - - if (error) - unwrap_dbus_error (g_error_copy (error), &err); - - if (err) { - g_debug (G_STRLOC ": ECalClient GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message); - g_error_free (err); - } else { - g_debug (G_STRLOC ": ECalClient GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : ""); - } - - gdbus_cal_client_disconnect (client); - - e_client_emit_backend_died (E_CLIENT (client)); -} - -static void -gdbus_cal_client_connection_gone_cb (GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) -{ - /* signal subscription takes care of correct parameters, - * thus just do what is to be done here */ - gdbus_cal_client_closed_cb (connection, TRUE, NULL, user_data); -} - -static void -gdbus_cal_client_disconnect (ECalClient *client) +static gboolean +cal_client_emit_backend_died_idle_cb (gpointer user_data) { - g_return_if_fail (E_IS_CAL_CLIENT (client)); - - /* Ensure that everything relevant is NULL */ - LOCK_FACTORY (); - - if (client->priv->dbus_proxy != NULL) { - GDBusConnection *connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (client->priv->dbus_proxy)); - - g_signal_handlers_disconnect_by_func (connection, gdbus_cal_client_closed_cb, client); - g_dbus_connection_signal_unsubscribe (connection, client->priv->gone_signal_id); - client->priv->gone_signal_id = 0; + SignalClosure *signal_closure = user_data; - e_dbus_calendar_call_close_sync ( - client->priv->dbus_proxy, NULL, NULL); - g_object_unref (client->priv->dbus_proxy); - client->priv->dbus_proxy = NULL; - } + g_signal_emit_by_name ( + signal_closure->client, + "backend-died"); - UNLOCK_FACTORY (); + return FALSE; } static gboolean @@ -853,6 +752,43 @@ cal_client_dbus_proxy_free_busy_data_cb (EDBusCalendar *dbus_proxy, } static void +cal_client_name_vanished_cb (GDBusConnection *connection, + const gchar *name, + ECalClient *cal_client) +{ + GSource *idle_source; + SignalClosure *signal_closure; + + signal_closure = g_slice_new0 (SignalClosure); + signal_closure->client = g_object_ref (cal_client); + + idle_source = g_idle_source_new (); + g_source_set_callback ( + idle_source, + cal_client_emit_backend_died_idle_cb, + signal_closure, + (GDestroyNotify) signal_closure_free); + g_source_attach (idle_source, cal_client->priv->main_context); + g_source_unref (idle_source); +} + +static void +cal_client_close_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + GError *error = NULL; + + e_dbus_calendar_call_close_finish ( + E_DBUS_CALENDAR (source_object), result, &error); + + if (error != NULL) { + g_warning ("%s: %s", G_STRFUNC, error->message); + g_error_free (error); + } +} + +static void cal_client_set_source_type (ECalClient *cal_client, ECalClientSourceType source_type) { @@ -924,7 +860,15 @@ cal_client_dispose (GObject *object) priv->dbus_proxy_free_busy_data_handler_id = 0; } - gdbus_cal_client_disconnect (E_CAL_CLIENT (object)); + if (priv->dbus_proxy != NULL) { + /* Call close() asynchronously + * so we don't block dispose(). */ + e_dbus_calendar_call_close ( + priv->dbus_proxy, NULL, + cal_client_close_cb, NULL); + g_object_unref (priv->dbus_proxy); + priv->dbus_proxy = NULL; + } if (priv->main_context != NULL) { g_main_context_unref (priv->main_context); @@ -938,12 +882,12 @@ cal_client_dispose (GObject *object) static void cal_client_finalize (GObject *object) { - ECalClient *client; ECalClientPrivate *priv; - client = E_CAL_CLIENT (object); + priv = E_CAL_CLIENT_GET_PRIVATE (object); - priv = client->priv; + if (priv->name_watcher_id > 0) + g_bus_unwatch_name (priv->name_watcher_id); if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ()) icaltimezone_free (priv->default_zone, 1); @@ -958,7 +902,7 @@ cal_client_finalize (GObject *object) G_OBJECT_CLASS (e_cal_client_parent_class)->finalize (object); if (g_atomic_int_dec_and_test (&active_cal_clients)) - gdbus_cal_factory_disconnect (NULL); + cal_factory_disconnect (); } static GDBusProxy * @@ -1123,7 +1067,8 @@ cal_client_init_in_dbus_thread (GSimpleAsyncResult *simple, ECalClientPrivate *priv; EClient *client; ESource *source; - GDBusConnection *connection; + GDBusProxy *factory_proxy; + GDBusProxy *proxy; const gchar *uid; gchar *object_path = NULL; gulong handler_id; @@ -1135,9 +1080,7 @@ cal_client_init_in_dbus_thread (GSimpleAsyncResult *simple, source = e_client_get_source (client); uid = e_source_get_uid (source); - LOCK_FACTORY (); - gdbus_cal_factory_activate (cancellable, &error); - UNLOCK_FACTORY (); + cal_factory_activate (cancellable, &error); if (error != NULL) { unwrap_dbus_error (error, &error); @@ -1176,14 +1119,13 @@ cal_client_init_in_dbus_thread (GSimpleAsyncResult *simple, return; } - connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory)); + factory_proxy = G_DBUS_PROXY (cal_factory); priv->dbus_proxy = e_dbus_calendar_proxy_new_sync ( - connection, + g_dbus_proxy_get_connection (factory_proxy), G_DBUS_PROXY_FLAGS_NONE, - CALENDAR_DBUS_SERVICE_NAME, - object_path, - cancellable, &error); + g_dbus_proxy_get_name (factory_proxy), + object_path, cancellable, &error); g_free (object_path); @@ -1198,45 +1140,42 @@ cal_client_init_in_dbus_thread (GSimpleAsyncResult *simple, return; } - g_dbus_proxy_set_default_timeout ( - G_DBUS_PROXY (priv->dbus_proxy), DBUS_PROXY_TIMEOUT_MS); + /* Configure our new GDBusProxy. */ + + proxy = G_DBUS_PROXY (priv->dbus_proxy); - priv->gone_signal_id = g_dbus_connection_signal_subscribe ( - connection, - "org.freedesktop.DBus", /* sender */ - "org.freedesktop.DBus", /* interface */ - "NameOwnerChanged", /* member */ - "/org/freedesktop/DBus", /* object_path */ - "org.gnome.evolution.dataserver.Calendar", /* arg0 */ - G_DBUS_SIGNAL_FLAGS_NONE, - gdbus_cal_client_connection_gone_cb, client, NULL); + g_dbus_proxy_set_default_timeout (proxy, DBUS_PROXY_TIMEOUT_MS); - g_signal_connect ( - connection, "closed", - G_CALLBACK (gdbus_cal_client_closed_cb), client); + priv->name_watcher_id = g_bus_watch_name_on_connection ( + g_dbus_proxy_get_connection (proxy), + g_dbus_proxy_get_name (proxy), + G_BUS_NAME_WATCHER_FLAGS_NONE, + (GBusNameAppearedCallback) NULL, + (GBusNameVanishedCallback) cal_client_name_vanished_cb, + client, (GDestroyNotify) NULL); handler_id = g_signal_connect_object ( - priv->dbus_proxy, "error", + proxy, "error", G_CALLBACK (cal_client_dbus_proxy_error_cb), client, 0); priv->dbus_proxy_error_handler_id = handler_id; handler_id = g_signal_connect_object ( - priv->dbus_proxy, "notify", + proxy, "notify", G_CALLBACK (cal_client_dbus_proxy_notify_cb), client, 0); priv->dbus_proxy_notify_handler_id = handler_id; handler_id = g_signal_connect_object ( - priv->dbus_proxy, "free-busy-data", + proxy, "free-busy-data", G_CALLBACK (cal_client_dbus_proxy_free_busy_data_cb), client, 0); priv->dbus_proxy_free_busy_data_handler_id = handler_id; /* Initialize our public-facing GObject properties. */ - g_object_notify (G_OBJECT (priv->dbus_proxy), "online"); - g_object_notify (G_OBJECT (priv->dbus_proxy), "writable"); - g_object_notify (G_OBJECT (priv->dbus_proxy), "capabilities"); + g_object_notify (G_OBJECT (proxy), "online"); + g_object_notify (G_OBJECT (proxy), "writable"); + g_object_notify (G_OBJECT (proxy), "capabilities"); } static gboolean