[telepathy-glib/master] Separate dbus.c into dbus.c and dbus-daemon.c

Simon McVittie simon.mcvittie at collabora.co.uk
Mon Aug 17 05:36:49 PDT 2009


No code changes, except renaming starter_bus_conn to
_tp_dbus_starter_bus_conn and making it visible within telepathy-glib
(both of the split modules need it, now).
---
 telepathy-glib/Makefile.am     |    1 +
 telepathy-glib/dbus-daemon.c   | 1098 ++++++++++++++++++++++++++++++++++++++++
 telepathy-glib/dbus-internal.h |    2 +
 telepathy-glib/dbus.c          | 1077 +---------------------------------------
 4 files changed, 1104 insertions(+), 1074 deletions(-)
 create mode 100644 telepathy-glib/dbus-daemon.c

diff --git a/telepathy-glib/Makefile.am b/telepathy-glib/Makefile.am
index 6844be9..3b364f5 100644
--- a/telepathy-glib/Makefile.am
+++ b/telepathy-glib/Makefile.am
@@ -290,6 +290,7 @@ libtelepathy_glib_internal_la_SOURCES = \
     contact.c \
     contacts-mixin.c \
     dbus.c \
+    dbus-daemon.c \
     dbus-internal.h \
     dbus-properties-mixin.c \
     debug.c \
