[evolution-data-server] EBookClient: Use g_bus_watch_name_on_connection().



commit 8726e44eac95b7966061d5bada845160a8ecc464
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sat Feb 9 10:37:31 2013 -0500

    EBookClient: 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.

 addressbook/libebook/e-book-client.c |  286 ++++++++++++++--------------------
 1 files changed, 116 insertions(+), 170 deletions(-)
---
diff --git a/addressbook/libebook/e-book-client.c b/addressbook/libebook/e-book-client.c
index 79ff390..f13c623 100644
--- a/addressbook/libebook/e-book-client.c
+++ b/addressbook/libebook/e-book-client.c
@@ -51,9 +51,9 @@ typedef struct _ConnectClosure ConnectClosure;
 typedef struct _RunInThreadClosure RunInThreadClosure;
 
 struct _EBookClientPrivate {
-	EDBusAddressBook *dbus_proxy;
 	GMainContext *main_context;
-	guint gone_signal_id;
+	EDBusAddressBook *dbus_proxy;
+	guint name_watcher_id;
 
 	gulong dbus_proxy_error_handler_id;
 	gulong dbus_proxy_notify_handler_id;
@@ -285,87 +285,46 @@ set_proxy_gone_error (GError **error)
 }
 
 static volatile gint active_book_clients = 0;
-static guint book_connection_closed_id = 0;
+static guint book_factory_watcher_id = 0;
 static EDBusAddressBookFactory *book_factory = NULL;
 static GRecMutex book_factory_lock;
 #define LOCK_FACTORY()   g_rec_mutex_lock (&book_factory_lock)
 #define UNLOCK_FACTORY() g_rec_mutex_unlock (&book_factory_lock)
 
-static void gdbus_book_factory_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, gpointer user_data);
-
 static void
-gdbus_book_factory_disconnect (GDBusConnection *connection)
+book_factory_disconnect (void)
 {
 	LOCK_FACTORY ();
 
-	if (!connection && book_factory)
-		connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (book_factory));
-
-	if (connection && book_connection_closed_id) {
-		g_dbus_connection_signal_unsubscribe (connection, book_connection_closed_id);
-		g_signal_handlers_disconnect_by_func (connection, gdbus_book_factory_closed_cb, NULL);
+	if (book_factory_watcher_id > 0) {
+		g_bus_unwatch_name (book_factory_watcher_id);
+		book_factory_watcher_id = 0;
 	}
 
-	if (book_factory != NULL)
-		g_object_unref (book_factory);
-
-	book_connection_closed_id = 0;
-	book_factory = NULL;
+	g_clear_object (&book_factory);
 
 	UNLOCK_FACTORY ();
 }
 
 static void
-gdbus_book_factory_closed_cb (GDBusConnection *connection,
-                              gboolean remote_peer_vanished,
-                              GError *error,
-                              gpointer user_data)
-{
-	GError *err = NULL;
-
-	LOCK_FACTORY ();
-
-	gdbus_book_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_book_clients > 0) {
-		g_debug ("GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
-	}
-
-	UNLOCK_FACTORY ();
-}
-
-static void
-gdbus_book_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)
+book_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_book_factory_closed_cb (connection, TRUE, NULL, user_data);
+	book_factory_disconnect ();
 }
 
 static gboolean
-gdbus_book_factory_activate (GCancellable *cancellable,
-                             GError **error)
+book_factory_activate (GCancellable *cancellable,
+                       GError **error)
 {
-	GDBusConnection *connection;
+	GDBusProxy *proxy;
+	gboolean success = TRUE;
 
 	LOCK_FACTORY ();
 
-	if (G_LIKELY (book_factory != NULL)) {
-		UNLOCK_FACTORY ();
-		return TRUE;
-	}
+	if (G_LIKELY (book_factory != NULL))
+		goto exit;
 
 	book_factory = e_dbus_address_book_factory_proxy_new_for_bus_sync (
 		G_BUS_TYPE_SESSION,
@@ -375,28 +334,24 @@ gdbus_book_factory_activate (GCancellable *cancellable,
 		cancellable, error);
 
 	if (book_factory == NULL) {
-		UNLOCK_FACTORY ();
-		return FALSE;
+		success = FALSE;
+		goto exit;
 	}
 
-	connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (book_factory));
-	book_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.AddressBook",	/* arg0 */
-		G_DBUS_SIGNAL_FLAGS_NONE,
-		gdbus_book_factory_connection_gone_cb, NULL, NULL);
-
-	g_signal_connect (
-		connection, "closed",
-		G_CALLBACK (gdbus_book_factory_closed_cb), NULL);
+	proxy = G_DBUS_PROXY (book_factory);
+
+	book_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) book_factory_name_vanished_cb,
+		NULL, (GDestroyNotify) NULL);
 
+exit:
 	UNLOCK_FACTORY ();
 
-	return TRUE;
+	return success;
 }
 
 static gpointer
@@ -500,72 +455,16 @@ book_client_run_in_dbus_thread (GSimpleAsyncResult *simple,
 	g_main_context_unref (main_context);
 }
 
