[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