diff --git a/telepathy-glib/dbus-daemon.c b/telepathy-glib/dbus-daemon.c
new file mode 100644
index 0000000..75525d6
--- /dev/null
+++ b/telepathy-glib/dbus-daemon.c
@@ -0,0 +1,1098 @@
+/*
+ * dbus-daemon.c - Source for TpDBusDaemon
+ *
+ * Copyright (C) 2005-2009 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2005-2009 Nokia Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/dbus-internal.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <telepathy-glib/errors.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/proxy-subclass.h>
+#include <telepathy-glib/util.h>
+
+#include "telepathy-glib/_gen/signals-marshal.h"
+
+#include "telepathy-glib/_gen/tp-cli-dbus-daemon-body.h"
+
+#define DEBUG_FLAG TP_DEBUG_PROXY
+#include "debug-internal.h"
+
+/**
+ * TpDBusDaemonClass:
+ *
+ * The class of #TpDBusDaemon.
+ *
+ * Since: 0.7.1
+ */
+struct _TpDBusDaemonClass
+{
+  /*<private>*/
+  TpProxyClass parent_class;
+  gpointer priv;
+};
+
+/**
+ * TpDBusDaemon:
+ *
+ * A subclass of #TpProxy that represents the D-Bus daemon. It mainly provides
+ * functionality to manage well-known names on the bus.
+ *
+ * Since: 0.7.1
+ */
+struct _TpDBusDaemon
+{
+  /*<private>*/
+  TpProxy parent;
+
+  TpDBusDaemonPrivate *priv;
+};
+
+struct _TpDBusDaemonPrivate
+{
+  /* dup'd name => _NameOwnerWatch */
+  GHashTable *name_owner_watches;
+  /* reffed */
+  DBusConnection *libdbus;
+};
+
+G_DEFINE_TYPE (TpDBusDaemon, tp_dbus_daemon, TP_TYPE_PROXY);
+
+static gpointer starter_bus_daemon = NULL;
+
+/**
+ * tp_dbus_daemon_dup:
+ * @error: Used to indicate error if %NULL is returned
+ *
+ * Returns a proxy for signals and method calls on the D-Bus daemon on which
+ * this process was activated (if it was launched by D-Bus service
+ * activation), or the session bus (otherwise).
+ *
+ * If it is not possible to connect to the appropriate bus, raise an error
+ * and return %NULL.
+ *
+ * The returned #TpDBusDaemon is cached; the same #TpDBusDaemon object will
+ * be returned by this function repeatedly, as long as at least one reference
+ * exists.
+ *
+ * Returns: a reference to a proxy for signals and method calls on the bus
+ *  daemon, or %NULL
+ *
+ * Since: 0.7.26
+ */
+TpDBusDaemon *
+tp_dbus_daemon_dup (GError **error)
+{
+  DBusGConnection *conn;
+
+  if (starter_bus_daemon != NULL)
+    return g_object_ref (starter_bus_daemon);
+
+  conn = _tp_dbus_starter_bus_conn (error);
+
+  if (conn == NULL)
+    return NULL;
+
+  starter_bus_daemon = tp_dbus_daemon_new (conn);
+  g_assert (starter_bus_daemon != NULL);
+  g_object_add_weak_pointer (starter_bus_daemon, &starter_bus_daemon);
+
+  return starter_bus_daemon;
+}
+
+/**
+ * tp_dbus_daemon_new:
+ * @connection: a connection to D-Bus
+ *
+ * Returns a proxy for signals and method calls on a particular bus
+ * connection.
+ *
+ * Use tp_dbus_daemon_dup() instead if you just want a connection to the
+ * starter or session bus (which is almost always the right thing for
+ * Telepathy).
+ *
+ * Returns: a new proxy for signals and method calls on the bus daemon
+ *  to which @connection is connected
+ *
+ * Since: 0.7.1
+ */
+TpDBusDaemon *
+tp_dbus_daemon_new (DBusGConnection *connection)
+{
+  g_return_val_if_fail (connection != NULL, NULL);
+
+  return TP_DBUS_DAEMON (g_object_new (TP_TYPE_DBUS_DAEMON,
+        "dbus-connection", connection,
+        "bus-name", DBUS_SERVICE_DBUS,
+        "object-path", DBUS_PATH_DBUS,
+        NULL));
+}
+
+typedef struct
+{
+  TpDBusDaemonNameOwnerChangedCb callback;
+  gpointer user_data;
+  GDestroyNotify destroy;
+  gchar *last_owner;
+} _NameOwnerWatch;
+
+typedef struct
+{
+  TpDBusDaemonNameOwnerChangedCb callback;
+  gpointer user_data;
+  GDestroyNotify destroy;
+} _NameOwnerSubWatch;
+
+static void
+_tp_dbus_daemon_name_owner_changed_multiple (TpDBusDaemon *self,
+                                             const gchar *name,
+                                             const gchar *new_owner,
+                                             gpointer user_data)
+{
+  GArray *array = user_data;
+  guint i;
+
+  for (i = 0; i < array->len; i++)
+    {
+      _NameOwnerSubWatch *watch = &g_array_index (array, _NameOwnerSubWatch,
+          i);
+
+      watch->callback (self, name, new_owner, watch->user_data);
+    }
+}
+
+static void
+_tp_dbus_daemon_name_owner_changed_multiple_free (gpointer data)
+{
+  GArray *array = data;
+  guint i;
+
+  for (i = 0; i < array->len; i++)
+    {
+      _NameOwnerSubWatch *watch = &g_array_index (array, _NameOwnerSubWatch,
+          i);
+
+      if (watch->destroy)
+        watch->destroy (watch->user_data);
+    }
+
+  g_array_free (array, TRUE);
+}
+
+static void
+_tp_dbus_daemon_name_owner_changed (TpDBusDaemon *self,
+                                    const gchar *name,
+                                    const gchar *new_owner)
+{
+  _NameOwnerWatch *watch = g_hash_table_lookup (self->priv->name_owner_watches,
+      name);
+
+  DEBUG ("%s -> %s", name, new_owner);
+
+  if (watch == NULL)
+    return;
+
+  /* This is partly to handle the case where an owner change happens
+   * while GetNameOwner is in flight, partly to be able to optimize by only
+   * calling GetNameOwner if we didn't already know, and partly because of a
+   * dbus-glib bug that means we get every signal twice
+   * (it thinks org.freedesktop.DBus is both a well-known name and a unique
+   * name). */
+  if (!tp_strdiff (watch->last_owner, new_owner))
+    return;
+
+  g_free (watch->last_owner);
+  watch->last_owner = g_strdup (new_owner);
+
+  watch->callback (self, name, new_owner, watch->user_data);
+}
+
+static dbus_int32_t daemons_slot = -1;
+
+typedef struct {
+    DBusConnection *libdbus;
+    DBusMessage *message;
+} NOCIdleContext;
+
+static NOCIdleContext *
+noc_idle_context_new (DBusConnection *libdbus,
+                      DBusMessage *message)
+{
+  NOCIdleContext *context = g_slice_new (NOCIdleContext);
+
+  context->libdbus = dbus_connection_ref (libdbus);
+  context->message = dbus_message_ref (message);
+  return context;
+}
+
+static void
+noc_idle_context_free (gpointer data)
+{
+  NOCIdleContext *context = data;
+
+  dbus_connection_unref (context->libdbus);
+  dbus_message_unref (context->message);
+  g_slice_free (NOCIdleContext, context);
+}
+
+static gboolean
+noc_idle_context_invoke (gpointer data)
+{
+  NOCIdleContext *context = data;
+  const gchar *name;
+  const gchar *old_owner;
+  const gchar *new_owner;
+  DBusError dbus_error = DBUS_ERROR_INIT;
+  GSList **daemons;
+
+  if (daemons_slot == -1)
+    return FALSE;
+
+  if (!dbus_message_get_args (context->message, &dbus_error,
+        DBUS_TYPE_STRING, &name,
+        DBUS_TYPE_STRING, &old_owner,
+        DBUS_TYPE_STRING, &new_owner,
+        DBUS_TYPE_INVALID))
+    {
+      DEBUG ("Couldn't unpack NameOwnerChanged(s, s, s): %s: %s",
+          dbus_error.name, dbus_error.message);
+      dbus_error_free (&dbus_error);
+      return FALSE;
+    }
+
+  daemons = dbus_connection_get_data (context->libdbus, daemons_slot);
+
+  DEBUG ("NameOwnerChanged(%s, %s -> %s)", name, old_owner, new_owner);
+
+  /* should always be non-NULL, barring bugs */
+  if (G_LIKELY (daemons != NULL))
+    {
+      GSList *iter;
+
+      for (iter = *daemons; iter != NULL; iter = iter->next)
+        _tp_dbus_daemon_name_owner_changed (iter->data, name, new_owner);
+    }
+
+  return FALSE;
+}
+
+static DBusHandlerResult
+_tp_dbus_daemon_name_owner_changed_filter (DBusConnection *libdbus,
+                                           DBusMessage *message,
+                                           void *unused G_GNUC_UNUSED)
+{
+  /* We have to do the real work in an idle, so we don't break re-entrant
+   * calls (the dbus-glib event source isn't re-entrant) */
+  if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
+        "NameOwnerChanged") &&
+      dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
+    g_idle_add_full (G_PRIORITY_HIGH, noc_idle_context_invoke,
+        noc_idle_context_new (libdbus, message),
+        noc_idle_context_free);
+
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+typedef struct {
+    TpDBusDaemon *self;
+    gchar *name;
+    DBusMessage *reply;
+    gsize refs;
+} GetNameOwnerContext;
+
+static GetNameOwnerContext *
+get_name_owner_context_new (TpDBusDaemon *self,
+                            const gchar *name)
+{
+  GetNameOwnerContext *context = g_slice_new (GetNameOwnerContext);
+
+  context->self = g_object_ref (self);
+  context->name = g_strdup (name);
+  context->reply = NULL;
+  DEBUG ("New, 1 ref");
+  context->refs = 1;
+  return context;
+}
+
+static void
+get_name_owner_context_unref (gpointer data)
+{
+  GetNameOwnerContext *context = data;
+
+  DEBUG ("%lu -> %lu", (gulong) context->refs, (gulong) (context->refs-1));
+
+  if (--context->refs == 0)
+    {
+      g_object_unref (context->self);
+      g_free (context->name);
+
+      if (context->reply != NULL)
+        dbus_message_unref (context->reply);
+
+      g_slice_free (GetNameOwnerContext, context);
+    }
+}
+
+static gboolean
+_tp_dbus_daemon_get_name_owner_idle (gpointer data)
+{
+  GetNameOwnerContext *context = data;
+  const gchar *owner = "";
+
+  if (context->reply == NULL)
+    {
+      DEBUG ("Connection disconnected or no reply to GetNameOwner(%s)",
+          context->name);
+    }
+  else if (dbus_message_get_type (context->reply) ==
+      DBUS_MESSAGE_TYPE_METHOD_RETURN)
+    {
+      if (!dbus_message_get_args (context->reply, NULL,
+            DBUS_TYPE_STRING, &owner,
+            DBUS_TYPE_INVALID))
+        {
+          DEBUG ("Malformed reply from GetNameOwner(%s), assuming no owner",
+              context->name);
+        }
+    }
+  else
+    {
+      if (DEBUGGING)
+        {
+          DBusError error = DBUS_ERROR_INIT;
+
+          if (dbus_set_error_from_message (&error, context->reply))
+            {
+              DEBUG ("GetNameOwner(%s) raised %s: %s", context->name,
+                  error.name, error.message);
+              dbus_error_free (&error);
+            }
+          else
+            {
+              DEBUG ("Unexpected message type from GetNameOwner(%s)",
+                  context->name);
+            }
+        }
+    }
+
+  _tp_dbus_daemon_name_owner_changed (context->self, context->name, owner);
+
+  return FALSE;
+}
+
+/**
+ * TpDBusDaemonNameOwnerChangedCb:
+ * @bus_daemon: The D-Bus daemon
+ * @name: The name whose ownership has changed or been discovered
+ * @new_owner: The unique name that now owns @name
+ * @user_data: Arbitrary user-supplied data as passed to
+ *  tp_dbus_daemon_watch_name_owner()
+ *
+ * The signature of the callback called by tp_dbus_daemon_watch_name_owner().
+ *
+ * Since: 0.7.1
+ */
+
+static inline gchar *
+_tp_dbus_daemon_get_noc_rule (const gchar *name)
+{
+  return g_strdup_printf ("type='signal',"
+      "sender='" DBUS_SERVICE_DBUS "',"
+      "path='" DBUS_PATH_DBUS "',"
+      "interface='"DBUS_INTERFACE_DBUS "',"
+      "member='NameOwnerChanged',"
+      "arg0='%s'", name);
+}
+
+static void
+_tp_dbus_daemon_get_name_owner_notify (DBusPendingCall *pc,
+                                       gpointer data)
+{
+  GetNameOwnerContext *context = data;
+
+  /* we recycle this function for the case where the connection is already
+   * disconnected: in that case we use pc = NULL */
+  if (pc != NULL)
+    context->reply = dbus_pending_call_steal_reply (pc);
+
+  /* We have to do the real work in an idle, so we don't break re-entrant
+   * calls (the dbus-glib event source isn't re-entrant) */
+  DEBUG ("%lu -> %lu", (gulong) context->refs, (gulong) (context->refs + 1));
+  context->refs++;
+  g_idle_add_full (G_PRIORITY_HIGH, _tp_dbus_daemon_get_name_owner_idle,
+      context, get_name_owner_context_unref);
+
+  if (pc != NULL)
+    dbus_pending_call_unref (pc);
+}
+
+/**
+ * tp_dbus_daemon_watch_name_owner:
+ * @self: The D-Bus daemon
+ * @name: The name whose ownership is to be watched
+ * @callback: Callback to call when the ownership is discovered or changes
+ * @user_data: Arbitrary data to pass to @callback
+ * @destroy: Called to destroy @user_data when the name owner watch is
+ *  cancelled due to tp_dbus_daemon_cancel_name_owner_watch()
+ *
+ * Arrange for @callback to be called with the owner of @name as soon as
+ * possible (which might even be before this function returns!), then
+ * again every time the ownership of @name changes.
+ *
+ * If multiple watches are registered for the same @name, they will be called
+ * in the order they were registered.
+ *
+ * Since: 0.7.1
+ */
+void
+tp_dbus_daemon_watch_name_owner (TpDBusDaemon *self,
+                                 const gchar *name,
+                                 TpDBusDaemonNameOwnerChangedCb callback,
+                                 gpointer user_data,
+                                 GDestroyNotify destroy)
+{
+  _NameOwnerWatch *watch = g_hash_table_lookup (self->priv->name_owner_watches,
+      name);
+
+  g_return_if_fail (TP_IS_DBUS_DAEMON (self));
+  g_return_if_fail (tp_dbus_check_valid_bus_name (name,
+        TP_DBUS_NAME_TYPE_ANY, NULL));
+  g_return_if_fail (name != NULL);
+  g_return_if_fail (callback != NULL);
+
+  if (watch == NULL)
+    {
+      gchar *match_rule;
+      DBusMessage *message;
+      DBusPendingCall *pc = NULL;
+      GetNameOwnerContext *context = get_name_owner_context_new (self, name);
+
+      /* Allocate a single watch (common case) */
+      watch = g_slice_new (_NameOwnerWatch);
+      watch->callback = callback;
+      watch->user_data = user_data;
+      watch->destroy = destroy;
+      watch->last_owner = NULL;
+
+      g_hash_table_insert (self->priv->name_owner_watches, g_strdup (name),
+          watch);
+
+      /* We want to be notified about name owner changes for this one.
+       * Assume the match addition will succeed; there's no good way to cope
+       * with failure here... */
+      match_rule = _tp_dbus_daemon_get_noc_rule (name);
+      DEBUG ("Adding match rule %s", match_rule);
+      dbus_bus_add_match (self->priv->libdbus, match_rule, NULL);
+
+      message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+          DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner");
+
+      if (message == NULL)
+        g_error ("Out of memory");
+
+      /* We already checked that @name was in (a small subset of) UTF-8,
+       * so OOM is the only thing that can go wrong. The use of &name here
+       * is because libdbus is strange. */
+      if (!dbus_message_append_args (message,
+            DBUS_TYPE_STRING, &name,
+            DBUS_TYPE_INVALID))
+        g_error ("Out of memory");
+
+      if (!dbus_connection_send_with_reply (self->priv->libdbus,
+          message, &pc, -1))
+        g_error ("Out of memory");
+      /* pc is unreffed by _tp_dbus_daemon_get_name_owner_notify */
+
+      if (pc == NULL || dbus_pending_call_get_completed (pc))
+        {
+          /* pc can be NULL when the connection is already disconnected */
+          _tp_dbus_daemon_get_name_owner_notify (pc, context);
+          get_name_owner_context_unref (context);
+        }
+      else if (!dbus_pending_call_set_notify (pc,
+            _tp_dbus_daemon_get_name_owner_notify,
+            context, get_name_owner_context_unref))
+        {
+          g_error ("Out of memory");
+        }
+    }
+  else
+    {
+      _NameOwnerSubWatch tmp = { callback, user_data, destroy };
+
+      if (watch->callback == _tp_dbus_daemon_name_owner_changed_multiple)
+        {
+          /* The watch is already a "multiplexer", just append to it */
+          GArray *array = watch->user_data;
+
+          g_array_append_val (array, tmp);
+        }
+      else
+        {
+          /* Replace the old contents of the watch with one that dispatches
+           * the signal to (potentially) more than one watcher */
+          GArray *array = g_array_sized_new (FALSE, FALSE,
+              sizeof (_NameOwnerSubWatch), 2);
+
+          /* The new watcher */
+          g_array_append_val (array, tmp);
+          /* The old watcher */
+          tmp.callback = watch->callback;
+          tmp.user_data = watch->user_data;
+          tmp.destroy = watch->destroy;
+          g_array_prepend_val (array, tmp);
+
+          watch->callback = _tp_dbus_daemon_name_owner_changed_multiple;
+          watch->user_data = array;
+          watch->destroy = _tp_dbus_daemon_name_owner_changed_multiple_free;
+        }
+
+      if (watch->last_owner != NULL)
+        {
+          /* FIXME: should avoid reentrancy? */
+          callback (self, name, watch->last_owner, user_data);
+        }
+    }
+}
+
+static void
+_tp_dbus_daemon_stop_watching (TpDBusDaemon *self,
+                               const gchar *name,
+                               _NameOwnerWatch *watch)
+{
+  gchar *match_rule;
+
+  if (watch->destroy)
+    watch->destroy (watch->user_data);
+
+  g_free (watch->last_owner);
+  g_slice_free (_NameOwnerWatch, watch);
+
+  match_rule = _tp_dbus_daemon_get_noc_rule (name);
+  DEBUG ("Removing match rule %s", match_rule);
+  dbus_bus_remove_match (self->priv->libdbus, match_rule, NULL);
+  g_free (match_rule);
+}
+
+/**
+ * tp_dbus_daemon_cancel_name_owner_watch:
+ * @self: the D-Bus daemon
+ * @name: the name that was being watched
+ * @callback: the callback that was called
+ * @user_data: the user data that was provided
+ *
+ * If there was a previous call to tp_dbus_daemon_watch_name_owner()
+ * with exactly the given @name, @callback and @user_data, remove it.
+ *
+ * If more than one watch matching the details provided was active, remove
+ * only the most recently added one.
+ *
+ * Returns: %TRUE if there was such a watch, %FALSE otherwise
+ *
+ * Since: 0.7.1
+ */
+gboolean
+tp_dbus_daemon_cancel_name_owner_watch (TpDBusDaemon *self,
+                                        const gchar *name,
+                                        TpDBusDaemonNameOwnerChangedCb callback,
+                                        gconstpointer user_data)
+{
+  _NameOwnerWatch *watch = g_hash_table_lookup (self->priv->name_owner_watches,
+      name);
+
+  g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
+  g_return_val_if_fail (name != NULL, FALSE);
+  g_return_val_if_fail (callback != NULL, FALSE);
+
+  if (watch == NULL)
+    {
+      /* No watch at all */
+      return FALSE;
+    }
+  else if (watch->callback == callback && watch->user_data == user_data)
+    {
+      /* Simple case: there is one name-owner watch and it's what we wanted */
+      _tp_dbus_daemon_stop_watching (self, name, watch);
+      g_hash_table_remove (self->priv->name_owner_watches, name);
+      return TRUE;
+    }
+  else if (watch->callback == _tp_dbus_daemon_name_owner_changed_multiple)
+    {
+      /* Complicated case: this watch is a "multiplexer", we need to check
+       * its contents */
+      GArray *array = watch->user_data;
+      guint i;
+
+      for (i = 1; i <= array->len; i++)
+        {
+          _NameOwnerSubWatch *entry = &g_array_index (array,
+              _NameOwnerSubWatch, array->len - i);
+
+          if (entry->callback == callback && entry->user_data == user_data)
+            {
+              if (entry->destroy != NULL)
+                entry->destroy (entry->user_data);
+
+              g_array_remove_index (array, array->len - i);
+
+              if (array->len == 0)
+                {
+                  _tp_dbus_daemon_stop_watching (self, name, watch);
+                  g_hash_table_remove (self->priv->name_owner_watches, name);
+                }
+
+              return TRUE;
+            }
+        }
+    }
+
+  /* We haven't found it */
+  return FALSE;
+}
+
+/* for internal use (TpChannel, TpConnection _new convenience functions) */
+gboolean
+_tp_dbus_daemon_get_name_owner (TpDBusDaemon *self,
+                                gint timeout_ms,
+                                const gchar *well_known_name,
+                                gchar **unique_name,
+                                GError **error)
+{
+  DBusGConnection *gconn;
+  DBusConnection *dbc;
+  DBusMessage *message;
+  DBusMessage *reply;
+  DBusError dbus_error;
+  const char *name_in_reply;
+  const GError *invalidated;
+
+  g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  invalidated = tp_proxy_get_invalidated (self);
+
+  if (invalidated != NULL)
+    {
+      if (error != NULL)
+        *error = g_error_copy (invalidated);
+
+      return FALSE;
+    }
+
+  gconn = tp_proxy_get_dbus_connection (self);
+  dbc = dbus_g_connection_get_connection (gconn);
+
+  message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+      DBUS_INTERFACE_DBUS, "GetNameOwner");
+
+  if (message == NULL)
+    g_error ("Out of memory");
+
+  if (!dbus_message_append_args (message,
+        DBUS_TYPE_STRING, &well_known_name,
+        DBUS_TYPE_INVALID))
+    g_error ("Out of memory");
+
+  dbus_error_init (&dbus_error);
+  reply = dbus_connection_send_with_reply_and_block (dbc, message,
+      timeout_ms, &dbus_error);
+
+  dbus_message_unref (message);
+
+  if (reply == NULL)
+    {
+      if (!tp_strdiff (dbus_error.name, DBUS_ERROR_NO_MEMORY))
+        g_error ("Out of memory");
+
+      /* FIXME: ideally we'd use dbus-glib's error mapping for this */
+      g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_NAME_OWNER_LOST,
+          "%s: %s", dbus_error.name, dbus_error.message);
+
+      dbus_error_free (&dbus_error);
+      return FALSE;
+    }
+
+  if (!dbus_message_get_args (reply, &dbus_error,
+        DBUS_TYPE_STRING, &name_in_reply,
+        DBUS_TYPE_INVALID))
+    {
+      g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_NAME_OWNER_LOST,
+          "%s: %s", dbus_error.name, dbus_error.message);
+
+      dbus_error_free (&dbus_error);
+      dbus_message_unref (reply);
+      return FALSE;
+    }
+
+  if (unique_name != NULL)
+    *unique_name = g_strdup (name_in_reply);
+
+  dbus_message_unref (reply);
+
+  return TRUE;
+}
+
+/**
+ * tp_dbus_daemon_request_name:
+ * @self: a TpDBusDaemon
+ * @well_known_name: a well-known name to acquire
+ * @idempotent: whether to consider it to be a success if this process
+ *              already owns the name
+ * @error: used to raise an error if %FALSE is returned
+ *
+ * Claim the given well-known name without queueing, allowing replacement
+ * or replacing an existing name-owner. This makes a synchronous call to the
+ * bus daemon.
+ *
+ * Returns: %TRUE if @well_known_name was claimed, or %FALSE and sets @error if
+ *          an error occurred.
+ *
+ * Since: 0.7.30
+ */
+gboolean
+tp_dbus_daemon_request_name (TpDBusDaemon *self,
+                             const gchar *well_known_name,
+                             gboolean idempotent,
+                             GError **error)
+{
+  TpProxy *as_proxy = (TpProxy *) self;
+  DBusGConnection *gconn;
+  DBusConnection *dbc;
+  DBusError dbus_error;
+  int result;
+  const GError *invalidated;
+
+  g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
+  g_return_val_if_fail (tp_dbus_check_valid_bus_name (well_known_name,
+        TP_DBUS_NAME_TYPE_WELL_KNOWN, error), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  invalidated = tp_proxy_get_invalidated (self);
+
+  if (invalidated != NULL)
+    {
+      if (error != NULL)
+        *error = g_error_copy (invalidated);
+
+      return FALSE;
+    }
+
+  gconn = as_proxy->dbus_connection;
+  dbc = dbus_g_connection_get_connection (gconn);
+
+  dbus_error_init (&dbus_error);
+  result = dbus_bus_request_name (dbc, well_known_name,
+      DBUS_NAME_FLAG_DO_NOT_QUEUE, &dbus_error);
+
+  switch (result)
+    {
+    case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
+      return TRUE;
+
+    case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
+      if (idempotent)
+        {
+          return TRUE;
+        }
+      else
+        {
+          g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+              "Name '%s' already in use by this process", well_known_name);
+          return FALSE;
+        }
+
+    case DBUS_REQUEST_NAME_REPLY_EXISTS:
+    case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
+      /* the latter shouldn't actually happen since we said DO_NOT_QUEUE */
+      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+          "Name '%s' already in use by another process", well_known_name);
+      return FALSE;
+
+    case -1:
+      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+          "%s: %s", dbus_error.name, dbus_error.message);
+      dbus_error_free (&dbus_error);
+      return FALSE;
+
+    default:
+      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+          "RequestName('%s') returned %d and I don't know what that means",
+          well_known_name, result);
+      return FALSE;
+    }
+}
+
+/**
+ * tp_dbus_daemon_release_name:
+ * @self: a TpDBusDaemon
+ * @well_known_name: a well-known name owned by this process to release
+ * @error: used to raise an error if %FALSE is returned
+ *
+ * Release the given well-known name. This makes a synchronous call to the bus
+ * daemon.
+ *
+ * Returns: %TRUE if @well_known_name was released, or %FALSE and sets @error
+ *          if an error occurred.
+ *
+ * Since: 0.7.30
+ */
+gboolean
+tp_dbus_daemon_release_name (TpDBusDaemon *self,
+                             const gchar *well_known_name,
+                             GError **error)
+{
+  TpProxy *as_proxy = (TpProxy *) self;
+  DBusGConnection *gconn;
+  DBusConnection *dbc;
+  DBusError dbus_error;
+  int result;
+  const GError *invalidated;
+
+  g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
+  g_return_val_if_fail (tp_dbus_check_valid_bus_name (well_known_name,
+        TP_DBUS_NAME_TYPE_WELL_KNOWN, error), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  invalidated = tp_proxy_get_invalidated (self);
+
+  if (invalidated != NULL)
+    {
+      if (error != NULL)
+        *error = g_error_copy (invalidated);
+
+      return FALSE;
+    }
+
+  gconn = as_proxy->dbus_connection;
+  dbc = dbus_g_connection_get_connection (gconn);
+  dbus_error_init (&dbus_error);
+  result = dbus_bus_release_name (dbc, well_known_name, &dbus_error);
+
+  switch (result)
+    {
+    case DBUS_RELEASE_NAME_REPLY_RELEASED:
+      return TRUE;
+
+    case DBUS_RELEASE_NAME_REPLY_NOT_OWNER:
+      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_YOURS,
+          "Name '%s' owned by another process", well_known_name);
+      return FALSE;
+
+    case DBUS_RELEASE_NAME_REPLY_NON_EXISTENT:
+      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+          "Name '%s' not owned", well_known_name);
+      return FALSE;
+
+    case -1:
+      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+          "%s: %s", dbus_error.name, dbus_error.message);
+      dbus_error_free (&dbus_error);
+      return FALSE;
+
+    default:
+      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+          "ReleaseName('%s') returned %d and I don't know what that means",
+          well_known_name, result);
+      return FALSE;
+    }
+}
+
+/**
+ * tp_dbus_daemon_get_unique_name:
+ *
+ * <!-- Returns: is enough -->
+ *
+ * Returns: the unique name of this connection to the bus, which is valid for
+ *  as long as this #TpDBusDaemon is
+ * Since: 0.7.UNRELEASED
+ */
+const gchar *
+tp_dbus_daemon_get_unique_name (TpDBusDaemon *self)
+{
+  g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), NULL);
+
+  return dbus_bus_get_unique_name (self->priv->libdbus);
+}
+
+static void
+free_daemon_list (gpointer p)
+{
+  GSList **slistp = p;
+
+  g_slist_free (*slistp);
+  g_slice_free (GSList *, slistp);
+}
+
+static GObject *
+tp_dbus_daemon_constructor (GType type,
+                            guint n_params,
+                            GObjectConstructParam *params)
+{
+  GObjectClass *object_class =
+      (GObjectClass *) tp_dbus_daemon_parent_class;
+  TpDBusDaemon *self = TP_DBUS_DAEMON (object_class->constructor (type,
+        n_params, params));
+  TpProxy *as_proxy = (TpProxy *) self;
+  GSList **daemons;
+
+  g_assert (!tp_strdiff (as_proxy->bus_name, DBUS_SERVICE_DBUS));
+  g_assert (!tp_strdiff (as_proxy->object_path, DBUS_PATH_DBUS));
+
+  self->priv->libdbus = dbus_connection_ref (
+      dbus_g_connection_get_connection (
+        tp_proxy_get_dbus_connection (self)));
+
+  /* one ref per TpDBusDaemon, released in finalize */
+  if (!dbus_connection_allocate_data_slot (&daemons_slot))
+    g_error ("Out of memory");
+
+  daemons = dbus_connection_get_data (self->priv->libdbus, daemons_slot);
+
+  if (daemons == NULL)
+    {
+      daemons = g_slice_new (GSList *);
+
+      *daemons = NULL;
+      dbus_connection_set_data (self->priv->libdbus, daemons_slot, daemons,
+          free_daemon_list);
+
+      /* we add this filter at most once per DBusConnection */
+      if (!dbus_connection_add_filter (self->priv->libdbus,
+            _tp_dbus_daemon_name_owner_changed_filter, NULL, NULL))
+        g_error ("Out of memory");
+    }
+
+  *daemons = g_slist_prepend (*daemons, self);
+
+  return (GObject *) self;
+}
+
+static void
+tp_dbus_daemon_init (TpDBusDaemon *self)
+{
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TYPE_DBUS_DAEMON,
+      TpDBusDaemonPrivate);
+
+  self->priv->name_owner_watches = g_hash_table_new_full (g_str_hash,
+      g_str_equal, g_free, NULL);
+}
+
+static void
+tp_dbus_daemon_dispose (GObject *object)
+{
+  TpDBusDaemon *self = TP_DBUS_DAEMON (object);
+  GSList **daemons;
+
+  if (self->priv->name_owner_watches != NULL)
+    {
+      GHashTable *tmp = self->priv->name_owner_watches;
+      GHashTableIter iter;
+      gpointer k, v;
+
+      self->priv->name_owner_watches = NULL;
+      g_hash_table_iter_init (&iter, tmp);
+
+      while (g_hash_table_iter_next (&iter, &k, &v))
+        {
+          _tp_dbus_daemon_stop_watching (self, k, v);
+          g_hash_table_iter_remove (&iter);
+        }
+
+      g_hash_table_destroy (tmp);
+    }
+
+  if (self->priv->libdbus != NULL)
+    {
+      /* remove myself from the list to be notified on NoC */
+      daemons = dbus_connection_get_data (self->priv->libdbus, daemons_slot);
+
+      /* should always be non-NULL, barring bugs */
+      if (G_LIKELY (daemons != NULL))
+        {
+          *daemons = g_slist_remove (*daemons, self);
+        }
+
+      dbus_connection_unref (self->priv->libdbus);
+      self->priv->libdbus = NULL;
+    }
+
+  G_OBJECT_CLASS (tp_dbus_daemon_parent_class)->dispose (object);
+}
+
+static void
+tp_dbus_daemon_finalize (GObject *object)
+{
+  GObjectFinalizeFunc chain_up = G_OBJECT_CLASS (tp_dbus_daemon_parent_class)->finalize;
+
+  /* one ref per TpDBusDaemon, from constructor */
+  dbus_connection_free_data_slot (&daemons_slot);
+
+  if (chain_up != NULL)
+    chain_up (object);
+}
+
+/**
+ * tp_dbus_daemon_init_known_interfaces:
+ *
+ * Ensure that the known interfaces for TpDBusDaemon have been set up.
+ * This is done automatically when necessary, but for correct
+ * overriding of library interfaces by local extensions, you should
+ * call this function before calling
+ * tp_proxy_or_subclass_hook_on_interface_add() with first argument
+ * %TP_TYPE_DBUS_DAEMON.
+ *
+ * Since: 0.7.32
+ */
+void
+tp_dbus_daemon_init_known_interfaces (void)
+{
+  static gsize once = 0;
+
+  if (g_once_init_enter (&once))
+    {
+      tp_proxy_init_known_interfaces ();
+      tp_proxy_or_subclass_hook_on_interface_add (TP_TYPE_DBUS_DAEMON,
+          tp_cli_dbus_daemon_add_signals);
+
+      g_once_init_leave (&once, 1);
+    }
+}
+
+static void
+tp_dbus_daemon_class_init (TpDBusDaemonClass *klass)
+{
+  TpProxyClass *proxy_class = (TpProxyClass *) klass;
+  GObjectClass *object_class = (GObjectClass *) klass;
+
+  tp_dbus_daemon_init_known_interfaces ();
+
+  g_type_class_add_private (klass, sizeof (TpDBusDaemonPrivate));
+
+  object_class->constructor = tp_dbus_daemon_constructor;
+  object_class->dispose = tp_dbus_daemon_dispose;
+  object_class->finalize = tp_dbus_daemon_finalize;
+
+  proxy_class->interface = TP_IFACE_QUARK_DBUS_DAEMON;
+}
+
+/* Auto-generated implementation of _tp_register_dbus_glib_marshallers */
+#include "_gen/register-dbus-glib-marshallers-body.h"
diff --git a/telepathy-glib/dbus-internal.h b/telepathy-glib/dbus-internal.h
index 8465c6f..883e69b 100644
--- a/telepathy-glib/dbus-internal.h
+++ b/telepathy-glib/dbus-internal.h
@@ -31,6 +31,8 @@ gboolean _tp_dbus_daemon_get_name_owner (TpDBusDaemon *self, gint timeout_ms,
 
 void _tp_register_dbus_glib_marshallers (void);
 
+DBusGConnection *_tp_dbus_starter_bus_conn (GError **error);
+
 G_END_DECLS
 
 #endif /* __TP_INTERNAL_DBUS_GLIB_H__ */
diff --git a/telepathy-glib/dbus.c b/telepathy-glib/dbus.c
index d833509..f08e36e 100644
--- a/telepathy-glib/dbus.c
+++ b/telepathy-glib/dbus.c
@@ -58,22 +58,12 @@
 #include <string.h>
 
 #include <dbus/dbus.h>
-#include <dbus/dbus-glib-lowlevel.h>
 
 #include <gobject/gvaluecollector.h>
 
 #include <telepathy-glib/errors.h>
-#include <telepathy-glib/interfaces.h>
-#include <telepathy-glib/proxy-subclass.h>
 #include <telepathy-glib/util.h>
 
-#include "telepathy-glib/_gen/signals-marshal.h"
-
-#include "telepathy-glib/_gen/tp-cli-dbus-daemon-body.h"
-
-#define DEBUG_FLAG TP_DEBUG_PROXY
-#include "debug-internal.h"
-
 /**
  * tp_asv_size:
  * @asv: a GHashTable
@@ -102,8 +92,8 @@ tp_dbus_g_method_return_not_implemented (DBusGMethodInvocation *context)
   dbus_g_method_return_error (context, &e);
 }
 
-static DBusGConnection *
-starter_bus_conn (GError **error)
+DBusGConnection *
+_tp_dbus_starter_bus_conn (GError **error)
 {
   static DBusGConnection *starter_bus = NULL;
 
@@ -136,7 +126,7 @@ DBusGConnection *
 tp_get_bus (void)
 {
   GError *error = NULL;
-  DBusGConnection *bus = starter_bus_conn (&error);
+  DBusGConnection *bus = _tp_dbus_starter_bus_conn (&error);
 
   if (bus == NULL)
     {
@@ -578,1067 +568,6 @@ tp_dbus_check_valid_object_path (const gchar *path, GError **error)
 }
 
 /**
- * TpDBusDaemonClass:
- *
- * The class of #TpDBusDaemon.
- *
- * Since: 0.7.1
- */
-struct _TpDBusDaemonClass
-{
-  /*<private>*/
-  TpProxyClass parent_class;
-  gpointer priv;
-};
-
-/**
- * TpDBusDaemon:
- *
- * A subclass of #TpProxy that represents the D-Bus daemon. It mainly provides
- * functionality to manage well-known names on the bus.
- *
- * Since: 0.7.1
- */
-struct _TpDBusDaemon
-{
-  /*<private>*/
-  TpProxy parent;
-
-  TpDBusDaemonPrivate *priv;
-};
-
-struct _TpDBusDaemonPrivate
-{
-  /* dup'd name => _NameOwnerWatch */
-  GHashTable *name_owner_watches;
-  /* reffed */
-  DBusConnection *libdbus;
-};
-
-G_DEFINE_TYPE (TpDBusDaemon, tp_dbus_daemon, TP_TYPE_PROXY);
-
-static gpointer starter_bus_daemon = NULL;
-
-/**
- * tp_dbus_daemon_dup:
- * @error: Used to indicate error if %NULL is returned
- *
- * Returns a proxy for signals and method calls on the D-Bus daemon on which
- * this process was activated (if it was launched by D-Bus service
- * activation), or the session bus (otherwise).
- *
- * If it is not possible to connect to the appropriate bus, raise an error
- * and return %NULL.
- *
- * The returned #TpDBusDaemon is cached; the same #TpDBusDaemon object will
- * be returned by this function repeatedly, as long as at least one reference
- * exists.
- *
- * Returns: a reference to a proxy for signals and method calls on the bus
- *  daemon, or %NULL
- *
- * Since: 0.7.26
- */
-TpDBusDaemon *
-tp_dbus_daemon_dup (GError **error)
-{
-  DBusGConnection *conn;
-
-  if (starter_bus_daemon != NULL)
-    return g_object_ref (starter_bus_daemon);
-
-  conn = starter_bus_conn (error);
-
-  if (conn == NULL)
-    return NULL;
-
-  starter_bus_daemon = tp_dbus_daemon_new (conn);
-  g_assert (starter_bus_daemon != NULL);
-  g_object_add_weak_pointer (starter_bus_daemon, &starter_bus_daemon);
-
-  return starter_bus_daemon;
-}
-
-/**
- * tp_dbus_daemon_new:
- * @connection: a connection to D-Bus
- *
- * Returns a proxy for signals and method calls on a particular bus
- * connection.
- *
- * Use tp_dbus_daemon_dup() instead if you just want a connection to the
- * starter or session bus (which is almost always the right thing for
- * Telepathy).
- *
- * Returns: a new proxy for signals and method calls on the bus daemon
- *  to which @connection is connected
- *
- * Since: 0.7.1
- */
-TpDBusDaemon *
-tp_dbus_daemon_new (DBusGConnection *connection)
-{
-  g_return_val_if_fail (connection != NULL, NULL);
-
-  return TP_DBUS_DAEMON (g_object_new (TP_TYPE_DBUS_DAEMON,
-        "dbus-connection", connection,
-        "bus-name", DBUS_SERVICE_DBUS,
-        "object-path", DBUS_PATH_DBUS,
-        NULL));
-}
-
-typedef struct
-{
-  TpDBusDaemonNameOwnerChangedCb callback;
-  gpointer user_data;
-  GDestroyNotify destroy;
-  gchar *last_owner;
-} _NameOwnerWatch;
-
-typedef struct
-{
-  TpDBusDaemonNameOwnerChangedCb callback;
-  gpointer user_data;
-  GDestroyNotify destroy;
-} _NameOwnerSubWatch;
-
-static void
-_tp_dbus_daemon_name_owner_changed_multiple (TpDBusDaemon *self,
-                                             const gchar *name,
-                                             const gchar *new_owner,
-                                             gpointer user_data)
-{
-  GArray *array = user_data;
-  guint i;
-
-  for (i = 0; i < array->len; i++)
-    {
-      _NameOwnerSubWatch *watch = &g_array_index (array, _NameOwnerSubWatch,
-          i);
-
-      watch->callback (self, name, new_owner, watch->user_data);
-    }
-}
-
-static void
-_tp_dbus_daemon_name_owner_changed_multiple_free (gpointer data)
-{
-  GArray *array = data;
-  guint i;
-
-  for (i = 0; i < array->len; i++)
-    {
-      _NameOwnerSubWatch *watch = &g_array_index (array, _NameOwnerSubWatch,
-          i);
-
-      if (watch->destroy)
-        watch->destroy (watch->user_data);
-    }
-
-  g_array_free (array, TRUE);
-}
-
-static void
-_tp_dbus_daemon_name_owner_changed (TpDBusDaemon *self,
-                                    const gchar *name,
-                                    const gchar *new_owner)
-{
-  _NameOwnerWatch *watch = g_hash_table_lookup (self->priv->name_owner_watches,
-      name);
-
-  DEBUG ("%s -> %s", name, new_owner);
-
-  if (watch == NULL)
-    return;
-
-  /* This is partly to handle the case where an owner change happens
-   * while GetNameOwner is in flight, partly to be able to optimize by only
-   * calling GetNameOwner if we didn't already know, and partly because of a
-   * dbus-glib bug that means we get every signal twice
-   * (it thinks org.freedesktop.DBus is both a well-known name and a unique
-   * name). */
-  if (!tp_strdiff (watch->last_owner, new_owner))
-    return;
-
-  g_free (watch->last_owner);
-  watch->last_owner = g_strdup (new_owner);
-
-  watch->callback (self, name, new_owner, watch->user_data);
-}
-
-static dbus_int32_t daemons_slot = -1;
-
-typedef struct {
-    DBusConnection *libdbus;
-    DBusMessage *message;
-} NOCIdleContext;
-
-static NOCIdleContext *
-noc_idle_context_new (DBusConnection *libdbus,
-                      DBusMessage *message)
-{
-  NOCIdleContext *context = g_slice_new (NOCIdleContext);
-
-  context->libdbus = dbus_connection_ref (libdbus);
-  context->message = dbus_message_ref (message);
-  return context;
-}
-
-static void
-noc_idle_context_free (gpointer data)
-{
-  NOCIdleContext *context = data;
-
-  dbus_connection_unref (context->libdbus);
-  dbus_message_unref (context->message);
-  g_slice_free (NOCIdleContext, context);
-}
-
-static gboolean
-noc_idle_context_invoke (gpointer data)
-{
-  NOCIdleContext *context = data;
-  const gchar *name;
-  const gchar *old_owner;
-  const gchar *new_owner;
-  DBusError dbus_error = DBUS_ERROR_INIT;
-  GSList **daemons;
-
-  if (daemons_slot == -1)
-    return FALSE;
-
-  if (!dbus_message_get_args (context->message, &dbus_error,
-        DBUS_TYPE_STRING, &name,
-        DBUS_TYPE_STRING, &old_owner,
-        DBUS_TYPE_STRING, &new_owner,
-        DBUS_TYPE_INVALID))
-    {
-      DEBUG ("Couldn't unpack NameOwnerChanged(s, s, s): %s: %s",
-          dbus_error.name, dbus_error.message);
-      dbus_error_free (&dbus_error);
-      return FALSE;
-    }
-
-  daemons = dbus_connection_get_data (context->libdbus, daemons_slot);
-
-  DEBUG ("NameOwnerChanged(%s, %s -> %s)", name, old_owner, new_owner);
-
-  /* should always be non-NULL, barring bugs */
-  if (G_LIKELY (daemons != NULL))
-    {
-      GSList *iter;
-
-      for (iter = *daemons; iter != NULL; iter = iter->next)
-        _tp_dbus_daemon_name_owner_changed (iter->data, name, new_owner);
-    }
-
-  return FALSE;
-}
-
-static DBusHandlerResult
-_tp_dbus_daemon_name_owner_changed_filter (DBusConnection *libdbus,
-                                           DBusMessage *message,
-                                           void *unused G_GNUC_UNUSED)
-{
-  /* We have to do the real work in an idle, so we don't break re-entrant
-   * calls (the dbus-glib event source isn't re-entrant) */
-  if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
-        "NameOwnerChanged") &&
-      dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
-    g_idle_add_full (G_PRIORITY_HIGH, noc_idle_context_invoke,
-        noc_idle_context_new (libdbus, message),
-        noc_idle_context_free);
-
-  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-typedef struct {
-    TpDBusDaemon *self;
-    gchar *name;
-    DBusMessage *reply;
-    gsize refs;
-} GetNameOwnerContext;
-
-static GetNameOwnerContext *
-get_name_owner_context_new (TpDBusDaemon *self,
-                            const gchar *name)
-{
-  GetNameOwnerContext *context = g_slice_new (GetNameOwnerContext);
-
-  context->self = g_object_ref (self);
-  context->name = g_strdup (name);
-  context->reply = NULL;
-  DEBUG ("New, 1 ref");
-  context->refs = 1;
-  return context;
-}
-
-static void
-get_name_owner_context_unref (gpointer data)
-{
-  GetNameOwnerContext *context = data;
-
-  DEBUG ("%lu -> %lu", (gulong) context->refs, (gulong) (context->refs-1));
-
-  if (--context->refs == 0)
-    {
-      g_object_unref (context->self);
-      g_free (context->name);
-
-      if (context->reply != NULL)
-        dbus_message_unref (context->reply);
-
-      g_slice_free (GetNameOwnerContext, context);
-    }
-}
-
-static gboolean
-_tp_dbus_daemon_get_name_owner_idle (gpointer data)
-{
-  GetNameOwnerContext *context = data;
-  const gchar *owner = "";
-
-  if (context->reply == NULL)
-    {
-      DEBUG ("Connection disconnected or no reply to GetNameOwner(%s)",
-          context->name);
-    }
-  else if (dbus_message_get_type (context->reply) ==
-      DBUS_MESSAGE_TYPE_METHOD_RETURN)
-    {
-      if (!dbus_message_get_args (context->reply, NULL,
-            DBUS_TYPE_STRING, &owner,
-            DBUS_TYPE_INVALID))
-        {
-          DEBUG ("Malformed reply from GetNameOwner(%s), assuming no owner",
-              context->name);
-        }
-    }
-  else
-    {
-      if (DEBUGGING)
-        {
-          DBusError error = DBUS_ERROR_INIT;
-
-          if (dbus_set_error_from_message (&error, context->reply))
-            {
-              DEBUG ("GetNameOwner(%s) raised %s: %s", context->name,
-                  error.name, error.message);
-              dbus_error_free (&error);
-            }
-          else
-            {
-              DEBUG ("Unexpected message type from GetNameOwner(%s)",
-                  context->name);
-            }
-        }
-    }
-
-  _tp_dbus_daemon_name_owner_changed (context->self, context->name, owner);
-
-  return FALSE;
-}
-
-/**
- * TpDBusDaemonNameOwnerChangedCb:
- * @bus_daemon: The D-Bus daemon
- * @name: The name whose ownership has changed or been discovered
- * @new_owner: The unique name that now owns @name
- * @user_data: Arbitrary user-supplied data as passed to
- *  tp_dbus_daemon_watch_name_owner()
- *
- * The signature of the callback called by tp_dbus_daemon_watch_name_owner().
- *
- * Since: 0.7.1
- */
-
-static inline gchar *
-_tp_dbus_daemon_get_noc_rule (const gchar *name)
-{
-  return g_strdup_printf ("type='signal',"
-      "sender='" DBUS_SERVICE_DBUS "',"
-      "path='" DBUS_PATH_DBUS "',"
-      "interface='"DBUS_INTERFACE_DBUS "',"
-      "member='NameOwnerChanged',"
-      "arg0='%s'", name);
-}
-
-static void
-_tp_dbus_daemon_get_name_owner_notify (DBusPendingCall *pc,
-                                       gpointer data)
-{
-  GetNameOwnerContext *context = data;
-
-  /* we recycle this function for the case where the connection is already
-   * disconnected: in that case we use pc = NULL */
-  if (pc != NULL)
-    context->reply = dbus_pending_call_steal_reply (pc);
-
-  /* We have to do the real work in an idle, so we don't break re-entrant
-   * calls (the dbus-glib event source isn't re-entrant) */
-  DEBUG ("%lu -> %lu", (gulong) context->refs, (gulong) (context->refs + 1));
-  context->refs++;
-  g_idle_add_full (G_PRIORITY_HIGH, _tp_dbus_daemon_get_name_owner_idle,
-      context, get_name_owner_context_unref);
-
-  if (pc != NULL)
-    dbus_pending_call_unref (pc);
-}
-
-/**
- * tp_dbus_daemon_watch_name_owner:
- * @self: The D-Bus daemon
- * @name: The name whose ownership is to be watched
- * @callback: Callback to call when the ownership is discovered or changes
- * @user_data: Arbitrary data to pass to @callback
- * @destroy: Called to destroy @user_data when the name owner watch is
- *  cancelled due to tp_dbus_daemon_cancel_name_owner_watch()
- *
- * Arrange for @callback to be called with the owner of @name as soon as
- * possible (which might even be before this function returns!), then
- * again every time the ownership of @name changes.
- *
- * If multiple watches are registered for the same @name, they will be called
- * in the order they were registered.
- *
- * Since: 0.7.1
- */
-void
-tp_dbus_daemon_watch_name_owner (TpDBusDaemon *self,
-                                 const gchar *name,
-                                 TpDBusDaemonNameOwnerChangedCb callback,
-                                 gpointer user_data,
-                                 GDestroyNotify destroy)
-{
-  _NameOwnerWatch *watch = g_hash_table_lookup (self->priv->name_owner_watches,
-      name);
-
-  g_return_if_fail (TP_IS_DBUS_DAEMON (self));
-  g_return_if_fail (tp_dbus_check_valid_bus_name (name,
-        TP_DBUS_NAME_TYPE_ANY, NULL));
-  g_return_if_fail (name != NULL);
-  g_return_if_fail (callback != NULL);
-
-  if (watch == NULL)
-    {
-      gchar *match_rule;
-      DBusMessage *message;
-      DBusPendingCall *pc = NULL;
-      GetNameOwnerContext *context = get_name_owner_context_new (self, name);
-
-      /* Allocate a single watch (common case) */
-      watch = g_slice_new (_NameOwnerWatch);
-      watch->callback = callback;
-      watch->user_data = user_data;
-      watch->destroy = destroy;
-      watch->last_owner = NULL;
-
-      g_hash_table_insert (self->priv->name_owner_watches, g_strdup (name),
-          watch);
-
-      /* We want to be notified about name owner changes for this one.
-       * Assume the match addition will succeed; there's no good way to cope
-       * with failure here... */
-      match_rule = _tp_dbus_daemon_get_noc_rule (name);
-      DEBUG ("Adding match rule %s", match_rule);
-      dbus_bus_add_match (self->priv->libdbus, match_rule, NULL);
-
-      message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
-          DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner");
-
-      if (message == NULL)
-        g_error ("Out of memory");
-
-      /* We already checked that @name was in (a small subset of) UTF-8,
-       * so OOM is the only thing that can go wrong. The use of &name here
-       * is because libdbus is strange. */
-      if (!dbus_message_append_args (message,
-            DBUS_TYPE_STRING, &name,
-            DBUS_TYPE_INVALID))
-        g_error ("Out of memory");
-
-      if (!dbus_connection_send_with_reply (self->priv->libdbus,
-          message, &pc, -1))
-        g_error ("Out of memory");
-      /* pc is unreffed by _tp_dbus_daemon_get_name_owner_notify */
-
-      if (pc == NULL || dbus_pending_call_get_completed (pc))
-        {
-          /* pc can be NULL when the connection is already disconnected */
-          _tp_dbus_daemon_get_name_owner_notify (pc, context);
-          get_name_owner_context_unref (context);
-        }
-      else if (!dbus_pending_call_set_notify (pc,
-            _tp_dbus_daemon_get_name_owner_notify,
-            context, get_name_owner_context_unref))
-        {
-          g_error ("Out of memory");
-        }
-    }
-  else
-    {
-      _NameOwnerSubWatch tmp = { callback, user_data, destroy };
-
-      if (watch->callback == _tp_dbus_daemon_name_owner_changed_multiple)
-        {
-          /* The watch is already a "multiplexer", just append to it */
-          GArray *array = watch->user_data;
-
-          g_array_append_val (array, tmp);
-        }
-      else
-        {
-          /* Replace the old contents of the watch with one that dispatches
-           * the signal to (potentially) more than one watcher */
-          GArray *array = g_array_sized_new (FALSE, FALSE,
-              sizeof (_NameOwnerSubWatch), 2);
-
-          /* The new watcher */
-          g_array_append_val (array, tmp);
-          /* The old watcher */
-          tmp.callback = watch->callback;
-          tmp.user_data = watch->user_data;
-          tmp.destroy = watch->destroy;
-          g_array_prepend_val (array, tmp);
-
-          watch->callback = _tp_dbus_daemon_name_owner_changed_multiple;
-          watch->user_data = array;
-          watch->destroy = _tp_dbus_daemon_name_owner_changed_multiple_free;
-        }
-
-      if (watch->last_owner != NULL)
-        {
-          /* FIXME: should avoid reentrancy? */
-          callback (self, name, watch->last_owner, user_data);
-        }
-    }
-}
-
-static void
-_tp_dbus_daemon_stop_watching (TpDBusDaemon *self,
-                               const gchar *name,
-                               _NameOwnerWatch *watch)
-{
-  gchar *match_rule;
-
-  if (watch->destroy)
-    watch->destroy (watch->user_data);
-
-  g_free (watch->last_owner);
-  g_slice_free (_NameOwnerWatch, watch);
-
-  match_rule = _tp_dbus_daemon_get_noc_rule (name);
-  DEBUG ("Removing match rule %s", match_rule);
-  dbus_bus_remove_match (self->priv->libdbus, match_rule, NULL);
-  g_free (match_rule);
-}
-
-/**
- * tp_dbus_daemon_cancel_name_owner_watch:
- * @self: the D-Bus daemon
- * @name: the name that was being watched
- * @callback: the callback that was called
- * @user_data: the user data that was provided
- *
- * If there was a previous call to tp_dbus_daemon_watch_name_owner()
- * with exactly the given @name, @callback and @user_data, remove it.
- *
- * If more than one watch matching the details provided was active, remove
- * only the most recently added one.
- *
- * Returns: %TRUE if there was such a watch, %FALSE otherwise
- *
- * Since: 0.7.1
- */
-gboolean
-tp_dbus_daemon_cancel_name_owner_watch (TpDBusDaemon *self,
-                                        const gchar *name,
-                                        TpDBusDaemonNameOwnerChangedCb callback,
-                                        gconstpointer user_data)
-{
-  _NameOwnerWatch *watch = g_hash_table_lookup (self->priv->name_owner_watches,
-      name);
-
-  g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
-  g_return_val_if_fail (name != NULL, FALSE);
-  g_return_val_if_fail (callback != NULL, FALSE);
-
-  if (watch == NULL)
-    {
-      /* No watch at all */
-      return FALSE;
-    }
-  else if (watch->callback == callback && watch->user_data == user_data)
-    {
-      /* Simple case: there is one name-owner watch and it's what we wanted */
-      _tp_dbus_daemon_stop_watching (self, name, watch);
-      g_hash_table_remove (self->priv->name_owner_watches, name);
-      return TRUE;
-    }
-  else if (watch->callback == _tp_dbus_daemon_name_owner_changed_multiple)
-    {
-      /* Complicated case: this watch is a "multiplexer", we need to check
-       * its contents */
-      GArray *array = watch->user_data;
-      guint i;
-
-      for (i = 1; i <= array->len; i++)
-        {
-          _NameOwnerSubWatch *entry = &g_array_index (array,
-              _NameOwnerSubWatch, array->len - i);
-
-          if (entry->callback == callback && entry->user_data == user_data)
-            {
-              if (entry->destroy != NULL)
-                entry->destroy (entry->user_data);
-
-              g_array_remove_index (array, array->len - i);
-
-              if (array->len == 0)
-                {
-                  _tp_dbus_daemon_stop_watching (self, name, watch);
-                  g_hash_table_remove (self->priv->name_owner_watches, name);
-                }
-
-              return TRUE;
-            }
-        }
-    }
-
-  /* We haven't found it */
-  return FALSE;
-}
-
-/* for internal use (TpChannel, TpConnection _new convenience functions) */
-gboolean
-_tp_dbus_daemon_get_name_owner (TpDBusDaemon *self,
-                                gint timeout_ms,
-                                const gchar *well_known_name,
-                                gchar **unique_name,
-                                GError **error)
-{
-  DBusGConnection *gconn;
-  DBusConnection *dbc;
-  DBusMessage *message;
-  DBusMessage *reply;
-  DBusError dbus_error;
-  const char *name_in_reply;
-  const GError *invalidated;
-
-  g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
-  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
-  invalidated = tp_proxy_get_invalidated (self);
-
-  if (invalidated != NULL)
-    {
-      if (error != NULL)
-        *error = g_error_copy (invalidated);
-
-      return FALSE;
-    }
-
-  gconn = tp_proxy_get_dbus_connection (self);
-  dbc = dbus_g_connection_get_connection (gconn);
-
-  message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
-      DBUS_INTERFACE_DBUS, "GetNameOwner");
-
-  if (message == NULL)
-    g_error ("Out of memory");
-
-  if (!dbus_message_append_args (message,
-        DBUS_TYPE_STRING, &well_known_name,
-        DBUS_TYPE_INVALID))
-    g_error ("Out of memory");
-
-  dbus_error_init (&dbus_error);
-  reply = dbus_connection_send_with_reply_and_block (dbc, message,
-      timeout_ms, &dbus_error);
-
-  dbus_message_unref (message);
-
-  if (reply == NULL)
-    {
-      if (!tp_strdiff (dbus_error.name, DBUS_ERROR_NO_MEMORY))
-        g_error ("Out of memory");
-
-      /* FIXME: ideally we'd use dbus-glib's error mapping for this */
-      g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_NAME_OWNER_LOST,
-          "%s: %s", dbus_error.name, dbus_error.message);
-
-      dbus_error_free (&dbus_error);
-      return FALSE;
-    }
-
-  if (!dbus_message_get_args (reply, &dbus_error,
-        DBUS_TYPE_STRING, &name_in_reply,
-        DBUS_TYPE_INVALID))
-    {
-      g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_NAME_OWNER_LOST,
-          "%s: %s", dbus_error.name, dbus_error.message);
-
-      dbus_error_free (&dbus_error);
-      dbus_message_unref (reply);
-      return FALSE;
-    }
-
-  if (unique_name != NULL)
-    *unique_name = g_strdup (name_in_reply);
-
-  dbus_message_unref (reply);
-
-  return TRUE;
-}
-
-/**
- * tp_dbus_daemon_request_name:
- * @self: a TpDBusDaemon
- * @well_known_name: a well-known name to acquire
- * @idempotent: whether to consider it to be a success if this process
- *              already owns the name
- * @error: used to raise an error if %FALSE is returned
- *
- * Claim the given well-known name without queueing, allowing replacement
- * or replacing an existing name-owner. This makes a synchronous call to the
- * bus daemon.
- *
- * Returns: %TRUE if @well_known_name was claimed, or %FALSE and sets @error if
- *          an error occurred.
- *
- * Since: 0.7.30
- */
-gboolean
-tp_dbus_daemon_request_name (TpDBusDaemon *self,
-                             const gchar *well_known_name,
-                             gboolean idempotent,
-                             GError **error)
-{
-  TpProxy *as_proxy = (TpProxy *) self;
-  DBusGConnection *gconn;
-  DBusConnection *dbc;
-  DBusError dbus_error;
-  int result;
-  const GError *invalidated;
-
-  g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
-  g_return_val_if_fail (tp_dbus_check_valid_bus_name (well_known_name,
-        TP_DBUS_NAME_TYPE_WELL_KNOWN, error), FALSE);
-  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
-  invalidated = tp_proxy_get_invalidated (self);
-
-  if (invalidated != NULL)
-    {
-      if (error != NULL)
-        *error = g_error_copy (invalidated);
-
-      return FALSE;
-    }
-
-  gconn = as_proxy->dbus_connection;
-  dbc = dbus_g_connection_get_connection (gconn);
-
-  dbus_error_init (&dbus_error);
-  result = dbus_bus_request_name (dbc, well_known_name,
-      DBUS_NAME_FLAG_DO_NOT_QUEUE, &dbus_error);
-
-  switch (result)
-    {
-    case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
-      return TRUE;
-
-    case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
-      if (idempotent)
-        {
-          return TRUE;
-        }
-      else
-        {
-          g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
-              "Name '%s' already in use by this process", well_known_name);
-          return FALSE;
-        }
-
-    case DBUS_REQUEST_NAME_REPLY_EXISTS:
-    case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
-      /* the latter shouldn't actually happen since we said DO_NOT_QUEUE */
-      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
-          "Name '%s' already in use by another process", well_known_name);
-      return FALSE;
-
-    case -1:
-      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
-          "%s: %s", dbus_error.name, dbus_error.message);
-      dbus_error_free (&dbus_error);
-      return FALSE;
-
-    default:
-      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
-          "RequestName('%s') returned %d and I don't know what that means",
-          well_known_name, result);
-      return FALSE;
-    }
-}
-
-/**
- * tp_dbus_daemon_release_name:
- * @self: a TpDBusDaemon
- * @well_known_name: a well-known name owned by this process to release
- * @error: used to raise an error if %FALSE is returned
- *
- * Release the given well-known name. This makes a synchronous call to the bus
- * daemon.
- *
- * Returns: %TRUE if @well_known_name was released, or %FALSE and sets @error
- *          if an error occurred.
- *
- * Since: 0.7.30
- */
-gboolean
-tp_dbus_daemon_release_name (TpDBusDaemon *self,
-                             const gchar *well_known_name,
-                             GError **error)
-{
-  TpProxy *as_proxy = (TpProxy *) self;
-  DBusGConnection *gconn;
-  DBusConnection *dbc;
-  DBusError dbus_error;
-  int result;
-  const GError *invalidated;
-
-  g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
-  g_return_val_if_fail (tp_dbus_check_valid_bus_name (well_known_name,
-        TP_DBUS_NAME_TYPE_WELL_KNOWN, error), FALSE);
-  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
-  invalidated = tp_proxy_get_invalidated (self);
-
-  if (invalidated != NULL)
-    {
-      if (error != NULL)
-        *error = g_error_copy (invalidated);
-
-      return FALSE;
-    }
-
-  gconn = as_proxy->dbus_connection;
-  dbc = dbus_g_connection_get_connection (gconn);
-  dbus_error_init (&dbus_error);
-  result = dbus_bus_release_name (dbc, well_known_name, &dbus_error);
-
-  switch (result)
-    {
-    case DBUS_RELEASE_NAME_REPLY_RELEASED:
-      return TRUE;
-
-    case DBUS_RELEASE_NAME_REPLY_NOT_OWNER:
-      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_YOURS,
-          "Name '%s' owned by another process", well_known_name);
-      return FALSE;
-
-    case DBUS_RELEASE_NAME_REPLY_NON_EXISTENT:
-      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
-          "Name '%s' not owned", well_known_name);
-      return FALSE;
-
-    case -1:
-      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
-          "%s: %s", dbus_error.name, dbus_error.message);
-      dbus_error_free (&dbus_error);
-      return FALSE;
-
-    default:
-      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
-          "ReleaseName('%s') returned %d and I don't know what that means",
-          well_known_name, result);
-      return FALSE;
-    }
-}
-
-/**
- * tp_dbus_daemon_get_unique_name:
- *
- * <!-- Returns: is enough -->
- *
- * Returns: the unique name of this connection to the bus, which is valid for
- *  as long as this #TpDBusDaemon is
- * Since: 0.7.UNRELEASED
- */
-const gchar *
-tp_dbus_daemon_get_unique_name (TpDBusDaemon *self)
-{
-  g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), NULL);
-
-  return dbus_bus_get_unique_name (self->priv->libdbus);
-}
-
-static void
-free_daemon_list (gpointer p)
-{
-  GSList **slistp = p;
-
-  g_slist_free (*slistp);
-  g_slice_free (GSList *, slistp);
-}
-
-static GObject *
-tp_dbus_daemon_constructor (GType type,
-                            guint n_params,
-                            GObjectConstructParam *params)
-{
-  GObjectClass *object_class =
-      (GObjectClass *) tp_dbus_daemon_parent_class;
-  TpDBusDaemon *self = TP_DBUS_DAEMON (object_class->constructor (type,
-        n_params, params));
-  TpProxy *as_proxy = (TpProxy *) self;
-  GSList **daemons;
-
-  g_assert (!tp_strdiff (as_proxy->bus_name, DBUS_SERVICE_DBUS));
-  g_assert (!tp_strdiff (as_proxy->object_path, DBUS_PATH_DBUS));
-
-  self->priv->libdbus = dbus_connection_ref (
-      dbus_g_connection_get_connection (
-        tp_proxy_get_dbus_connection (self)));
-
-  /* one ref per TpDBusDaemon, released in finalize */
-  if (!dbus_connection_allocate_data_slot (&daemons_slot))
-    g_error ("Out of memory");
-
-  daemons = dbus_connection_get_data (self->priv->libdbus, daemons_slot);
-
-  if (daemons == NULL)
-    {
-      daemons = g_slice_new (GSList *);
-
-      *daemons = NULL;
-      dbus_connection_set_data (self->priv->libdbus, daemons_slot, daemons,
-          free_daemon_list);
-
-      /* we add this filter at most once per DBusConnection */
-      if (!dbus_connection_add_filter (self->priv->libdbus,
-            _tp_dbus_daemon_name_owner_changed_filter, NULL, NULL))
-        g_error ("Out of memory");
-    }
-
-  *daemons = g_slist_prepend (*daemons, self);
-
-  return (GObject *) self;
-}
-
-static void
-tp_dbus_daemon_init (TpDBusDaemon *self)
-{
-  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TYPE_DBUS_DAEMON,
-      TpDBusDaemonPrivate);
-
-  self->priv->name_owner_watches = g_hash_table_new_full (g_str_hash,
-      g_str_equal, g_free, NULL);
-}
-
-static void
-tp_dbus_daemon_dispose (GObject *object)
-{
-  TpDBusDaemon *self = TP_DBUS_DAEMON (object);
-  GSList **daemons;
-
-  if (self->priv->name_owner_watches != NULL)
-    {
-      GHashTable *tmp = self->priv->name_owner_watches;
-      GHashTableIter iter;
-      gpointer k, v;
-
-      self->priv->name_owner_watches = NULL;
-      g_hash_table_iter_init (&iter, tmp);
-
-      while (g_hash_table_iter_next (&iter, &k, &v))
-        {
-          _tp_dbus_daemon_stop_watching (self, k, v);
-          g_hash_table_iter_remove (&iter);
-        }
-
-      g_hash_table_destroy (tmp);
-    }
-
-  if (self->priv->libdbus != NULL)
-    {
-      /* remove myself from the list to be notified on NoC */
-      daemons = dbus_connection_get_data (self->priv->libdbus, daemons_slot);
-
-      /* should always be non-NULL, barring bugs */
-      if (G_LIKELY (daemons != NULL))
-        {
-          *daemons = g_slist_remove (*daemons, self);
-        }
-
-      dbus_connection_unref (self->priv->libdbus);
-      self->priv->libdbus = NULL;
-    }
-
-  G_OBJECT_CLASS (tp_dbus_daemon_parent_class)->dispose (object);
-}
-
-static void
-tp_dbus_daemon_finalize (GObject *object)
-{
-  GObjectFinalizeFunc chain_up = G_OBJECT_CLASS (tp_dbus_daemon_parent_class)->finalize;
-
-  /* one ref per TpDBusDaemon, from constructor */
-  dbus_connection_free_data_slot (&daemons_slot);
-
-  if (chain_up != NULL)
-    chain_up (object);
-}
-
-/**
- * tp_dbus_daemon_init_known_interfaces:
- *
- * Ensure that the known interfaces for TpDBusDaemon have been set up.
- * This is done automatically when necessary, but for correct
- * overriding of library interfaces by local extensions, you should
- * call this function before calling
- * tp_proxy_or_subclass_hook_on_interface_add() with first argument
- * %TP_TYPE_DBUS_DAEMON.
- *
- * Since: 0.7.32
- */
-void
-tp_dbus_daemon_init_known_interfaces (void)
-{
-  static gsize once = 0;
-
-  if (g_once_init_enter (&once))
-    {
-      tp_proxy_init_known_interfaces ();
-      tp_proxy_or_subclass_hook_on_interface_add (TP_TYPE_DBUS_DAEMON,
-          tp_cli_dbus_daemon_add_signals);
-
-      g_once_init_leave (&once, 1);
-    }
-}
-
-static void
-tp_dbus_daemon_class_init (TpDBusDaemonClass *klass)
-{
-  TpProxyClass *proxy_class = (TpProxyClass *) klass;
-  GObjectClass *object_class = (GObjectClass *) klass;
-
-  tp_dbus_daemon_init_known_interfaces ();
-
-  g_type_class_add_private (klass, sizeof (TpDBusDaemonPrivate));
-
-  object_class->constructor = tp_dbus_daemon_constructor;
-  object_class->dispose = tp_dbus_daemon_dispose;
-  object_class->finalize = tp_dbus_daemon_finalize;
-
-  proxy_class->interface = TP_IFACE_QUARK_DBUS_DAEMON;
-}
-
-/* Auto-generated implementation of _tp_register_dbus_glib_marshallers */
-#include "_gen/register-dbus-glib-marshallers-body.h"
-
-
-/**
  * tp_g_value_slice_new_bytes:
  * @length: number of bytes to copy
  * @bytes: location of an array of bytes to be copied (this may be %NULL
-- 
1.5.6.5




More information about the telepathy-commits mailing list