-static void gdbus_book_client_disconnect (EBookClient *client);
-
-/*
- * Called when the addressbook server dies.
- */
-static void
-gdbus_book_client_closed_cb (GDBusConnection *connection,
-                             gboolean remote_peer_vanished,
-                             GError *error,
-                             EBookClient *client)
-{
-	GError *err = NULL;
-
-	g_assert (E_IS_BOOK_CLIENT (client));
-
-	if (error)
-		unwrap_dbus_error (g_error_copy (error), &err);
-
-	if (err) {
-		g_debug (G_STRLOC ": EBookClient GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
-		g_error_free (err);
-	} else {
-		g_debug (G_STRLOC ": EBookClient GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
-	}
-
-	gdbus_book_client_disconnect (client);
-
-	e_client_emit_backend_died (E_CLIENT (client));
-}
-
-static void
-gdbus_book_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_book_client_closed_cb (connection, TRUE, NULL, user_data);
-}
-
-static void
-gdbus_book_client_disconnect (EBookClient *client)
+static gboolean
+book_client_emit_backend_died_idle_cb (gpointer user_data)
 {
-	g_return_if_fail (E_IS_BOOK_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_book_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_address_book_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
@@ -703,6 +602,43 @@ book_client_dbus_proxy_notify_cb (EDBusAddressBook *dbus_proxy,
 }
 
 static void
+book_client_name_vanished_cb (GDBusConnection *connection,
+                              const gchar *name,
+                              EBookClient *book_client)
+{
+	GSource *idle_source;
+	SignalClosure *signal_closure;
+
+	signal_closure = g_slice_new0 (SignalClosure);
+	signal_closure->client = g_object_ref (book_client);
+
+	idle_source = g_idle_source_new ();
+	g_source_set_callback (
+		idle_source,
+		book_client_emit_backend_died_idle_cb,
+		signal_closure,
+		(GDestroyNotify) signal_closure_free);
+	g_source_attach (idle_source, book_client->priv->main_context);
+	g_source_unref (idle_source);
+}
+
+static void
+book_client_close_cb (GObject *source_object,
+                      GAsyncResult *result,
+                      gpointer user_data)
+{
+	GError *error = NULL;
+
+	e_dbus_address_book_call_close_finish (
+		E_DBUS_ADDRESS_BOOK (source_object), result, &error);
+
+	if (error != NULL) {
+		g_warning ("%s: %s", G_STRFUNC, error->message);
+		g_error_free (error);
+	}
+}
+
+static void
 book_client_dispose (GObject *object)
 {
 	EBookClientPrivate *priv;
@@ -725,7 +661,15 @@ book_client_dispose (GObject *object)
 		priv->dbus_proxy_notify_handler_id = 0;
 	}
 
-	gdbus_book_client_disconnect (E_BOOK_CLIENT (object));
+	if (priv->dbus_proxy != NULL) {
+		/* Call close() asynchronously
+		 * so we don't block dispose(). */
+		e_dbus_address_book_call_close (
+			priv->dbus_proxy, NULL,
+			book_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);
@@ -739,11 +683,18 @@ book_client_dispose (GObject *object)
 static void
 book_client_finalize (GObject *object)
 {
+	EBookClientPrivate *priv;
+
+	priv = E_BOOK_CLIENT_GET_PRIVATE (object);
+
+	if (priv->name_watcher_id > 0)
+		g_bus_unwatch_name (priv->name_watcher_id);
+
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (e_book_client_parent_class)->finalize (object);
 
 	if (g_atomic_int_dec_and_test (&active_book_clients))
-		gdbus_book_factory_disconnect (NULL);
+		book_factory_disconnect ();
 }
 
 static GDBusProxy *
@@ -916,7 +867,8 @@ book_client_init_in_dbus_thread (GSimpleAsyncResult *simple,
 	EBookClientPrivate *priv;
 	EClient *client;
 	ESource *source;
-	GDBusConnection *connection;
+	GDBusProxy *factory_proxy;
+	GDBusProxy *proxy;
 	const gchar *uid;
 	gchar *object_path = NULL;
 	gulong handler_id;
@@ -928,9 +880,7 @@ book_client_init_in_dbus_thread (GSimpleAsyncResult *simple,
 	source = e_client_get_source (client);
 	uid = e_source_get_uid (source);
 
-	LOCK_FACTORY ();
-	gdbus_book_factory_activate (cancellable, &error);
-	UNLOCK_FACTORY ();
+	book_factory_activate (cancellable, &error);
 
 	if (error != NULL) {
 		unwrap_dbus_error (error, &error);
@@ -946,20 +896,19 @@ book_client_init_in_dbus_thread (GSimpleAsyncResult *simple,
 		((object_path != NULL) && (error == NULL)) ||
 		((object_path == NULL) && (error != NULL)));
 
-	if (object_path == NULL) {
+	if (error != NULL) {
 		unwrap_dbus_error (error, &error);
 		g_simple_async_result_take_error (simple, error);
 		return;
 	}
 
-	connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (book_factory));
+	factory_proxy = G_DBUS_PROXY (book_factory);
 
 	priv->dbus_proxy = e_dbus_address_book_proxy_new_sync (
-		connection,
+		g_dbus_proxy_get_connection (factory_proxy),
 		G_DBUS_PROXY_FLAGS_NONE,
-		ADDRESS_BOOK_DBUS_SERVICE_NAME,
-		object_path,
-		cancellable, &error);
+		g_dbus_proxy_get_name (factory_proxy),
+		object_path, cancellable, &error);
 
 	g_free (object_path);
 
@@ -974,39 +923,36 @@ book_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.AddressBook",	/* arg0 */
-		G_DBUS_SIGNAL_FLAGS_NONE,
-		gdbus_book_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_book_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) book_client_name_vanished_cb,
+		client, (GDestroyNotify) NULL);
 
 	handler_id = g_signal_connect_object (
-		priv->dbus_proxy, "error",
+		proxy, "error",
 		G_CALLBACK (book_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 (book_client_dbus_proxy_notify_cb),
 		client, 0);
 	priv->dbus_proxy_notify_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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]