[glib/gdbus-codegen] Start merging gdbus-codegen code
- From: David Zeuthen <davidz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/gdbus-codegen] Start merging gdbus-codegen code
- Date: Fri, 8 Apr 2011 19:51:00 +0000 (UTC)
commit 94b907134426e26393a86630dae5ce53baee6ae6
Author: David Zeuthen <davidz redhat com>
Date: Fri Apr 8 15:14:47 2011 -0400
Start merging gdbus-codegen code
Signed-off-by: David Zeuthen <davidz redhat com>
gio/Makefile.am | 16 +
gio/gdbusauthobserver.c | 17 +-
gio/gdbusinterface.c | 410 +++++++++++
gio/gdbusinterface.h | 79 ++
gio/gdbusinterfacestub.c | 693 ++++++++++++++++++
gio/gdbusinterfacestub.h | 105 +++
gio/gdbusobject.c | 191 +++++
gio/gdbusobject.h | 95 +++
gio/gdbusobjectmanager.c | 216 ++++++
gio/gdbusobjectmanager.h | 89 +++
gio/gdbusobjectmanagerclient.c | 1575 ++++++++++++++++++++++++++++++++++++++++
gio/gdbusobjectmanagerclient.h | 129 ++++
gio/gdbusobjectmanagerserver.c | 898 +++++++++++++++++++++++
gio/gdbusobjectmanagerserver.h | 80 ++
gio/gdbusobjectproxy.c | 315 ++++++++
gio/gdbusobjectproxy.h | 72 ++
gio/gdbusobjectstub.c | 475 ++++++++++++
gio/gdbusobjectstub.h | 87 +++
gio/gdbusprivate.c | 18 +
gio/gdbusprivate.h | 20 +-
gio/gdbusproxy.c | 36 +
gio/gio-marshal.list | 3 +
gio/gio.h | 8 +
gio/gio.symbols | 96 +++
gio/gioenums.h | 36 +
gio/giotypes.h | 33 +
26 files changed, 5774 insertions(+), 18 deletions(-)
---
diff --git a/gio/Makefile.am b/gio/Makefile.am
index e2fcd7e..318c22c 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -82,6 +82,14 @@ gdbus_headers = \
gdbusintrospection.h \
gdbusmethodinvocation.h \
gdbusserver.h \
+ gdbusinterface.h \
+ gdbusinterfacestub.h \
+ gdbusobject.h \
+ gdbusobjectstub.h \
+ gdbusobjectproxy.h \
+ gdbusobjectmanager.h \
+ gdbusobjectmanagerclient.h \
+ gdbusobjectmanagerserver.h \
$(NULL)
gdbus_sources = \
@@ -103,6 +111,14 @@ gdbus_sources = \
gdbusintrospection.h gdbusintrospection.c \
gdbusmethodinvocation.h gdbusmethodinvocation.c \
gdbusserver.h gdbusserver.c \
+ gdbusinterface.h gdbusinterface.c \
+ gdbusinterfacestub.h gdbusinterfacestub.c \
+ gdbusobject.h gdbusobject.c \
+ gdbusobjectstub.h gdbusobjectstub.c \
+ gdbusobjectproxy.h gdbusobjectproxy.c \
+ gdbusobjectmanager.h gdbusobjectmanager.c \
+ gdbusobjectmanagerclient.h gdbusobjectmanagerclient.c \
+ gdbusobjectmanagerserver.h gdbusobjectmanagerserver.c \
$(NULL)
settings_headers = \
diff --git a/gio/gdbusauthobserver.c b/gio/gdbusauthobserver.c
index 46af595..ff94821 100644
--- a/gio/gdbusauthobserver.c
+++ b/gio/gdbusauthobserver.c
@@ -27,6 +27,7 @@
#include "gcredentials.h"
#include "gioenumtypes.h"
#include "giostream.h"
+#include "gdbusprivate.h"
#include "glibintl.h"
@@ -130,22 +131,6 @@ g_dbus_auth_observer_authorize_authenticated_peer_real (GDBusAuthObserver *obse
return TRUE;
}
-gboolean
-_g_signal_accumulator_false_handled (GSignalInvocationHint *ihint,
- GValue *return_accu,
- const GValue *handler_return,
- gpointer dummy)
-{
- gboolean continue_emission;
- gboolean signal_handled;
-
- signal_handled = g_value_get_boolean (handler_return);
- g_value_set_boolean (return_accu, signal_handled);
- continue_emission = signal_handled;
-
- return continue_emission;
-}
-
static void
g_dbus_auth_observer_class_init (GDBusAuthObserverClass *klass)
{
diff --git a/gio/gdbusinterface.c b/gio/gdbusinterface.c
new file mode 100644
index 0000000..d8f8594
--- /dev/null
+++ b/gio/gdbusinterface.c
@@ -0,0 +1,410 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include "gdbusobject.h"
+#include "gdbusinterface.h"
+#include "gio-marshal.h"
+
+#include "glibintl.h"
+
+/**
+ * SECTION:gdbusinterface
+ * @short_description: Base type for D-Bus interfaces
+ * @include: gio/gio.h
+ *
+ * The #GDBusInterface type is the base type for D-Bus interfaces both
+ * on the service side (see #GDBusInterfaceStub) and client side (see
+ * #GDBusProxy).
+ */
+
+typedef GDBusInterfaceIface GDBusInterfaceInterface;
+G_DEFINE_INTERFACE (GDBusInterface, g_dbus_interface, G_TYPE_OBJECT)
+
+static void
+g_dbus_interface_default_init (GDBusInterfaceIface *iface)
+{
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_dbus_interface_get_info:
+ * @interface: An exported D-Bus interface.
+ *
+ * Gets D-Bus introspection information for the D-Bus interface
+ * implemented by @interface.
+ *
+ * Returns: (transfer none): A #GDBusInterfaceInfo. Do not free.
+ */
+GDBusInterfaceInfo *
+g_dbus_interface_get_info (GDBusInterface *interface)
+{
+ g_return_val_if_fail (G_IS_DBUS_INTERFACE (interface), NULL);
+ return G_DBUS_INTERFACE_GET_IFACE (interface)->get_info (interface);
+}
+
+/**
+ * g_dbus_interface_get_object:
+ * @interface: An exported D-Bus interface.
+ *
+ * Gets the #GDBusObject that @interface belongs to, if any.
+ *
+ * Returns: (transfer none): A #GDBusObject or %NULL. The returned
+ * reference belongs to @interface and should not be freed.
+ */
+GDBusObject *
+g_dbus_interface_get_object (GDBusInterface *interface)
+{
+ g_return_val_if_fail (G_IS_DBUS_INTERFACE (interface), NULL);
+ return G_DBUS_INTERFACE_GET_IFACE (interface)->get_object (interface);
+}
+
+/**
+ * g_dbus_interface_set_object:
+ * @interface: An exported D-Bus interface.
+ * @object: A #GDBusObject or %NULL.
+ *
+ * Sets the #GDBusObject for @interface to @object.
+ *
+ * Note that @interface will hold a weak reference to @object.
+ */
+void
+g_dbus_interface_set_object (GDBusInterface *interface,
+ GDBusObject *object)
+{
+ g_return_if_fail (G_IS_DBUS_INTERFACE (interface));
+ g_return_if_fail (object == NULL || G_IS_DBUS_OBJECT (object));
+ G_DBUS_INTERFACE_GET_IFACE (interface)->set_object (interface, object);
+}
+
+/* Keep it here for now. TODO: move */
+
+#include <string.h>
+
+/**
+ * g_dbus_gvariant_to_gvalue:
+ * @value: A #GVariant.
+ * @out_gvalue: Return location for the #GValue.
+ *
+ * Convert a #GVariant to a #GValue. If @value is floating, it is consumed.
+ *
+ * Note that the passed @out_gvalue does not have to have a #GType set.
+ *
+ * Returns: %TRUE if the conversion succeeded, %FALSE otherwise.
+ */
+gboolean
+g_dbus_gvariant_to_gvalue (GVariant *value,
+ GValue *out_gvalue)
+{
+ gboolean ret;
+ const GVariantType *type;
+ gchar **array;
+
+ g_return_val_if_fail (value != NULL, FALSE);
+ g_return_val_if_fail (out_gvalue != NULL, FALSE);
+
+ ret = FALSE;
+
+ memset (out_gvalue, '\0', sizeof (GValue));
+
+ switch (g_variant_classify (value))
+ {
+ case G_VARIANT_CLASS_BOOLEAN:
+ g_value_init (out_gvalue, G_TYPE_BOOLEAN);
+ g_value_set_boolean (out_gvalue, g_variant_get_boolean (value));
+ break;
+
+ case G_VARIANT_CLASS_BYTE:
+ g_value_init (out_gvalue, G_TYPE_UCHAR);
+ g_value_set_uchar (out_gvalue, g_variant_get_byte (value));
+ break;
+
+ case G_VARIANT_CLASS_INT16:
+ g_value_init (out_gvalue, G_TYPE_INT);
+ g_value_set_int (out_gvalue, g_variant_get_int16 (value));
+ break;
+
+ case G_VARIANT_CLASS_UINT16:
+ g_value_init (out_gvalue, G_TYPE_UINT);
+ g_value_set_uint (out_gvalue, g_variant_get_uint16 (value));
+ break;
+
+ case G_VARIANT_CLASS_INT32:
+ g_value_init (out_gvalue, G_TYPE_INT);
+ g_value_set_int (out_gvalue, g_variant_get_int32 (value));
+ break;
+
+ case G_VARIANT_CLASS_UINT32:
+ g_value_init (out_gvalue, G_TYPE_UINT);
+ g_value_set_uint (out_gvalue, g_variant_get_uint32 (value));
+ break;
+
+ case G_VARIANT_CLASS_INT64:
+ g_value_init (out_gvalue, G_TYPE_INT64);
+ g_value_set_int64 (out_gvalue, g_variant_get_int64 (value));
+ break;
+
+ case G_VARIANT_CLASS_UINT64:
+ g_value_init (out_gvalue, G_TYPE_UINT64);
+ g_value_set_uint64 (out_gvalue, g_variant_get_uint64 (value));
+ break;
+
+ case G_VARIANT_CLASS_HANDLE:
+ g_value_init (out_gvalue, G_TYPE_INT);
+ g_value_set_int (out_gvalue, g_variant_get_int32 (value));
+ break;
+
+ case G_VARIANT_CLASS_DOUBLE:
+ g_value_init (out_gvalue, G_TYPE_DOUBLE);
+ g_value_set_double (out_gvalue, g_variant_get_double (value));
+ break;
+
+ case G_VARIANT_CLASS_STRING:
+ g_value_init (out_gvalue, G_TYPE_STRING);
+ g_value_set_string (out_gvalue, g_variant_get_string (value, NULL));
+ break;
+
+ case G_VARIANT_CLASS_OBJECT_PATH:
+ g_value_init (out_gvalue, G_TYPE_STRING);
+ g_value_set_string (out_gvalue, g_variant_get_string (value, NULL));
+ break;
+
+ case G_VARIANT_CLASS_SIGNATURE:
+ g_value_init (out_gvalue, G_TYPE_STRING);
+ g_value_set_string (out_gvalue, g_variant_get_string (value, NULL));
+ break;
+
+ case G_VARIANT_CLASS_ARRAY:
+ type = g_variant_get_type (value);
+ switch (g_variant_type_peek_string (type)[1])
+ {
+ case G_VARIANT_CLASS_BYTE:
+ g_value_init (out_gvalue, G_TYPE_STRING);
+ g_value_set_string (out_gvalue, g_variant_get_bytestring (value));
+ break;
+
+ case G_VARIANT_CLASS_STRING:
+ g_value_init (out_gvalue, G_TYPE_STRV);
+ array = g_variant_dup_strv (value, NULL);
+ g_value_take_boxed (out_gvalue, array);
+ break;
+
+ case G_VARIANT_CLASS_ARRAY:
+ switch (g_variant_type_peek_string (type)[2])
+ {
+ case G_VARIANT_CLASS_BYTE:
+ g_value_init (out_gvalue, G_TYPE_STRV);
+ array = g_variant_dup_bytestring_array (value, NULL);
+ g_value_take_boxed (out_gvalue, array);
+ break;
+
+ default:
+ g_value_init (out_gvalue, G_TYPE_VARIANT);
+ g_value_set_variant (out_gvalue, value);
+ break;
+ }
+ break;
+
+ default:
+ g_value_init (out_gvalue, G_TYPE_VARIANT);
+ g_value_set_variant (out_gvalue, value);
+ break;
+ }
+ break;
+
+ case G_VARIANT_CLASS_VARIANT:
+ case G_VARIANT_CLASS_MAYBE:
+ case G_VARIANT_CLASS_TUPLE:
+ case G_VARIANT_CLASS_DICT_ENTRY:
+ g_value_init (out_gvalue, G_TYPE_VARIANT);
+ g_value_set_variant (out_gvalue, value);
+ break;
+ }
+
+ ret = TRUE;
+
+ return ret;
+}
+
+
+/**
+ * g_dbus_gvalue_to_gvariant:
+ * @gvalue: A #GValue to convert to a #GVariant.
+ * @expected_type: The #GVariantType to create.
+ *
+ * Convert a #GValue to #GVariant.
+ *
+ * Returns: A #GVariant (never floating) holding the data from @gvalue
+ * or %NULL in case of error. Free with g_variant_unref().
+ */
+GVariant *
+g_dbus_gvalue_to_gvariant (const GValue *gvalue,
+ const GVariantType *expected_type)
+{
+ GVariant *ret;
+ const gchar *s;
+ const gchar * const *as;
+ const gchar *empty_strv[1] = {NULL};
+
+ g_return_val_if_fail (gvalue != NULL, NULL);
+ g_return_val_if_fail (expected_type != NULL, NULL);
+
+ ret = NULL;
+
+ /* The expected type could easily be e.g. "s" with the GValue holding a string.
+ * because of the UseGVariant annotation
+ */
+ if (G_VALUE_TYPE (gvalue) == G_TYPE_VARIANT)
+ {
+ ret = g_value_dup_variant (gvalue);
+ }
+ else
+ {
+ switch (g_variant_type_peek_string (expected_type)[0])
+ {
+ case G_VARIANT_CLASS_BOOLEAN:
+ ret = g_variant_ref_sink (g_variant_new_boolean (g_value_get_boolean (gvalue)));
+ break;
+
+ case G_VARIANT_CLASS_BYTE:
+ ret = g_variant_ref_sink (g_variant_new_byte (g_value_get_uchar (gvalue)));
+ break;
+
+ case G_VARIANT_CLASS_INT16:
+ ret = g_variant_ref_sink (g_variant_new_int16 (g_value_get_int (gvalue)));
+ break;
+
+ case G_VARIANT_CLASS_UINT16:
+ ret = g_variant_ref_sink (g_variant_new_uint16 (g_value_get_uint (gvalue)));
+ break;
+
+ case G_VARIANT_CLASS_INT32:
+ ret = g_variant_ref_sink (g_variant_new_int32 (g_value_get_int (gvalue)));
+ break;
+
+ case G_VARIANT_CLASS_UINT32:
+ ret = g_variant_ref_sink (g_variant_new_uint32 (g_value_get_uint (gvalue)));
+ break;
+
+ case G_VARIANT_CLASS_INT64:
+ ret = g_variant_ref_sink (g_variant_new_int64 (g_value_get_int64 (gvalue)));
+ break;
+
+ case G_VARIANT_CLASS_UINT64:
+ ret = g_variant_ref_sink (g_variant_new_uint64 (g_value_get_uint64 (gvalue)));
+ break;
+
+ case G_VARIANT_CLASS_HANDLE:
+ ret = g_variant_ref_sink (g_variant_new_handle (g_value_get_int (gvalue)));
+ break;
+
+ case G_VARIANT_CLASS_DOUBLE:
+ ret = g_variant_ref_sink (g_variant_new_double (g_value_get_double (gvalue)));
+ break;
+
+ case G_VARIANT_CLASS_STRING:
+ s = g_value_get_string (gvalue);
+ if (s == NULL)
+ s = "";
+ ret = g_variant_ref_sink (g_variant_new_string (s));
+ break;
+
+ case G_VARIANT_CLASS_OBJECT_PATH:
+ s = g_value_get_string (gvalue);
+ if (s == NULL)
+ s = "/";
+ ret = g_variant_ref_sink (g_variant_new_object_path (s));
+ break;
+
+ case G_VARIANT_CLASS_SIGNATURE:
+ s = g_value_get_string (gvalue);
+ if (s == NULL)
+ s = "";
+ ret = g_variant_ref_sink (g_variant_new_signature (s));
+ break;
+
+ case G_VARIANT_CLASS_ARRAY:
+ switch (g_variant_type_peek_string (expected_type)[1])
+ {
+ case G_VARIANT_CLASS_BYTE:
+ s = g_value_get_string (gvalue);
+ if (s == NULL)
+ s = "";
+ ret = g_variant_ref_sink (g_variant_new_bytestring (s));
+ break;
+
+ case G_VARIANT_CLASS_STRING:
+ as = g_value_get_boxed (gvalue);
+ if (as == NULL)
+ as = empty_strv;
+ ret = g_variant_ref_sink (g_variant_new_strv (as, -1));
+ break;
+
+ case G_VARIANT_CLASS_ARRAY:
+ switch (g_variant_type_peek_string (expected_type)[2])
+ {
+ case G_VARIANT_CLASS_BYTE:
+ as = g_value_get_boxed (gvalue);
+ if (as == NULL)
+ as = empty_strv;
+ ret = g_variant_ref_sink (g_variant_new_bytestring_array (as, -1));
+ break;
+
+ default:
+ ret = g_value_dup_variant (gvalue);
+ break;
+ }
+ break;
+
+ default:
+ ret = g_value_dup_variant (gvalue);
+ break;
+ }
+ break;
+
+ default:
+ case G_VARIANT_CLASS_VARIANT:
+ case G_VARIANT_CLASS_MAYBE:
+ case G_VARIANT_CLASS_TUPLE:
+ case G_VARIANT_CLASS_DICT_ENTRY:
+ ret = g_value_dup_variant (gvalue);
+ break;
+ }
+ }
+
+ /* Could be that the GValue is holding a NULL GVariant - in that case,
+ * we return an "empty" GVariant instead of a NULL GVariant
+ */
+ if (ret == NULL)
+ {
+ GVariant *untrusted_empty;
+ untrusted_empty = g_variant_new_from_data (expected_type, NULL, 0, FALSE, NULL, NULL);
+ ret = g_variant_ref_sink (g_variant_get_normal_form (untrusted_empty));
+ g_variant_unref (untrusted_empty);
+ }
+
+ g_assert (!g_variant_is_floating (ret));
+
+ return ret;
+}
diff --git a/gio/gdbusinterface.h b/gio/gdbusinterface.h
new file mode 100644
index 0000000..275f43e
--- /dev/null
+++ b/gio/gdbusinterface.h
@@ -0,0 +1,79 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __G_DBUS_INTERFACE_H__
+#define __G_DBUS_INTERFACE_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_DBUS_INTERFACE (g_dbus_interface_get_type())
+#define G_DBUS_INTERFACE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_INTERFACE, GDBusInterface))
+#define G_IS_DBUS_INTERFACE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_INTERFACE))
+#define G_DBUS_INTERFACE_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE((o), G_TYPE_DBUS_INTERFACE, GDBusInterfaceIface))
+
+/**
+ * GDBusInterface:
+ *
+ * Base type for D-Bus interfaces.
+ */
+typedef struct _GDBusInterface GDBusInterface; /* Dummy typedef */
+
+typedef struct _GDBusInterfaceIface GDBusInterfaceIface;
+
+/**
+ * GDBusInterfaceIface:
+ * @parent_iface: The parent interface.
+ * @get_info: Returns a #GDBusInterfaceInfo. See g_dbus_interface_get_info().
+ * @get_object: Gets the enclosing #GDBusObject. See g_dbus_interface_get_object().
+ * @set_object: Sets the enclosing #GDBusObject. See g_dbus_interface_set_object().
+ *
+ * Base type for D-Bus interfaces.
+ */
+struct _GDBusInterfaceIface
+{
+ GTypeInterface parent_iface;
+
+ /* Virtual Functions */
+ GDBusInterfaceInfo *(*get_info) (GDBusInterface *interface);
+ GDBusObject *(*get_object) (GDBusInterface *interface);
+ void (*set_object) (GDBusInterface *interface,
+ GDBusObject *object);
+};
+
+GType g_dbus_interface_get_type (void) G_GNUC_CONST;
+GDBusInterfaceInfo *g_dbus_interface_get_info (GDBusInterface *interface);
+GDBusObject *g_dbus_interface_get_object (GDBusInterface *interface);
+void g_dbus_interface_set_object (GDBusInterface *interface,
+ GDBusObject *object);
+
+/* Keep it here for now. TODO: move */
+
+gboolean g_dbus_gvariant_to_gvalue (GVariant *value,
+ GValue *out_gvalue);
+GVariant *g_dbus_gvalue_to_gvariant (const GValue *gvalue,
+ const GVariantType *expected_type);
+
+G_END_DECLS
+
+#endif /* __G_DBUS_INTERFACE_H__ */
diff --git a/gio/gdbusinterfacestub.c b/gio/gdbusinterfacestub.c
new file mode 100644
index 0000000..4eee99b
--- /dev/null
+++ b/gio/gdbusinterfacestub.c
@@ -0,0 +1,693 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include "gdbusinterface.h"
+#include "gdbusinterfacestub.h"
+#include "gdbusobjectstub.h"
+#include "gio-marshal.h"
+#include "gioenumtypes.h"
+#include "gdbusprivate.h"
+#include "gdbusmethodinvocation.h"
+#include "gdbusconnection.h"
+#include "gioscheduler.h"
+#include "gioerror.h"
+
+#include "glibintl.h"
+
+/**
+ * SECTION:gdbusinterfacestub
+ * @short_description: Service-side D-Bus interface
+ * @include: gio/gio.h
+ *
+ * Abstract base class for D-Bus interfaces on the service side.
+ */
+
+struct _GDBusInterfaceStubPrivate
+{
+ GDBusObject *object;
+ GDBusInterfaceStubFlags flags;
+ guint registration_id;
+
+ GDBusConnection *connection;
+ gchar *object_path;
+ GDBusInterfaceVTable *hooked_vtable;
+};
+
+enum
+{
+ G_AUTHORIZE_METHOD_SIGNAL,
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0,
+ PROP_G_FLAGS
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
+static void dbus_interface_interface_init (GDBusInterfaceIface *iface);
+
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GDBusInterfaceStub, g_dbus_interface_stub, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_INTERFACE, dbus_interface_interface_init));
+
+static void
+g_dbus_interface_stub_finalize (GObject *object)
+{
+ GDBusInterfaceStub *stub = G_DBUS_INTERFACE_STUB (object);
+ /* unexport if already exported */
+ if (stub->priv->registration_id > 0)
+ g_dbus_interface_stub_unexport (stub);
+
+ g_assert (stub->priv->connection == NULL);
+ g_assert (stub->priv->object_path == NULL);
+ g_assert (stub->priv->hooked_vtable == NULL);
+
+ if (stub->priv->object != NULL)
+ g_object_remove_weak_pointer (G_OBJECT (stub->priv->object), (gpointer *) &stub->priv->object);
+ G_OBJECT_CLASS (g_dbus_interface_stub_parent_class)->finalize (object);
+}
+
+static void
+g_dbus_interface_stub_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GDBusInterfaceStub *stub = G_DBUS_INTERFACE_STUB (object);
+
+ switch (prop_id)
+ {
+ case PROP_G_FLAGS:
+ g_value_set_flags (value, g_dbus_interface_stub_get_flags (stub));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_dbus_interface_stub_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GDBusInterfaceStub *stub = G_DBUS_INTERFACE_STUB (object);
+
+ switch (prop_id)
+ {
+ case PROP_G_FLAGS:
+ g_dbus_interface_stub_set_flags (stub, g_value_get_flags (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+g_dbus_interface_stub_g_authorize_method_default (GDBusInterfaceStub *stub,
+ GDBusMethodInvocation *invocation)
+{
+ return TRUE;
+}
+
+static void
+g_dbus_interface_stub_class_init (GDBusInterfaceStubClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = g_dbus_interface_stub_finalize;
+ gobject_class->set_property = g_dbus_interface_stub_set_property;
+ gobject_class->get_property = g_dbus_interface_stub_get_property;
+
+ klass->g_authorize_method = g_dbus_interface_stub_g_authorize_method_default;
+
+ /**
+ * GDBusInterfaceStub:g-flags:
+ *
+ * Flags from the #GDBusInterfaceStubFlags enumeration.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_G_FLAGS,
+ g_param_spec_flags ("g-flags",
+ "g-flags",
+ "Flags for the interface stub",
+ G_TYPE_DBUS_INTERFACE_STUB_FLAGS,
+ G_DBUS_INTERFACE_STUB_FLAGS_NONE,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GDBusInterfaceStub::g-authorize-method:
+ * @interface: The #GDBusInterfaceStub emitting the signal.
+ * @invocation: A #GDBusMethodInvocation.
+ *
+ * Emitted when a method is invoked by a remote caller and used to
+ * determine if the method call is authorized.
+ *
+ * Note that this signal is emitted in a thread dedicated to
+ * handling the method call so handlers are allowed to perform
+ * blocking IO. This means that it is appropriate to call
+ * e.g. <ulink
+ * url="http://hal.freedesktop.org/docs/polkit/PolkitAuthority.html#polkit-authority-check-authorization-sync">polkit_authority_check_authorization_sync()</ulink>
+ * with the <ulink
+ * url="http://hal.freedesktop.org/docs/polkit/PolkitAuthority.html#POLKIT-CHECK-AUTHORIZATION-FLAGS-ALLOW-USER-INTERACTION:CAPS">POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION</ulink> flag set.
+ *
+ * If %FALSE is returned then no further handlers are run and the
+ * signal handler must take ownership of @invocation and finish
+ * handling the call (e.g. return an error via
+ * g_dbus_method_invocation_return_error()).
+ *
+ * Otherwise, if %TRUE is returned, signal emission continues. If no
+ * handlers return %FALSE, then the method is dispatched. If
+ * @interface has an enclosing #GDBusObjectStub, then the
+ * #GDBusObjectStub::authorize-method signal handlers run before the
+ * handlers for this signal.
+ *
+ * The default class handler just returns %TRUE.
+ *
+ * Please note that the common case is optimized: if no signals
+ * handlers are connected and the default class handler isn't
+ * overridden (for both @interface and the enclosing
+ * #GDBusObjectStub, if any) and #GDBusInterfaceStub:g-flags does
+ * not have the
+ * %G_DBUS_INTERFACE_STUB_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD
+ * flags set, no dedicated thread is ever used and the call will be
+ * handled in the same thread as the object that @interface belongs
+ * to was exported in.
+ *
+ * Returns: %TRUE if the call is authorized, %FALSE otherwise.
+ */
+ signals[G_AUTHORIZE_METHOD_SIGNAL] =
+ g_signal_new ("g-authorize-method",
+ G_TYPE_DBUS_INTERFACE_STUB,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GDBusInterfaceStubClass, g_authorize_method),
+ _g_signal_accumulator_false_handled,
+ NULL,
+ _gio_marshal_BOOLEAN__OBJECT,
+ G_TYPE_BOOLEAN,
+ 1,
+ G_TYPE_DBUS_METHOD_INVOCATION);
+
+ g_type_class_add_private (klass, sizeof (GDBusInterfaceStubPrivate));
+}
+
+static void
+g_dbus_interface_stub_init (GDBusInterfaceStub *stub)
+{
+ stub->priv = G_TYPE_INSTANCE_GET_PRIVATE (stub, G_TYPE_DBUS_INTERFACE_STUB, GDBusInterfaceStubPrivate);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_dbus_interface_stub_get_flags:
+ * @stub: A #GDBusInterfaceStub.
+ *
+ * Gets the #GDBusInterfaceStubFlags that describes what the behavior
+ * of @stub
+ *
+ * Returns: One or more flags from the #GDBusInterfaceStubFlags enumeration.
+ */
+GDBusInterfaceStubFlags
+g_dbus_interface_stub_get_flags (GDBusInterfaceStub *stub)
+{
+ g_return_val_if_fail (G_IS_DBUS_INTERFACE_STUB (stub), G_DBUS_INTERFACE_STUB_FLAGS_NONE);
+ return stub->priv->flags;
+}
+
+/**
+ * g_dbus_interface_stub_set_flags:
+ * @stub: A #GDBusInterfaceStub.
+ * @flags: Flags from the #GDBusInterfaceStubFlags enumeration.
+ *
+ * Sets flags describing what the behavior of @stub should be.
+ */
+void
+g_dbus_interface_stub_set_flags (GDBusInterfaceStub *stub,
+ GDBusInterfaceStubFlags flags)
+{
+ g_return_if_fail (G_IS_DBUS_INTERFACE_STUB (stub));
+ if (stub->priv->flags != flags)
+ {
+ stub->priv->flags = flags;
+ g_object_notify (G_OBJECT (stub), "g-flags");
+ }
+}
+
+/**
+ * g_dbus_interface_stub_get_info:
+ * @stub: A #GDBusInterfaceStub.
+ *
+ * Gets D-Bus introspection information for the D-Bus interface
+ * implemented by @interface.
+ *
+ * Returns: (transfer none): A #GDBusInterfaceInfo (never %NULL). Do not free.
+ */
+GDBusInterfaceInfo *
+g_dbus_interface_stub_get_info (GDBusInterfaceStub *stub)
+{
+ GDBusInterfaceInfo *ret;
+ g_return_val_if_fail (G_IS_DBUS_INTERFACE_STUB (stub), NULL);
+ ret = G_DBUS_INTERFACE_STUB_GET_CLASS (stub)->get_info (stub);
+ g_warn_if_fail (ret != NULL);
+ return ret;
+}
+
+/**
+ * g_dbus_interface_stub_get_vtable:
+ * @stub: A #GDBusInterfaceStub.
+ *
+ * Gets the interface vtable for the D-Bus interface implemented by
+ * @interface. The returned function pointers should expect @stub
+ * itself to be passed as @user_data.
+ *
+ * Returns: A #GDBusInterfaceVTable (never %NULL).
+ */
+GDBusInterfaceVTable *
+g_dbus_interface_stub_get_vtable (GDBusInterfaceStub *stub)
+{
+ GDBusInterfaceVTable *ret;
+ g_return_val_if_fail (G_IS_DBUS_INTERFACE_STUB (stub), NULL);
+ ret = G_DBUS_INTERFACE_STUB_GET_CLASS (stub)->get_vtable (stub);
+ g_warn_if_fail (ret != NULL);
+ return ret;
+}
+
+/**
+ * g_dbus_interface_stub_get_properties:
+ * @stub: A #GDBusInterfaceStub.
+ *
+ * Gets all D-Bus properties for @stub.
+ *
+ * Returns: A new, floating, #GVariant. Free with g_variant_unref().
+ */
+GVariant *
+g_dbus_interface_stub_get_properties (GDBusInterfaceStub *stub)
+{
+ GVariant *ret;
+ g_return_val_if_fail (G_IS_DBUS_INTERFACE_STUB (stub), NULL);
+ ret = G_DBUS_INTERFACE_STUB_GET_CLASS (stub)->get_properties (stub);
+ g_warn_if_fail (g_variant_is_floating (ret));
+ return ret;
+}
+
+/**
+ * g_dbus_interface_stub_flush:
+ * @stub: A #GDBusInterfaceStub.
+ *
+ * If @stub has outstanding changes, request for these changes to be
+ * emitted immediately.
+ *
+ * For example, an exported D-Bus interface may queue up property
+ * changes and emit the
+ * <literal>org.freedesktop.DBus.Properties::PropertiesChanged</literal>
+ * signal later (e.g. in an idle handler). This technique is useful
+ * for collapsing multiple property changes into one.
+ */
+void
+g_dbus_interface_stub_flush (GDBusInterfaceStub *stub)
+{
+ g_return_if_fail (G_IS_DBUS_INTERFACE_STUB (stub));
+ G_DBUS_INTERFACE_STUB_GET_CLASS (stub)->flush (stub);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GDBusInterfaceInfo *
+_g_dbus_interface_stub_get_info (GDBusInterface *interface)
+{
+ GDBusInterfaceStub *stub = G_DBUS_INTERFACE_STUB (interface);
+ return g_dbus_interface_stub_get_info (stub);
+}
+
+static GDBusObject *
+g_dbus_interface_stub_get_object (GDBusInterface *interface)
+{
+ GDBusInterfaceStub *stub = G_DBUS_INTERFACE_STUB (interface);
+ return stub->priv->object;
+}
+
+static void
+g_dbus_interface_stub_set_object (GDBusInterface *interface,
+ GDBusObject *object)
+{
+ GDBusInterfaceStub *stub = G_DBUS_INTERFACE_STUB (interface);
+ if (stub->priv->object != NULL)
+ g_object_remove_weak_pointer (G_OBJECT (stub->priv->object), (gpointer *) &stub->priv->object);
+ stub->priv->object = object;
+ if (object != NULL)
+ g_object_add_weak_pointer (G_OBJECT (stub->priv->object), (gpointer *) &stub->priv->object);
+}
+
+static void
+dbus_interface_interface_init (GDBusInterfaceIface *iface)
+{
+ iface->get_info = _g_dbus_interface_stub_get_info;
+ iface->get_object = g_dbus_interface_stub_get_object;
+ iface->set_object = g_dbus_interface_stub_set_object;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+ volatile gint ref_count;
+ GDBusInterfaceStub *stub;
+ GDBusInterfaceMethodCallFunc method_call_func;
+ GDBusMethodInvocation *invocation;
+ GMainContext *context;
+} DispatchData;
+
+static void
+dispatch_data_unref (DispatchData *data)
+{
+ if (g_atomic_int_dec_and_test (&data->ref_count))
+ {
+ if (data->context != NULL)
+ g_main_context_unref (data->context);
+ g_free (data);
+ }
+}
+
+static DispatchData *
+dispatch_data_ref (DispatchData *data)
+{
+ g_atomic_int_inc (&data->ref_count);
+ return data;
+}
+
+static gboolean
+dispatch_invoke_in_context_func (gpointer user_data)
+{
+ DispatchData *data = user_data;
+ data->method_call_func (g_dbus_method_invocation_get_connection (data->invocation),
+ g_dbus_method_invocation_get_sender (data->invocation),
+ g_dbus_method_invocation_get_object_path (data->invocation),
+ g_dbus_method_invocation_get_interface_name (data->invocation),
+ g_dbus_method_invocation_get_method_name (data->invocation),
+ g_dbus_method_invocation_get_parameters (data->invocation),
+ data->invocation,
+ g_dbus_method_invocation_get_user_data (data->invocation));
+ return FALSE;
+}
+
+static gboolean
+dispatch_in_thread_func (GIOSchedulerJob *job,
+ GCancellable *cancellable,
+ gpointer user_data)
+{
+ DispatchData *data = user_data;
+ gboolean authorized;
+
+ /* first check on the enclosing object (if any), then the interface */
+ authorized = TRUE;
+ if (data->stub->priv->object != NULL)
+ {
+ g_signal_emit_by_name (data->stub->priv->object,
+ "authorize-method",
+ data->stub,
+ data->invocation,
+ &authorized);
+ }
+ if (authorized)
+ {
+ g_signal_emit (data->stub,
+ signals[G_AUTHORIZE_METHOD_SIGNAL],
+ 0,
+ data->invocation,
+ &authorized);
+ }
+
+ if (authorized)
+ {
+ gboolean run_in_thread;
+ run_in_thread = (data->stub->priv->flags & G_DBUS_INTERFACE_STUB_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
+ if (run_in_thread)
+ {
+ /* might as well just re-use the existing thread */
+ data->method_call_func (g_dbus_method_invocation_get_connection (data->invocation),
+ g_dbus_method_invocation_get_sender (data->invocation),
+ g_dbus_method_invocation_get_object_path (data->invocation),
+ g_dbus_method_invocation_get_interface_name (data->invocation),
+ g_dbus_method_invocation_get_method_name (data->invocation),
+ g_dbus_method_invocation_get_parameters (data->invocation),
+ data->invocation,
+ g_dbus_method_invocation_get_user_data (data->invocation));
+ }
+ else
+ {
+ /* bah, back to original context */
+ g_main_context_invoke_full (data->context,
+ G_PRIORITY_DEFAULT,
+ dispatch_invoke_in_context_func,
+ dispatch_data_ref (data),
+ (GDestroyNotify) dispatch_data_unref);
+ }
+ }
+ else
+ {
+ /* do nothing */
+ }
+
+ return FALSE;
+}
+
+static void
+g_dbus_interface_method_dispatch_helper (GDBusInterfaceStub *stub,
+ GDBusInterfaceMethodCallFunc method_call_func,
+ GDBusMethodInvocation *invocation)
+{
+ gboolean has_handlers;
+ gboolean has_default_class_handler;
+ gboolean emit_authorized_signal;
+ gboolean run_in_thread;
+
+ g_return_if_fail (G_IS_DBUS_INTERFACE_STUB (stub));
+ g_return_if_fail (method_call_func != NULL);
+ g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation));
+
+ /* optimization for the common case where
+ *
+ * a) no handler is connected and class handler is not overridden (both interface and object); and
+ * b) method calls are not dispatched in a thread
+ */
+ has_handlers = g_signal_has_handler_pending (stub,
+ signals[G_AUTHORIZE_METHOD_SIGNAL],
+ 0,
+ TRUE);
+ has_default_class_handler = (G_DBUS_INTERFACE_STUB_GET_CLASS (stub)->g_authorize_method ==
+ g_dbus_interface_stub_g_authorize_method_default);
+
+ emit_authorized_signal = (has_handlers || !has_default_class_handler);
+ if (!emit_authorized_signal)
+ {
+ if (stub->priv->object != NULL)
+ emit_authorized_signal = _g_dbus_object_stub_has_authorize_method_handlers (G_DBUS_OBJECT_STUB (stub->priv->object));
+ }
+
+ run_in_thread = (stub->priv->flags & G_DBUS_INTERFACE_STUB_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
+ if (!emit_authorized_signal && !run_in_thread)
+ {
+ method_call_func (g_dbus_method_invocation_get_connection (invocation),
+ g_dbus_method_invocation_get_sender (invocation),
+ g_dbus_method_invocation_get_object_path (invocation),
+ g_dbus_method_invocation_get_interface_name (invocation),
+ g_dbus_method_invocation_get_method_name (invocation),
+ g_dbus_method_invocation_get_parameters (invocation),
+ invocation,
+ g_dbus_method_invocation_get_user_data (invocation));
+ }
+ else
+ {
+ DispatchData *data;
+ data = g_new0 (DispatchData, 1);
+ data->stub = stub;
+ data->method_call_func = method_call_func;
+ data->invocation = invocation;
+ data->context = g_main_context_get_thread_default ();
+ data->ref_count = 1;
+ if (data->context != NULL)
+ g_main_context_ref (data->context);
+ g_io_scheduler_push_job (dispatch_in_thread_func,
+ data,
+ (GDestroyNotify) dispatch_data_unref,
+ G_PRIORITY_DEFAULT,
+ NULL); /* GCancellable* */
+ }
+}
+
+static void
+stub_intercept_handle_method_call(GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ GDBusInterfaceStub *stub = G_DBUS_INTERFACE_STUB (user_data);
+ g_dbus_interface_method_dispatch_helper (stub,
+ g_dbus_interface_stub_get_vtable (stub)->method_call,
+ invocation);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_dbus_interface_stub_get_connection:
+ * @stub: A #GDBusInterfaceStub.
+ *
+ * Gets the connection that @stub is exported on, if any.
+ *
+ * Returns: (transfer none): A #GDBusConnection or %NULL if @stub is
+ * not exported anywhere. Do not free, the object belongs to @stub.
+ */
+GDBusConnection *
+g_dbus_interface_stub_get_connection (GDBusInterfaceStub *stub)
+{
+ g_return_val_if_fail (G_IS_DBUS_INTERFACE_STUB (stub), NULL);
+ return stub->priv->connection;
+}
+
+/**
+ * g_dbus_interface_stub_get_object_path:
+ * @stub: A #GDBusInterfaceStub.
+ *
+ * Gets the object that that @stub is exported on, if any.
+ *
+ * Returns: A string owned by @stub or %NULL if stub is not exported
+ * anywhere. Do not free, the string belongs to @stub.
+ */
+const gchar *
+g_dbus_interface_stub_get_object_path (GDBusInterfaceStub *stub)
+{
+ g_return_val_if_fail (G_IS_DBUS_INTERFACE_STUB (stub), NULL);
+ return stub->priv->object_path;
+}
+
+/**
+ * g_dbus_interface_stub_export:
+ * @stub: The D-Bus interface to export.
+ * @connection: A #GDBusConnection to export @stub on.
+ * @object_path: The path to export the interface at.
+ * @error: Return location for error or %NULL.
+ *
+ * Exports @stubs at @object_path on @connection.
+ *
+ * Use g_dbus_interface_stub_unexport() to unexport the object.
+ *
+ * Returns: %TRUE if the interface was exported, other %FALSE with
+ * @error set.
+ */
+gboolean
+g_dbus_interface_stub_export (GDBusInterfaceStub *stub,
+ GDBusConnection *connection,
+ const gchar *object_path,
+ GError **error)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (G_IS_DBUS_INTERFACE_STUB (stub), 0);
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
+ g_return_val_if_fail (g_variant_is_object_path (object_path), 0);
+ g_return_val_if_fail (error == NULL || *error == NULL, 0);
+
+ ret = FALSE;
+ if (stub->priv->registration_id > 0)
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED, /* TODO: new error code */
+ "The object is already exported");
+ goto out;
+ }
+
+ g_assert (stub->priv->connection == NULL);
+ g_assert (stub->priv->object_path == NULL);
+ g_assert (stub->priv->hooked_vtable == NULL);
+
+ /* Hook the vtable since we need to intercept method calls for
+ * ::g-authorize-method and for dispatching in thread vs
+ * context
+ */
+ stub->priv->hooked_vtable = g_memdup (g_dbus_interface_stub_get_vtable (stub), sizeof (GDBusInterfaceVTable));
+ stub->priv->hooked_vtable->method_call = stub_intercept_handle_method_call;
+
+ stub->priv->connection = g_object_ref (connection);
+ stub->priv->object_path = g_strdup (object_path);
+ stub->priv->registration_id = g_dbus_connection_register_object (connection,
+ object_path,
+ g_dbus_interface_stub_get_info (stub),
+ stub->priv->hooked_vtable,
+ stub,
+ NULL, /* user_data_free_func */
+ error);
+ if (stub->priv->registration_id == 0)
+ goto out;
+
+ ret = TRUE;
+
+ out:
+ return ret;
+}
+
+/**
+ * g_dbus_interface_stub_unexport:
+ * @stub: A #GDBusInterfaceStub.
+ *
+ * Stops exporting an interface previously exported with
+ * g_dbus_interface_stub_export().
+ */
+void
+g_dbus_interface_stub_unexport (GDBusInterfaceStub *stub)
+{
+ g_return_if_fail (G_IS_DBUS_INTERFACE_STUB (stub));
+ g_return_if_fail (stub->priv->registration_id > 0);
+
+ g_assert (stub->priv->connection != NULL);
+ g_assert (stub->priv->object_path != NULL);
+ g_assert (stub->priv->hooked_vtable != NULL);
+
+ g_warn_if_fail (g_dbus_connection_unregister_object (stub->priv->connection,
+ stub->priv->registration_id));
+
+ g_object_unref (stub->priv->connection);
+ g_free (stub->priv->object_path);
+ stub->priv->connection = NULL;
+ stub->priv->object_path = NULL;
+ stub->priv->hooked_vtable = NULL;
+ stub->priv->registration_id = 0;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
diff --git a/gio/gdbusinterfacestub.h b/gio/gdbusinterfacestub.h
new file mode 100644
index 0000000..8e03d72
--- /dev/null
+++ b/gio/gdbusinterfacestub.h
@@ -0,0 +1,105 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __G_DBUS_INTERFACE_STUB_H__
+#define __G_DBUS_INTERFACE_STUB_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_DBUS_INTERFACE_STUB (g_dbus_interface_stub_get_type ())
+#define G_DBUS_INTERFACE_STUB(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_INTERFACE_STUB, GDBusInterfaceStub))
+#define G_DBUS_INTERFACE_STUB_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_INTERFACE_STUB, GDBusInterfaceStubClass))
+#define G_DBUS_INTERFACE_STUB_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_INTERFACE_STUB, GDBusInterfaceStubClass))
+#define G_IS_DBUS_INTERFACE_STUB(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_INTERFACE_STUB))
+#define G_IS_DBUS_INTERFACE_STUB_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_INTERFACE_STUB))
+
+typedef struct _GDBusInterfaceStubClass GDBusInterfaceStubClass;
+typedef struct _GDBusInterfaceStubPrivate GDBusInterfaceStubPrivate;
+
+/**
+ * GDBusInterfaceStub:
+ *
+ * The #GDBusInterfaceStub structure contains private data and should
+ * only be accessed using the provided API.
+ */
+struct _GDBusInterfaceStub
+{
+ /*< private >*/
+ GObject parent_instance;
+ GDBusInterfaceStubPrivate *priv;
+};
+
+/**
+ * GDBusInterfaceStubClass:
+ * @parent_class: The parent class.
+ * @get_info: Returns a #GDBusInterfaceInfo. See g_dbus_interface_stub_get_info() for details.
+ * @get_vtable: Returns a #GDBusInterfaceVTable. See g_dbus_interface_stub_get_vtable() for details.
+ * @get_properties: Returns a new, floating, #GVariant with all properties. See g_dbus_interface_stub_get_properties().
+ * @flush: Emits outstanding changes, if any. See g_dbus_interface_stub_flush().
+ * @g_authorize_method: Signal class handler for the #GDBusInterfaceStub::g-authorize-method signal.
+ *
+ * Class structure for #GDBusInterfaceStub.
+ */
+struct _GDBusInterfaceStubClass
+{
+ GObjectClass parent_class;
+
+ /* Virtual Functions */
+ GDBusInterfaceInfo *(*get_info) (GDBusInterfaceStub *stub);
+ GDBusInterfaceVTable *(*get_vtable) (GDBusInterfaceStub *stub);
+ GVariant *(*get_properties) (GDBusInterfaceStub *stub);
+ void (*flush) (GDBusInterfaceStub *stub);
+
+ /*< private >*/
+ gpointer vfunc_padding[8];
+ /*< public >*/
+
+ /* Signals */
+ gboolean (*g_authorize_method) (GDBusInterfaceStub *stub,
+ GDBusMethodInvocation *invocation);
+
+ /*< private >*/
+ gpointer signal_padding[8];
+};
+
+GType g_dbus_interface_stub_get_type (void) G_GNUC_CONST;
+GDBusInterfaceStubFlags g_dbus_interface_stub_get_flags (GDBusInterfaceStub *stub);
+void g_dbus_interface_stub_set_flags (GDBusInterfaceStub *stub,
+ GDBusInterfaceStubFlags flags);
+GDBusInterfaceInfo *g_dbus_interface_stub_get_info (GDBusInterfaceStub *stub);
+GDBusInterfaceVTable *g_dbus_interface_stub_get_vtable (GDBusInterfaceStub *stub);
+GVariant *g_dbus_interface_stub_get_properties (GDBusInterfaceStub *stub);
+void g_dbus_interface_stub_flush (GDBusInterfaceStub *stub);
+
+gboolean g_dbus_interface_stub_export (GDBusInterfaceStub *stub,
+ GDBusConnection *connection,
+ const gchar *object_path,
+ GError **error);
+void g_dbus_interface_stub_unexport (GDBusInterfaceStub *stub);
+GDBusConnection *g_dbus_interface_stub_get_connection (GDBusInterfaceStub *stub);
+const gchar *g_dbus_interface_stub_get_object_path (GDBusInterfaceStub *stub);
+
+G_END_DECLS
+
+#endif /* __G_DBUS_INTERFACE_STUB_H */
diff --git a/gio/gdbusobject.c b/gio/gdbusobject.c
new file mode 100644
index 0000000..2211d4c
--- /dev/null
+++ b/gio/gdbusobject.c
@@ -0,0 +1,191 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include "gdbusobject.h"
+#include "gdbusinterface.h"
+#include "gdbusutils.h"
+#include "gio-marshal.h"
+
+#include "glibintl.h"
+
+/**
+ * SECTION:gdbusobject
+ * @short_description: Base type for D-Bus objects
+ * @include: gio/gio.h
+ *
+ * The #GDBusObject type is the base type for D-Bus objects on both
+ * the service side (see #GDBusObjectStub) and the client side (see
+ * #GDBusObjectProxy). It is essentially just a container of
+ * interfaces.
+ */
+
+typedef GDBusObjectIface GDBusObjectInterface;
+G_DEFINE_INTERFACE (GDBusObject, g_dbus_object, G_TYPE_OBJECT)
+
+static void
+g_dbus_object_default_init (GDBusObjectIface *iface)
+{
+ /**
+ * GDBusObject::interface-added:
+ * @object: The #GDBusObject emitting the signal.
+ * @interface: The #GDBusInterface that was added.
+ *
+ * Emitted when @interface is added to @object.
+ */
+ g_signal_new ("interface-added",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GDBusObjectIface, interface_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_DBUS_INTERFACE);
+
+ /**
+ * GDBusObject::interface-removed:
+ * @object: The #GDBusObject emitting the signal.
+ * @interface: The #GDBusInterface that was removed.
+ *
+ * Emitted when @interface is removed from @object.
+ */
+ g_signal_new ("interface-removed",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GDBusObjectIface, interface_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_DBUS_INTERFACE);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_dbus_object_get_object_path:
+ * @object: A #GDBusObject.
+ *
+ * Gets the object path for @object.
+ *
+ * Returns: A string owned by @object. Do not free.
+ */
+const gchar *
+g_dbus_object_get_object_path (GDBusObject *object)
+{
+ GDBusObjectIface *iface = G_DBUS_OBJECT_GET_IFACE (object);
+ return iface->get_object_path (object);
+}
+
+/**
+ * g_dbus_object_get_interfaces:
+ * @object: A #GDBusObject.
+ *
+ * Gets the D-Bus interfaces associated with @object.
+ *
+ * Returns: (element-type GDBusInterface) (transfer full) : A list of #GDBusInterface instances.
+ * The returned list must be freed by g_list_free() after each element has been freed
+ * with g_object_unref().
+ */
+GList *
+g_dbus_object_get_interfaces (GDBusObject *object)
+{
+ GDBusObjectIface *iface = G_DBUS_OBJECT_GET_IFACE (object);
+ return iface->get_interfaces (object);
+}
+
+/**
+ * g_dbus_object_get_interface:
+ * @object: A #GDBusObject.
+ * @interface_name: A D-Bus interface name.
+ *
+ * Gets the D-Bus interface with name @interface_name associated with
+ * @object, if any.
+ *
+ * Returns: %NULL if not found, otherwise a #GDBusInterface that must
+ * be freed with g_object_unref().
+ */
+GDBusInterface *
+g_dbus_object_get_interface (GDBusObject *object,
+ const gchar *interface_name)
+{
+ GDBusObjectIface *iface = G_DBUS_OBJECT_GET_IFACE (object);
+ g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
+ return iface->get_interface (object, interface_name);
+}
+
+
+/**
+ * g_dbus_object_peek_with_typecheck:
+ * @object: A #GDBusObject.
+ * @interface_name: A D-Bus interface name.
+ * @type: The #GType that the returned object must conform to.
+ *
+ * Like g_dbus_object_lookup_with_typecheck() except that the caller
+ * does not own a reference to the returned object.
+ *
+ * <note><para>This function is intended to only be used in type
+ * implementations.</para></note>
+ *
+ * Returns: A #GDBusInterface implementing @type or %NULL if
+ * not found. Do not free the returned object, it is owned by
+ * @object.
+ */
+gpointer
+g_dbus_object_peek_with_typecheck (GDBusObject *object,
+ const gchar *interface_name,
+ GType type)
+{
+ GDBusObjectIface *iface = G_DBUS_OBJECT_GET_IFACE (object);
+ g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
+ return iface->peek_with_typecheck (object, interface_name, type);
+}
+
+/**
+ * g_dbus_object_lookup_with_typecheck:
+ * @object: A #GDBusObject.
+ * @interface_name: A D-Bus interface name.
+ * @type: The #GType that the returned object must conform to.
+ *
+ * Like g_dbus_object_get_interface() but warns on stderr if the
+ * returned object, if any, does not conform to @type.
+ *
+ * <note><para>This function is intended to only be used in type
+ * implementations.</para></note>
+ *
+ * Returns: A #GDBusInterface implementing @type or %NULL if
+ * not found. Free with g_object_unref().
+ */
+gpointer
+g_dbus_object_lookup_with_typecheck (GDBusObject *object,
+ const gchar *interface_name,
+ GType type)
+{
+ GDBusObjectIface *iface = G_DBUS_OBJECT_GET_IFACE (object);
+ g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
+ return iface->lookup_with_typecheck (object, interface_name, type);
+}
+
diff --git a/gio/gdbusobject.h b/gio/gdbusobject.h
new file mode 100644
index 0000000..e941ddd
--- /dev/null
+++ b/gio/gdbusobject.h
@@ -0,0 +1,95 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __G_DBUS_OBJECT_H__
+#define __G_DBUS_OBJECT_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_DBUS_OBJECT (g_dbus_object_get_type())
+#define G_DBUS_OBJECT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_OBJECT, GDBusObject))
+#define G_IS_DBUS_OBJECT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_OBJECT))
+#define G_DBUS_OBJECT_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE((o), G_TYPE_DBUS_OBJECT, GDBusObjectIface))
+
+typedef struct _GDBusObjectIface GDBusObjectIface;
+
+/**
+ * GDBusObjectIface:
+ * @parent_iface: The parent interface.
+ * @get_object_path: Returns the object path. See g_dbus_object_get_object_path().
+ * @get_interfaces: Returns all interfaces. See g_dbus_object_get_interfaces().
+ * @get_interface: Returns an interface by name. See g_dbus_object_get_interface().
+ * @lookup_with_typecheck: Like @get_interface but warns on stderr if the returned object, if any,
+ * does not conform to @type. Returned object must be freed by the caller.
+ * @peek_with_typecheck: Like @lookup_with_typecheck but does not transfer the reference.
+ * @interface_added: Signal handler for the #GDBusObject::interface-added signal.
+ * @interface_removed: Signal handler for the #GDBusObject::interface-removed signal.
+ *
+ * Base object type for D-Bus objects.
+ *
+ * <note><para>The @lookup_with_typecheck and @peek_with_typecheck
+ * virtual functions should only be used by D-Bus interface
+ * implementations.</para></note>
+ */
+struct _GDBusObjectIface
+{
+ GTypeInterface parent_iface;
+
+ /* Virtual Functions */
+ const gchar *(*get_object_path) (GDBusObject *object);
+ GList *(*get_interfaces) (GDBusObject *object);
+ GDBusInterface *(*get_interface) (GDBusObject *object,
+ const gchar *interface_name);
+
+ gpointer (*lookup_with_typecheck) (GDBusObject *object,
+ const gchar *interface_name,
+ GType type);
+ gpointer (*peek_with_typecheck) (GDBusObject *object,
+ const gchar *interface_name,
+ GType type);
+
+ /* Signals */
+ void (*interface_added) (GDBusObject *object,
+ GDBusInterface *interface);
+ void (*interface_removed) (GDBusObject *object,
+ GDBusInterface *interface);
+
+};
+
+GType g_dbus_object_get_type (void) G_GNUC_CONST;
+const gchar *g_dbus_object_get_object_path (GDBusObject *object);
+GList *g_dbus_object_get_interfaces (GDBusObject *object);
+GDBusInterface *g_dbus_object_get_interface (GDBusObject *object,
+ const gchar *interface_name);
+
+gpointer g_dbus_object_peek_with_typecheck (GDBusObject *object,
+ const gchar *interface_name,
+ GType type);
+gpointer g_dbus_object_lookup_with_typecheck (GDBusObject *object,
+ const gchar *interface_name,
+ GType type);
+
+G_END_DECLS
+
+#endif /* __G_DBUS_OBJECT_H__ */
diff --git a/gio/gdbusobjectmanager.c b/gio/gdbusobjectmanager.c
new file mode 100644
index 0000000..6b3b291
--- /dev/null
+++ b/gio/gdbusobjectmanager.c
@@ -0,0 +1,216 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include "gdbusobject.h"
+#include "gdbusobjectmanager.h"
+#include "gio-marshal.h"
+#include "gdbusinterface.h"
+#include "gdbusutils.h"
+
+#include "glibintl.h"
+
+/**
+ * SECTION:gdbusobjectmanager
+ * @short_description: Base type for D-Bus object managers
+ * @include: gio/gio.h
+ *
+ * The #GDBusObjectManager type is the base type for service- and
+ * client-side implementations of the standardized <ulink
+ * url="http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager">org.freedesktop.DBus.ObjectManager</ulink>
+ * interface.
+ *
+ * See #GDBusObjectManagerClient for the client-side implementation
+ * and #GDBusObjectManagerServer for the service-side implementation.
+ */
+
+/**
+ * GDBusObjectManager:
+ *
+ * A D-Bus object.
+ */
+
+typedef GDBusObjectManagerIface GDBusObjectManagerInterface;
+G_DEFINE_INTERFACE (GDBusObjectManager, g_dbus_object_manager, G_TYPE_OBJECT)
+
+static void
+g_dbus_object_manager_default_init (GDBusObjectManagerIface *iface)
+{
+ /**
+ * GDBusObjectManager::object-added:
+ * @manager: The #GDBusObjectManager emitting the signal.
+ * @object: The #GDBusObject that was added.
+ *
+ * Emitted when @object is added to @manager.
+ */
+ g_signal_new ("object-added",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GDBusObjectManagerIface, object_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_DBUS_OBJECT);
+
+ /**
+ * GDBusObjectManager::object-removed:
+ * @manager: The #GDBusObjectManager emitting the signal.
+ * @object: The #GDBusObject that was removed.
+ *
+ * Emitted when @object is removed from @manager.
+ */
+ g_signal_new ("object-removed",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GDBusObjectManagerIface, object_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_DBUS_OBJECT);
+
+ /**
+ * GDBusObjectManager::interface-added:
+ * @manager: The #GDBusObjectManager emitting the signal.
+ * @object: The #GDBusObject on which an interface was added.
+ * @interface: The #GDBusInterface that was added.
+ *
+ * Emitted when @interface is added to @object.
+ *
+ * This signal exists purely as a convenience to avoid having to
+ * connect signals to all objects managed by @manager.
+ */
+ g_signal_new ("interface-added",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GDBusObjectManagerIface, interface_added),
+ NULL,
+ NULL,
+ _gio_marshal_VOID__OBJECT_OBJECT,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_DBUS_OBJECT,
+ G_TYPE_DBUS_INTERFACE);
+
+ /**
+ * GDBusObjectManager::interface-removed:
+ * @manager: The #GDBusObjectManager emitting the signal.
+ * @object: The #GDBusObject on which an interface was removed.
+ * @interface: The #GDBusInterface that was removed.
+ *
+ * Emitted when @interface has been removed from @object.
+ *
+ * This signal exists purely as a convenience to avoid having to
+ * connect signals to all objects managed by @manager.
+ */
+ g_signal_new ("interface-removed",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GDBusObjectManagerIface, interface_removed),
+ NULL,
+ NULL,
+ _gio_marshal_VOID__OBJECT_OBJECT,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_DBUS_OBJECT,
+ G_TYPE_DBUS_INTERFACE);
+
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_dbus_object_manager_get_object_path:
+ * @manager: A #GDBusObjectManager.
+ *
+ * Gets the object path that @manager is for.
+ *
+ * Returns: A string owned by @manager. Do not free.
+ */
+const gchar *
+g_dbus_object_manager_get_object_path (GDBusObjectManager *manager)
+{
+ GDBusObjectManagerIface *iface = G_DBUS_OBJECT_MANAGER_GET_IFACE (manager);
+ return iface->get_object_path (manager);
+}
+
+/**
+ * g_dbus_object_manager_get_objects:
+ * @manager: A #GDBusObjectManager.
+ *
+ * Gets all #GDBusObject objects known to @manager.
+ *
+ * Returns: (transfer full) (element-type GDBusObject): A list of
+ * #GDBusObject objects. The returned list should be freed with
+ * g_list_free() after each element has been freed with
+ * g_object_unref().
+ */
+GList *
+g_dbus_object_manager_get_objects (GDBusObjectManager *manager)
+{
+ GDBusObjectManagerIface *iface = G_DBUS_OBJECT_MANAGER_GET_IFACE (manager);
+ return iface->get_objects (manager);
+}
+
+/**
+ * g_dbus_object_manager_get_object:
+ * @manager: A #GDBusObjectManager.
+ * @object_path: Object path to lookup.
+ *
+ * Gets the #GDBusObjectProxy at @object_path, if any.
+ *
+ * Returns: A #GDBusObject or %NULL. Free with g_object_unref().
+ */
+GDBusObject *
+g_dbus_object_manager_get_object (GDBusObjectManager *manager,
+ const gchar *object_path)
+{
+ GDBusObjectManagerIface *iface = G_DBUS_OBJECT_MANAGER_GET_IFACE (manager);
+ g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
+ return iface->get_object (manager, object_path);
+}
+
+/**
+ * g_dbus_object_manager_get_interface:
+ * @manager: A #GDBusObjectManager.
+ * @object_path: Object path to lookup.
+ * @interface_name: D-Bus interface name to lookup.
+ *
+ * Gets the interface proxy for @interface_name at @object_path, if
+ * any.
+ *
+ * Returns: A #GDBusInterface instance or %NULL. Free with g_object_unref().
+ */
+GDBusInterface *
+g_dbus_object_manager_get_interface (GDBusObjectManager *manager,
+ const gchar *object_path,
+ const gchar *interface_name)
+{
+ GDBusObjectManagerIface *iface = G_DBUS_OBJECT_MANAGER_GET_IFACE (manager);
+ g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
+ g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
+ return iface->get_interface (manager, object_path, interface_name);
+}
diff --git a/gio/gdbusobjectmanager.h b/gio/gdbusobjectmanager.h
new file mode 100644
index 0000000..2b82bf4
--- /dev/null
+++ b/gio/gdbusobjectmanager.h
@@ -0,0 +1,89 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __G_DBUS_OBJECT_MANAGER_H__
+#define __G_DBUS_OBJECT_MANAGER_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_DBUS_OBJECT_MANAGER (g_dbus_object_manager_get_type())
+#define G_DBUS_OBJECT_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_OBJECT_MANAGER, GDBusObjectManager))
+#define G_IS_DBUS_OBJECT_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_OBJECT_MANAGER))
+#define G_DBUS_OBJECT_MANAGER_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE((o), G_TYPE_DBUS_OBJECT_MANAGER, GDBusObjectManagerIface))
+
+typedef struct _GDBusObjectManagerIface GDBusObjectManagerIface;
+
+/**
+ * GDBusObjectManagerIface:
+ * @parent_iface: The parent interface.
+ * @get_object_path: Virtual function for g_dbus_object_manager_get_object_path().
+ * @get_objects: Virtual function for g_dbus_object_manager_get_objects().
+ * @get_object: Virtual function for g_dbus_object_manager_get_object().
+ * @get_interface: Virtual function for g_dbus_object_manager_get_interface().
+ * @object_added: Signal handler for the #GDBusObjectManager::object-added signal.
+ * @object_removed: Signal handler for the #GDBusObjectManager::object-removed signal.
+ * @interface_added: Signal handler for the #GDBusObjectManager::interface-added signal.
+ * @interface_removed: Signal handler for the #GDBusObjectManager::interface-removed signal.
+ *
+ * Base type for D-Bus object managers.
+ */
+struct _GDBusObjectManagerIface
+{
+ GTypeInterface parent_iface;
+
+ /* Virtual Functions */
+ const gchar *(*get_object_path) (GDBusObjectManager *manager);
+ GList *(*get_objects) (GDBusObjectManager *manager);
+ GDBusObject *(*get_object) (GDBusObjectManager *manager,
+ const gchar *object_path);
+ GDBusInterface *(*get_interface) (GDBusObjectManager *manager,
+ const gchar *object_path,
+ const gchar *interface_name);
+
+ /* Signals */
+ void (*object_added) (GDBusObjectManager *manager,
+ GDBusObject *object);
+ void (*object_removed) (GDBusObjectManager *manager,
+ GDBusObject *object);
+
+ void (*interface_added) (GDBusObjectManager *manager,
+ GDBusObject *object,
+ GDBusInterface *interface);
+ void (*interface_removed) (GDBusObjectManager *manager,
+ GDBusObject *object,
+ GDBusInterface *interface);
+};
+
+GType g_dbus_object_manager_get_type (void) G_GNUC_CONST;
+const gchar *g_dbus_object_manager_get_object_path (GDBusObjectManager *manager);
+GList *g_dbus_object_manager_get_objects (GDBusObjectManager *manager);
+GDBusObject *g_dbus_object_manager_get_object (GDBusObjectManager *manager,
+ const gchar *object_path);
+GDBusInterface *g_dbus_object_manager_get_interface (GDBusObjectManager *manager,
+ const gchar *object_path,
+ const gchar *interface_name);
+
+G_END_DECLS
+
+#endif /* __G_DBUS_OBJECT_MANAGER_H__ */
diff --git a/gio/gdbusobjectmanagerclient.c b/gio/gdbusobjectmanagerclient.c
new file mode 100644
index 0000000..79eb5cc
--- /dev/null
+++ b/gio/gdbusobjectmanagerclient.c
@@ -0,0 +1,1575 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include "gdbusobjectmanager.h"
+#include "gdbusobjectmanagerclient.h"
+#include "gdbusobject.h"
+#include "gdbusprivate.h"
+#include "gio-marshal.h"
+#include "gioenumtypes.h"
+#include "ginitable.h"
+#include "gasyncresult.h"
+#include "gsimpleasyncresult.h"
+#include "gasyncinitable.h"
+#include "gdbusconnection.h"
+#include "gdbusutils.h"
+#include "gdbusobject.h"
+#include "gdbusobjectproxy.h"
+#include "gdbusproxy.h"
+#include "gdbusinterface.h"
+
+#include "glibintl.h"
+
+/**
+ * SECTION:gdbusobjectmanagerclient
+ * @short_description: Client-side object manager
+ * @include: gio/gio.h
+ *
+ * #GDBusObjectManagerClient is used to create, monitor and delete object
+ * proxies for remote objects exported by a #GDBusObjectManagerServer (or any
+ * code implementing the <ulink
+ * url="http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager">org.freedesktop.DBus.ObjectManager</ulink>
+ * interface).
+ *
+ * Once an instance of this type has been created, you can connect to
+ * the #GDBusObjectManager::object-added and
+ * #GDBusObjectManager::object-removed signals and inspect the
+ * #GDBusObjectProxy objects returned by
+ * g_dbus_object_manager_get_objects().
+ *
+ * If the name for a #GDBusObjectManagerClient is not owned by anyone at
+ * object construction time, the default behavior is to request the
+ * message bus to launch an owner for the name. This behavior can be
+ * disabled using the %G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START
+ * flag. It's also worth noting that this only works if the name of
+ * interest is activatable in the first place. E.g. in some cases it
+ * is not possible to launch an owner for the requested name. In this
+ * case, #GDBusObjectManagerClient object construction still succeeds but
+ * there will be no object proxies
+ * (e.g. g_dbus_object_manager_get_objects() returns the empty list) and
+ * the #GDBusObjectManagerClient:name-owner property is %NULL.
+ *
+ * The owner of the requested name can come and go (for example
+ * consider a system service being restarted) â?? #GDBusObjectManagerClient
+ * handles this case too; simply connect to the #GObject::notify
+ * signal to watch for changes on the #GDBusObjectManagerClient:name-owner
+ * property. When the name owner vanishes, the behavior is that
+ * #GDBusObjectManagerClient:name-owner is set to %NULL (this includes
+ * emission of the #GObject::notify signal) and then
+ * #GDBusObjectManager::object-removed signals are synthesized
+ * for all currently existing object proxies. Since
+ * #GDBusObjectManagerClient:name-owner is %NULL when this happens, you can
+ * use this information to disambiguate a synthesized signal from a
+ * genuine signal caused by object removal on the remote
+ * #GDBusObjectManager. Similarly, when a new name owner appears,
+ * #GDBusObjectManager::object-added signals are synthesized
+ * while #GDBusObjectManagerClient:name-owner is still %NULL. Only when all
+ * object proxies have been added, the #GDBusObjectManagerClient:name-owner
+ * is set to the new name owner (this includes emission of the
+ * #GObject::notify signal). Furthermore, you are guaranteed that
+ * #GDBusObjectManagerClient:name-owner will alternate between a name owner
+ * (e.g. <literal>:1.42</literal>) and %NULL even in the case where
+ * the name of interest is atomically replaced
+ *
+ * Ultimately, #GDBusObjectManagerClient is used to obtain #GDBusProxy
+ * instances. All signals (including the
+ * <literal>org.freedesktop.DBus.Properties::PropertiesChanged</literal>
+ * signal) delivered to #GDBusProxy instances are guaranteed to
+ * originate from the name owner. This guarantee along with the
+ * behavior described above, means that certain race conditions
+ * including the <emphasis><quote>half the proxy is from the old owner
+ * and the other half is from the new owner</quote></emphasis> problem
+ * cannot happen.
+ *
+ * To avoid having the application connect to signals on the returned
+ * #GDBusObjectProxy and #GDBusProxy objects, the
+ * #GDBusObject::interface-added,
+ * #GDBusObject::interface-removed,
+ * #GDBusProxy::g-properties-changed and
+ * #GDBusProxy::g-signal signals
+ * are also emitted on the #GDBusObjectManagerClient instance managing these
+ * objects. The signals emitted are
+ * #GDBusObjectManager::interface-added,
+ * #GDBusObjectManager::interface-removed,
+ * #GDBusObjectManagerClient::interface-proxy-properties-changed and
+ * #GDBusObjectManagerClient::interface-proxy-signal.
+ *
+ * Note that all callbacks and signals are emitted in the
+ * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+ * that the #GDBusObjectManagerClient object was constructed
+ * in. Additionally, the #GDBusObjectProxy and #GDBusProxy objects
+ * originating from the #GDBusObjectManagerClient object will be created in
+ * the same context and, consequently, will deliver signals in the
+ * same main loop.
+ */
+
+struct _GDBusObjectManagerClientPrivate
+{
+ GBusType bus_type;
+ GDBusConnection *connection;
+ gchar *object_path;
+ gchar *name;
+ gchar *name_owner;
+ GDBusObjectManagerClientFlags flags;
+
+ GDBusProxy *control_proxy;
+
+ GHashTable *map_object_path_to_object_proxy;
+
+ guint signal_subscription_id;
+ gchar *match_rule;
+
+ GDBusProxyTypeFunc get_proxy_type_func;
+ gpointer get_proxy_type_user_data;
+};
+
+enum
+{
+ PROP_0,
+ PROP_BUS_TYPE,
+ PROP_CONNECTION,
+ PROP_FLAGS,
+ PROP_OBJECT_PATH,
+ PROP_NAME,
+ PROP_NAME_OWNER,
+ PROP_GET_PROXY_TYPE_FUNC,
+ PROP_GET_PROXY_TYPE_USER_DATA
+};
+
+enum
+{
+ INTERFACE_PROXY_SIGNAL_SIGNAL,
+ INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void initable_iface_init (GInitableIface *initable_iface);
+static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
+static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerClient, g_dbus_object_manager_client, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
+ G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
+ G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init));
+
+static void maybe_unsubscribe_signals (GDBusObjectManagerClient *manager);
+
+static void on_control_proxy_g_signal (GDBusProxy *proxy,
+ const gchar *sender_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data);
+
+static void process_get_all_result (GDBusObjectManagerClient *manager,
+ GVariant *value,
+ const gchar *name_owner);
+
+static void
+g_dbus_object_manager_client_finalize (GObject *object)
+{
+ GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object);
+
+ maybe_unsubscribe_signals (manager);
+
+ g_hash_table_unref (manager->priv->map_object_path_to_object_proxy);
+
+ if (manager->priv->control_proxy != NULL)
+ {
+ g_warn_if_fail (g_signal_handlers_disconnect_by_func (manager->priv->control_proxy,
+ on_control_proxy_g_signal,
+ manager) == 1);
+ g_object_unref (manager->priv->control_proxy);
+ }
+ g_object_unref (manager->priv->connection);
+ g_free (manager->priv->object_path);
+ g_free (manager->priv->name);
+ g_free (manager->priv->name_owner);
+
+ if (G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (g_dbus_object_manager_client_parent_class)->finalize (object);
+}
+
+static void
+g_dbus_object_manager_client_get_property (GObject *_object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
+
+ switch (prop_id)
+ {
+ case PROP_CONNECTION:
+ g_value_set_object (value, g_dbus_object_manager_client_get_connection (manager));
+ break;
+
+ case PROP_OBJECT_PATH:
+ g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
+ break;
+
+ case PROP_NAME:
+ g_value_set_string (value, g_dbus_object_manager_client_get_name (manager));
+ break;
+
+ case PROP_FLAGS:
+ g_value_set_flags (value, g_dbus_object_manager_client_get_flags (manager));
+ break;
+
+ case PROP_NAME_OWNER:
+ g_value_take_string (value, g_dbus_object_manager_client_get_name_owner (manager));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_dbus_object_manager_client_set_property (GObject *_object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_object);
+
+ switch (prop_id)
+ {
+ case PROP_BUS_TYPE:
+ manager->priv->bus_type = g_value_get_enum (value);
+ break;
+
+ case PROP_CONNECTION:
+ if (g_value_get_object (value) != NULL)
+ {
+ g_assert (manager->priv->connection == NULL);
+ g_assert (G_IS_DBUS_CONNECTION (g_value_get_object (value)));
+ manager->priv->connection = g_value_dup_object (value);
+ }
+ break;
+
+ case PROP_OBJECT_PATH:
+ g_assert (manager->priv->object_path == NULL);
+ g_assert (g_variant_is_object_path (g_value_get_string (value)));
+ manager->priv->object_path = g_value_dup_string (value);
+ break;
+
+ case PROP_NAME:
+ g_assert (manager->priv->name == NULL);
+ g_assert (g_dbus_is_name (g_value_get_string (value)));
+ manager->priv->name = g_value_dup_string (value);
+ break;
+
+ case PROP_FLAGS:
+ manager->priv->flags = g_value_get_flags (value);
+ break;
+
+ case PROP_GET_PROXY_TYPE_FUNC:
+ manager->priv->get_proxy_type_func = g_value_get_pointer (value);
+ break;
+
+ case PROP_GET_PROXY_TYPE_USER_DATA:
+ manager->priv->get_proxy_type_user_data = g_value_get_pointer (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = g_dbus_object_manager_client_finalize;
+ gobject_class->set_property = g_dbus_object_manager_client_set_property;
+ gobject_class->get_property = g_dbus_object_manager_client_get_property;
+
+ /**
+ * GDBusObjectManagerClient:connection:
+ *
+ * The #GDBusConnection to use.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_CONNECTION,
+ g_param_spec_object ("connection",
+ "Connection",
+ "The connection to use",
+ G_TYPE_DBUS_CONNECTION,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GDBusObjectManagerClient:bus-type:
+ *
+ * If this property is not %G_BUS_TYPE_NONE, then
+ * #GDBusObjectManagerClient:connection must be %NULL and will be set to the
+ * #GDBusConnection obtained by calling g_bus_get() with the value
+ * of this property.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_BUS_TYPE,
+ g_param_spec_enum ("bus-type",
+ "Bus Type",
+ "The bus to connect to, if any",
+ G_TYPE_BUS_TYPE,
+ G_BUS_TYPE_NONE,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GDBusObjectManagerClient:flags:
+ *
+ * Flags from the #GDBusObjectManagerClientFlags enumeration.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_FLAGS,
+ g_param_spec_flags ("flags",
+ "Flags",
+ "Flags for the proxy manager",
+ G_TYPE_DBUS_OBJECT_MANAGER_CLIENT_FLAGS,
+ G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GDBusObjectManagerClient:object-path:
+ *
+ * The object path the manager is for.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_OBJECT_PATH,
+ g_param_spec_string ("object-path",
+ "Object Path",
+ "The object path of the control object",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GDBusObjectManagerClient:name:
+ *
+ * The well-known name or unique name that the manager is for.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_NAME,
+ g_param_spec_string ("name",
+ "Name",
+ "Name that the manager is for",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GDBusObjectManagerClient:name-owner:
+ *
+ * The unique name that owns #GDBusObjectManagerClient:name or %NULL if
+ * no-one is currently owning the name. Connect to the
+ * #GObject::notify signal to track changes to this property.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_NAME_OWNER,
+ g_param_spec_string ("name-owner",
+ "Name Owner",
+ "The owner of the name we are watching",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GDBusObjectManagerClient:get-proxy-type-func:
+ *
+ * The #GDBusProxyTypeFunc to use when determining what #GType to
+ * use for interface proxies or %NULL.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_GET_PROXY_TYPE_FUNC,
+ g_param_spec_pointer ("get-proxy-type-func",
+ "GDBusProxyTypeFunc Function Pointer",
+ "The GDBusProxyTypeFunc pointer to use",
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GDBusObjectManagerClient:get-proxy-type-user-data:
+ *
+ * The #gpointer user_data to pass to #GDBusObjectManagerClient:get-proxy-type-func.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_GET_PROXY_TYPE_USER_DATA,
+ g_param_spec_pointer ("get-proxy-type-user-data",
+ "GDBusProxyTypeFunc User Data",
+ "The GDBusProxyTypeFunc user_data",
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GDBusObjectManagerClient::interface-proxy-signal:
+ * @manager: The #GDBusObjectManagerClient emitting the signal.
+ * @object_proxy: The #GDBusObjectProxy on which an interface is emitting a D-Bus signal.
+ * @interface_proxy: The #GDBusProxy that is emitting a D-Bus signal.
+ * @sender_name: The sender of the signal or NULL if the connection is not a bus connection.
+ * @signal_name: The signal name.
+ * @parameters: A #GVariant tuple with parameters for the signal.
+ *
+ * Emitted when a D-Bus signal is received on @interface_proxy.
+ *
+ * This signal exists purely as a convenience to avoid having to
+ * connect signals to all interface proxies managed by @manager.
+ *
+ * This signal is emitted in the
+ * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+ * that @manager was constructed in.
+ */
+ signals[INTERFACE_PROXY_SIGNAL_SIGNAL] =
+ g_signal_new ("interface-proxy-signal",
+ G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_signal),
+ NULL,
+ NULL,
+ _gio_marshal_VOID__OBJECT_OBJECT_STRING_STRING_VARIANT,
+ G_TYPE_NONE,
+ 5,
+ G_TYPE_DBUS_OBJECT_PROXY,
+ G_TYPE_DBUS_PROXY,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_VARIANT);
+
+ /**
+ * GDBusObjectManagerClient::interface-proxy-properties-changed:
+ * @manager: The #GDBusObjectManagerClient emitting the signal.
+ * @object_proxy: The #GDBusObjectProxy on which an interface has properties that are changing.
+ * @interface_proxy: The #GDBusProxy that has properties that are changing.
+ * @changed_properties: A #GVariant containing the properties that changed.
+ * @invalidated_properties: A %NULL terminated array of properties that was invalidated.
+ *
+ * Emitted when one or more D-Bus properties on proxy changes. The
+ * local cache has already been updated when this signal fires. Note
+ * that both @changed_properties and @invalidated_properties are
+ * guaranteed to never be %NULL (either may be empty though).
+ *
+ * This signal exists purely as a convenience to avoid having to
+ * connect signals to all interface proxies managed by @manager.
+ *
+ * This signal is emitted in the
+ * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+ * that @manager was constructed in.
+ */
+ signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL] =
+ g_signal_new ("interface-proxy-properties-changed",
+ G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GDBusObjectManagerClientClass, interface_proxy_properties_changed),
+ NULL,
+ NULL,
+ _gio_marshal_VOID__OBJECT_OBJECT_VARIANT_BOXED,
+ G_TYPE_NONE,
+ 4,
+ G_TYPE_DBUS_OBJECT_PROXY,
+ G_TYPE_DBUS_PROXY,
+ G_TYPE_VARIANT,
+ G_TYPE_STRV);
+
+ g_type_class_add_private (klass, sizeof (GDBusObjectManagerClientPrivate));
+}
+
+static void
+g_dbus_object_manager_client_init (GDBusObjectManagerClient *manager)
+{
+ manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
+ G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
+ GDBusObjectManagerClientPrivate);
+ manager->priv->map_object_path_to_object_proxy = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) g_object_unref);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_dbus_object_manager_client_new_sync:
+ * @connection: A #GDBusConnection.
+ * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
+ * @name: The owner of the control object (unique or well-known name).
+ * @object_path: The object path of the control object.
+ * @get_proxy_type_func: A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
+ * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
+ * @cancellable: A #GCancellable or %NULL
+ * @error: Return location for error or %NULL.
+ *
+ * Creates a new #GDBusObjectManagerClient object.
+ *
+ * This is a synchronous failable constructor - the calling thread is
+ * blocked until a reply is received. See g_dbus_object_manager_client_new()
+ * for the asynchronous version.
+ *
+ * Returns: A #GDBusObjectManagerClient object or %NULL if @error is
+ * set. Free with g_object_unref().
+ */
+GDBusObjectManager *
+g_dbus_object_manager_client_new_sync (GDBusConnection *connection,
+ GDBusObjectManagerClientFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GDBusProxyTypeFunc get_proxy_type_func,
+ gpointer get_proxy_type_user_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GInitable *initable;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+ g_return_val_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
+ g_dbus_is_name (name), NULL);
+ g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
+ cancellable,
+ error,
+ "connection", connection,
+ "flags", flags,
+ "name", name,
+ "object-path", object_path,
+ "get-proxy-type-func", get_proxy_type_func,
+ "get-proxy-type-user-data", get_proxy_type_user_data,
+ NULL);
+ if (initable != NULL)
+ return G_DBUS_OBJECT_MANAGER (initable);
+ else
+ return NULL;
+}
+
+/**
+ * g_dbus_object_manager_client_new:
+ * @connection: A #GDBusConnection.
+ * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
+ * @name: The owner of the control object (unique or well-known name).
+ * @object_path: The object path of the control object.
+ * @get_proxy_type_func: A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
+ * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
+ * @cancellable: A #GCancellable or %NULL
+ * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
+ * @user_data: The data to pass to @callback.
+ *
+ * Asynchronously creates a new #GDBusObjectManagerClient object.
+ *
+ * This is an asynchronous failable constructor. When the result is
+ * ready, @callback will be invoked in the
+ * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+ * of the thread you are calling this method from. You can
+ * then call g_dbus_object_manager_client_new_finish() to get the result. See
+ * g_dbus_object_manager_client_new_sync() for the synchronous version.
+ */
+void
+g_dbus_object_manager_client_new (GDBusConnection *connection,
+ GDBusObjectManagerClientFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GDBusProxyTypeFunc get_proxy_type_func,
+ gpointer get_proxy_type_user_data,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
+ g_return_if_fail ((name == NULL && g_dbus_connection_get_unique_name (connection) == NULL) ||
+ g_dbus_is_name (name));
+ g_return_if_fail (g_variant_is_object_path (object_path));
+
+ g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ callback,
+ user_data,
+ "connection", connection,
+ "flags", flags,
+ "name", name,
+ "object-path", object_path,
+ "get-proxy-type-func", get_proxy_type_func,
+ "get-proxy-type-user-data", get_proxy_type_user_data,
+ NULL);
+}
+
+/**
+ * g_dbus_object_manager_client_new_finish:
+ * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes an operation started with g_dbus_object_manager_client_new().
+ *
+ * Returns: A #GDBusObjectManagerClient object or %NULL if @error is
+ * set. Free with g_object_unref().
+ */
+GDBusObjectManager *
+g_dbus_object_manager_client_new_finish (GAsyncResult *res,
+ GError **error)
+{
+ GObject *object;
+ GObject *source_object;
+
+ source_object = g_async_result_get_source_object (res);
+ g_assert (source_object != NULL);
+
+ object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
+ res,
+ error);
+ g_object_unref (source_object);
+
+ if (object != NULL)
+ return G_DBUS_OBJECT_MANAGER (object);
+ else
+ return NULL;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_dbus_object_manager_client_new_for_bus_sync:
+ * @bus_type: A #GBusType.
+ * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
+ * @name: The owner of the control object (unique or well-known name).
+ * @object_path: The object path of the control object.
+ * @get_proxy_type_func: A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
+ * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
+ * @cancellable: A #GCancellable or %NULL
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_object_manager_client_new_sync() but takes a #GBusType instead
+ * of a #GDBusConnection.
+ *
+ * This is a synchronous failable constructor - the calling thread is
+ * blocked until a reply is received. See g_dbus_object_manager_client_new_for_bus()
+ * for the asynchronous version.
+ *
+ * Returns: A #GDBusObjectManagerClient object or %NULL if @error is
+ * set. Free with g_object_unref().
+ */
+GDBusObjectManager *
+g_dbus_object_manager_client_new_for_bus_sync (GBusType bus_type,
+ GDBusObjectManagerClientFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GDBusProxyTypeFunc get_proxy_type_func,
+ gpointer get_proxy_type_user_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GInitable *initable;
+
+ g_return_val_if_fail (bus_type != G_BUS_TYPE_NONE, NULL);
+ g_return_val_if_fail (g_dbus_is_name (name), NULL);
+ g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ initable = g_initable_new (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
+ cancellable,
+ error,
+ "bus-type", bus_type,
+ "flags", flags,
+ "name", name,
+ "object-path", object_path,
+ "get-proxy-type-func", get_proxy_type_func,
+ "get-proxy-type-user-data", get_proxy_type_user_data,
+ NULL);
+ if (initable != NULL)
+ return G_DBUS_OBJECT_MANAGER (initable);
+ else
+ return NULL;
+}
+
+/**
+ * g_dbus_object_manager_client_new_for_bus:
+ * @bus_type: A #GBusType.
+ * @flags: Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
+ * @name: The owner of the control object (unique or well-known name).
+ * @object_path: The object path of the control object.
+ * @get_proxy_type_func: A #GDBusProxyTypeFunc function or %NULL to always construct #GDBusProxy proxies.
+ * @get_proxy_type_user_data: User data to pass to @get_proxy_type_func.
+ * @cancellable: A #GCancellable or %NULL
+ * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
+ * @user_data: The data to pass to @callback.
+ *
+ * Like g_dbus_object_manager_client_new() but takes a #GBusType instead of a
+ * #GDBusConnection.
+ *
+ * This is an asynchronous failable constructor. When the result is
+ * ready, @callback will be invoked in the
+ * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+ * of the thread you are calling this method from. You can
+ * then call g_dbus_object_manager_client_new_for_bus_finish() to get the result. See
+ * g_dbus_object_manager_client_new_for_bus_sync() for the synchronous version.
+ */
+void
+g_dbus_object_manager_client_new_for_bus (GBusType bus_type,
+ GDBusObjectManagerClientFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GDBusProxyTypeFunc get_proxy_type_func,
+ gpointer get_proxy_type_user_data,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (bus_type != G_BUS_TYPE_NONE);
+ g_return_if_fail (g_dbus_is_name (name));
+ g_return_if_fail (g_variant_is_object_path (object_path));
+
+ g_async_initable_new_async (G_TYPE_DBUS_OBJECT_MANAGER_CLIENT,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ callback,
+ user_data,
+ "bus-type", bus_type,
+ "flags", flags,
+ "name", name,
+ "object-path", object_path,
+ "get-proxy-type-func", get_proxy_type_func,
+ "get-proxy-type-user-data", get_proxy_type_user_data,
+ NULL);
+}
+
+/**
+ * g_dbus_object_manager_client_new_for_bus_finish:
+ * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_object_manager_client_new_for_bus().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes an operation started with g_dbus_object_manager_client_new_for_bus().
+ *
+ * Returns: A #GDBusObjectManagerClient object or %NULL if @error is
+ * set. Free with g_object_unref().
+ */
+GDBusObjectManager *
+g_dbus_object_manager_client_new_for_bus_finish (GAsyncResult *res,
+ GError **error)
+{
+ GObject *object;
+ GObject *source_object;
+
+ source_object = g_async_result_get_source_object (res);
+ g_assert (source_object != NULL);
+
+ object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
+ res,
+ error);
+ g_object_unref (source_object);
+
+ if (object != NULL)
+ return G_DBUS_OBJECT_MANAGER (object);
+ else
+ return NULL;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_dbus_object_manager_client_get_connection:
+ * @manager: A #GDBusObjectManagerClient
+ *
+ * Gets the #GDBusConnection used by @manager.
+ *
+ * Returns: A #GDBusConnection object. Do not free, the object belongs
+ * to @manager.
+ */
+GDBusConnection *
+g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient *manager)
+{
+ g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
+ return manager->priv->connection;
+}
+
+/**
+ * g_dbus_object_manager_client_get_name:
+ * @manager: A #GDBusObjectManagerClient
+ *
+ * Gets the name that @manager is for.
+ *
+ * Returns: A unique or well-known name. Do not free, the string
+ * belongs to @manager.
+ */
+const gchar *
+g_dbus_object_manager_client_get_name (GDBusObjectManagerClient *manager)
+{
+ g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
+ return manager->priv->name;
+}
+
+/**
+ * g_dbus_object_manager_client_get_flags:
+ * @manager: A #GDBusObjectManagerClient
+ *
+ * Gets the flags that @manager was constructed with.
+ *
+ * Returns: Zero of more flags from the #GDBusObjectManagerClientFlags
+ * enumeration.
+ */
+GDBusObjectManagerClientFlags
+g_dbus_object_manager_client_get_flags (GDBusObjectManagerClient *manager)
+{
+ g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE);
+ return manager->priv->flags;
+}
+
+/**
+ * g_dbus_object_manager_client_get_name_owner:
+ * @manager: A #GDBusObjectManagerClient.
+ *
+ * The unique name that owns the name that @manager is for or %NULL if
+ * no-one currently owns that name. You can connect to the
+ * #GObject::notify signal to track changes to the
+ * #GDBusObjectManagerClient:name-owner property.
+ *
+ * Returns: The name owner or %NULL if no name owner exists. Free with
+ * g_free().
+ */
+gchar *
+g_dbus_object_manager_client_get_name_owner (GDBusObjectManagerClient *manager)
+{
+ g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
+ return g_strdup (manager->priv->name_owner);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* signal handler for all objects we manage - we dispatch signals
+ * from here to the objects
+ */
+static void
+signal_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
+ GDBusObjectProxy *object_proxy;
+ GDBusInterface *interface;
+
+ object_proxy = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
+ if (object_proxy == NULL)
+ goto out;
+
+ //g_debug ("yay, signal_cb %s %s: %s\n", signal_name, object_path, g_variant_print (parameters, TRUE));
+
+ if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0)
+ {
+ if (g_strcmp0 (signal_name, "PropertiesChanged") == 0)
+ {
+ const gchar *interface_name;
+ GVariant *changed_properties;
+ const gchar **invalidated_properties;
+
+ g_variant_get (parameters,
+ "(&s a{sv}^a&s)",
+ &interface_name,
+ &changed_properties,
+ &invalidated_properties);
+
+ interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name);
+ if (interface != NULL)
+ {
+ GVariantIter property_iter;
+ const gchar *property_name;
+ GVariant *property_value;
+ guint n;
+
+ /* update caches... */
+ g_variant_iter_init (&property_iter, changed_properties);
+ while (g_variant_iter_next (&property_iter,
+ "{&sv}",
+ &property_name,
+ &property_value))
+ {
+ g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
+ property_name,
+ property_value);
+ g_variant_unref (property_value);
+ }
+
+ for (n = 0; invalidated_properties[n] != NULL; n++)
+ {
+ g_dbus_proxy_set_cached_property (G_DBUS_PROXY (interface),
+ invalidated_properties[n],
+ NULL);
+ }
+ /* ... and then synthesize the signal */
+ g_signal_emit (manager,
+ signals[INTERFACE_PROXY_PROPERTIES_CHANGED_SIGNAL],
+ 0,
+ object_proxy,
+ interface,
+ changed_properties,
+ invalidated_properties);
+ g_signal_emit_by_name (interface,
+ "g-properties-changed",
+ changed_properties,
+ invalidated_properties);
+ g_object_unref (interface);
+ }
+ g_variant_unref (changed_properties);
+ g_free (invalidated_properties);
+ }
+ }
+ else
+ {
+ /* regular signal - just dispatch it */
+ interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object_proxy), interface_name);
+ if (interface != NULL)
+ {
+ g_signal_emit (manager,
+ signals[INTERFACE_PROXY_SIGNAL_SIGNAL],
+ 0,
+ object_proxy,
+ interface,
+ sender_name,
+ signal_name,
+ parameters);
+ g_signal_emit_by_name (interface,
+ "g-signal",
+ sender_name,
+ signal_name,
+ parameters);
+ g_object_unref (interface);
+ }
+ }
+
+ out:
+ ;
+}
+
+static void
+subscribe_signals (GDBusObjectManagerClient *manager,
+ const gchar *name_owner)
+{
+ GError *error;
+ GVariant *ret;
+
+ g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
+ g_return_if_fail (manager->priv->signal_subscription_id == 0);
+ g_return_if_fail (g_dbus_is_unique_name (name_owner));
+
+ /* the bus daemon may not implement path_prefix so gracefully
+ * handle this by using a fallback
+ */
+ manager->priv->match_rule = g_strdup_printf ("type='signal',sender='%s',path_namespace='%s'",
+ name_owner,
+ manager->priv->object_path);
+
+ error = NULL;
+ ret = g_dbus_connection_call_sync (manager->priv->connection,
+ "org.freedesktop.DBus",
+ "/org/freedeskop/DBus",
+ "org.freedesktop.DBus",
+ "AddMatch",
+ g_variant_new ("(s)",
+ manager->priv->match_rule),
+ NULL, /* reply_type */
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, /* default timeout */
+ NULL, /* TODO: Cancellable */
+ &error);
+ if (ret != NULL)
+ {
+ /* yay, bus daemon supports path_namespace */
+ g_variant_unref (ret);
+
+ /* still need to ask GDBusConnection for the callbacks */
+ manager->priv->signal_subscription_id =
+ g_dbus_connection_signal_subscribe (manager->priv->connection,
+ name_owner,
+ NULL, /* interface */
+ NULL, /* member */
+ NULL, /* path - TODO: really want wilcard support here */
+ NULL, /* arg0 */
+ G_DBUS_SIGNAL_FLAGS_NONE |
+ G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
+ signal_cb,
+ manager,
+ NULL); /* user_data_free_func */
+
+ }
+ else
+ {
+ /* TODO: we could report this to the user
+ g_warning ("Message bus daemon does not support path_namespace: %s (%s %d)",
+ error->message,
+ g_quark_to_string (error->domain),
+ error->code);
+ */
+
+ g_error_free (error);
+
+ /* no need to call RemoveMatch when done since it didn't work */
+ g_free (manager->priv->match_rule);
+ manager->priv->match_rule = NULL;
+
+ /* Fallback is to subscribe to *all* signals from the name owner which
+ * is rather wasteful. It's probably not a big practical problem because
+ * users typically want all objects that the name owner supplies.
+ */
+ manager->priv->signal_subscription_id =
+ g_dbus_connection_signal_subscribe (manager->priv->connection,
+ name_owner,
+ NULL, /* interface */
+ NULL, /* member */
+ NULL, /* path - TODO: really want wilcard support here */
+ NULL, /* arg0 */
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ signal_cb,
+ manager,
+ NULL); /* user_data_free_func */
+ }
+}
+
+static void
+maybe_unsubscribe_signals (GDBusObjectManagerClient *manager)
+{
+ g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
+
+ if (manager->priv->signal_subscription_id > 0)
+ {
+ g_dbus_connection_signal_unsubscribe (manager->priv->connection,
+ manager->priv->signal_subscription_id);
+ manager->priv->signal_subscription_id = 0;
+ }
+
+ if (manager->priv->match_rule != NULL)
+ {
+ /* Since the AddMatch call succeeded this is guaranteed to not
+ * fail - therefore, don't bother checking the return value
+ */
+ g_dbus_connection_call (manager->priv->connection,
+ "org.freedesktop.DBus",
+ "/org/freedeskop/DBus",
+ "org.freedesktop.DBus",
+ "RemoveMatch",
+ g_variant_new ("(s)",
+ manager->priv->match_rule),
+ NULL, /* reply_type */
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, /* default timeout */
+ NULL, /* GCancellable */
+ NULL, /* GAsyncReadyCallback */
+ NULL); /* user data */
+ g_free (manager->priv->match_rule);
+ manager->priv->match_rule = NULL;
+ }
+
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_notify_g_name_owner (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
+ gchar *old_name_owner;
+ gchar *new_name_owner;
+
+ old_name_owner = manager->priv->name_owner;
+ new_name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
+ manager->priv->name_owner = NULL;
+
+ if (g_strcmp0 (old_name_owner, new_name_owner) != 0)
+ {
+ GList *l;
+ GList *proxies;
+
+ /* do the :name-owner notify with a NULL name - this way the user knows
+ * the ::object-proxy-removed following is because the name owner went
+ * away
+ */
+ g_object_notify (G_OBJECT (manager), "name-owner");
+
+ /* remote manager changed; nuke all local proxies */
+ proxies = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
+ g_list_foreach (proxies, (GFunc) g_object_ref, NULL);
+ g_hash_table_remove_all (manager->priv->map_object_path_to_object_proxy);
+ for (l = proxies; l != NULL; l = l->next)
+ {
+ GDBusObjectProxy *object_proxy = G_DBUS_OBJECT_PROXY (l->data);
+ g_signal_emit_by_name (manager, "object-removed", object_proxy);
+ }
+ g_list_foreach (proxies, (GFunc) g_object_unref, NULL);
+ g_list_free (proxies);
+
+ /* nuke local filter */
+ maybe_unsubscribe_signals (manager);
+ }
+
+ if (new_name_owner != NULL)
+ {
+ GError *error;
+ GVariant *value;
+
+ //g_debug ("repopulating for %s", new_name_owner);
+
+ /* TODO: do this async! */
+ subscribe_signals (manager,
+ new_name_owner);
+ error = NULL;
+ value = g_dbus_proxy_call_sync (manager->priv->control_proxy,
+ "GetManagedObjects",
+ NULL, /* parameters */
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (value == NULL)
+ {
+ maybe_unsubscribe_signals (manager);
+ g_warning ("Error calling GetManagedObjects() when name owner %s for name %s came back: %s",
+ new_name_owner,
+ manager->priv->name,
+ error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ process_get_all_result (manager, value, new_name_owner);
+ g_variant_unref (value);
+ }
+
+ /* do the :name-owner notify *AFTER* emitting ::object-proxy-added signals - this
+ * way the user knows that the signals were emitted because the name owner came back
+ */
+ manager->priv->name_owner = new_name_owner;
+ g_object_notify (G_OBJECT (manager), "name-owner");
+
+ }
+ g_free (old_name_owner);
+}
+
+static gboolean
+initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (initable);
+ gboolean ret;
+ GVariant *value;
+ GDBusProxyFlags proxy_flags;
+
+ ret = FALSE;
+
+ if (manager->priv->bus_type != G_BUS_TYPE_NONE)
+ {
+ g_assert (manager->priv->connection == NULL);
+ manager->priv->connection = g_bus_get_sync (manager->priv->bus_type, cancellable, error);
+ if (manager->priv->connection == NULL)
+ goto out;
+ }
+
+ proxy_flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
+ if (manager->priv->flags & G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START)
+ proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;;
+
+ manager->priv->control_proxy = g_dbus_proxy_new_sync (manager->priv->connection,
+ proxy_flags,
+ NULL, /* GDBusInterfaceInfo* */
+ manager->priv->name,
+ manager->priv->object_path,
+ "org.freedesktop.DBus.ObjectManager",
+ cancellable,
+ error);
+ if (manager->priv->control_proxy == NULL)
+ goto out;
+
+ g_signal_connect (G_OBJECT (manager->priv->control_proxy),
+ "notify::g-name-owner",
+ G_CALLBACK (on_notify_g_name_owner),
+ manager);
+
+ manager->priv->name_owner = g_dbus_proxy_get_name_owner (manager->priv->control_proxy);
+ if (manager->priv->name_owner == NULL)
+ {
+ /* it's perfectly fine if there's no name owner.. we're just going to
+ * wait until one is ready
+ */
+ }
+ else
+ {
+ /* yay, we have a name owner */
+ g_signal_connect (manager->priv->control_proxy,
+ "g-signal",
+ G_CALLBACK (on_control_proxy_g_signal),
+ manager);
+ subscribe_signals (manager,
+ manager->priv->name_owner);
+ value = g_dbus_proxy_call_sync (manager->priv->control_proxy,
+ "GetManagedObjects",
+ NULL, /* parameters */
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cancellable,
+ error);
+ if (value == NULL)
+ {
+ maybe_unsubscribe_signals (manager);
+ g_warn_if_fail (g_signal_handlers_disconnect_by_func (manager->priv->control_proxy,
+ on_control_proxy_g_signal,
+ manager) == 1);
+ g_object_unref (manager->priv->control_proxy);
+ manager->priv->control_proxy = NULL;
+ goto out;
+ }
+
+ process_get_all_result (manager, value, manager->priv->name_owner);
+ g_variant_unref (value);
+ }
+
+ ret = TRUE;
+
+ out:
+ return ret;
+}
+
+static void
+initable_iface_init (GInitableIface *initable_iface)
+{
+ initable_iface->init = initable_init;
+}
+
+static void
+async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
+{
+ /* for now, just use default: run GInitable code in thread */
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+add_interfaces (GDBusObjectManagerClient *manager,
+ const gchar *object_path,
+ GVariant *ifaces_and_properties,
+ const gchar *name_owner)
+{
+ GDBusObjectProxy *op;
+ gboolean added;
+ GVariantIter iter;
+ const gchar *interface_name;
+ GVariant *properties;
+
+ g_return_if_fail (g_dbus_is_unique_name (name_owner));
+
+ added = FALSE;
+ op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
+ if (op == NULL)
+ {
+ op = _g_dbus_object_proxy_new (manager->priv->connection, object_path);
+ added = TRUE;
+ }
+
+ g_variant_iter_init (&iter, ifaces_and_properties);
+ while (g_variant_iter_next (&iter,
+ "{&s a{sv}}",
+ &interface_name,
+ &properties))
+ {
+ GDBusProxy *interface_proxy;
+ GError *error;
+ GType interface_proxy_type;
+
+ if (manager->priv->get_proxy_type_func != NULL)
+ {
+ interface_proxy_type = manager->priv->get_proxy_type_func (manager,
+ object_path,
+ interface_name,
+ manager->priv->get_proxy_type_user_data);
+ g_warn_if_fail (g_type_is_a (interface_proxy_type, G_TYPE_DBUS_PROXY));
+ }
+ else
+ {
+ interface_proxy_type = G_TYPE_DBUS_PROXY;
+ }
+
+ /* this is fine - there is no blocking IO because we pass DO_NOT_LOAD_PROPERTIES and
+ * DO_NOT_CONNECT_SIGNALS and use a unique name
+ */
+ error = NULL;
+ interface_proxy = g_initable_new (interface_proxy_type,
+ NULL, /* GCancellable */
+ &error,
+ "g-connection", manager->priv->connection,
+ "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
+ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
+ "g-name", name_owner,
+ "g-object-path", object_path,
+ "g-interface-name", interface_name,
+ NULL);
+ if (interface_proxy == NULL)
+ {
+ g_warning ("%s: Error constructing proxy for path %s and interface %s: %s",
+ G_STRLOC,
+ object_path,
+ interface_name,
+ error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ GVariantIter property_iter;
+ const gchar *property_name;
+ GVariant *property_value;
+
+ /* associate the interface proxy with the object */
+ g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_proxy),
+ G_DBUS_OBJECT (op));
+
+ g_variant_iter_init (&property_iter, properties);
+ while (g_variant_iter_next (&property_iter,
+ "{&sv}",
+ &property_name,
+ &property_value))
+ {
+ g_dbus_proxy_set_cached_property (interface_proxy,
+ property_name,
+ property_value);
+ g_variant_unref (property_value);
+ }
+
+ _g_dbus_object_proxy_add_interface (op, interface_proxy);
+ if (!added)
+ g_signal_emit_by_name (manager, "interface-added", op, interface_proxy);
+ g_object_unref (interface_proxy);
+ }
+ g_variant_unref (properties);
+ }
+
+ if (added)
+ {
+ g_hash_table_insert (manager->priv->map_object_path_to_object_proxy,
+ g_strdup (object_path),
+ op);
+ g_signal_emit_by_name (manager, "object-added", op);
+ }
+}
+
+static void
+remove_interfaces (GDBusObjectManagerClient *manager,
+ const gchar *object_path,
+ const gchar *const *interface_names)
+{
+ GDBusObjectProxy *op;
+ GList *interfaces;
+ guint n;
+ guint num_interfaces;
+ guint num_interfaces_to_remove;
+
+ op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
+ if (op == NULL)
+ {
+ g_warning ("%s: Processing InterfaceRemoved signal for path %s but no object proxy exists",
+ G_STRLOC,
+ object_path);
+ goto out;
+ }
+
+ interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (op));
+ num_interfaces = g_list_length (interfaces);
+ g_list_foreach (interfaces, (GFunc) g_object_unref, NULL);
+ g_list_free (interfaces);
+
+ num_interfaces_to_remove = g_strv_length ((gchar **) interface_names);
+
+ /* see if we are going to completety remove the object */
+ if (num_interfaces_to_remove == num_interfaces)
+ {
+ g_object_ref (op);
+ g_warn_if_fail (g_hash_table_remove (manager->priv->map_object_path_to_object_proxy, object_path));
+ g_signal_emit_by_name (manager, "object-removed", op);
+ g_object_unref (op);
+ }
+ else
+ {
+ for (n = 0; interface_names != NULL && interface_names[n] != NULL; n++)
+ {
+ GDBusInterface *interface;
+ interface = g_dbus_object_get_interface (G_DBUS_OBJECT (op), interface_names[n]);
+ _g_dbus_object_proxy_remove_interface (op, interface_names[n]);
+ if (interface != NULL)
+ {
+ g_signal_emit_by_name (manager, "interface-removed", op, interface);
+ g_object_unref (interface);
+ }
+ }
+ }
+ out:
+ ;
+}
+
+static void
+process_get_all_result (GDBusObjectManagerClient *manager,
+ GVariant *value,
+ const gchar *name_owner)
+{
+ GVariant *arg0;
+ const gchar *object_path;
+ GVariant *ifaces_and_properties;
+ GVariantIter iter;
+
+ g_return_if_fail (g_dbus_is_unique_name (name_owner));
+
+ arg0 = g_variant_get_child_value (value, 0);
+ g_variant_iter_init (&iter, arg0);
+ while (g_variant_iter_next (&iter,
+ "{&o a{sa{sv}}}",
+ &object_path,
+ &ifaces_and_properties))
+ {
+ add_interfaces (manager, object_path, ifaces_and_properties, name_owner);
+ g_variant_unref (ifaces_and_properties);
+ }
+ g_variant_unref (arg0);
+}
+
+static void
+on_control_proxy_g_signal (GDBusProxy *proxy,
+ const gchar *sender_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (user_data);
+ const gchar *object_path;
+
+ //g_debug ("yay, g_signal %s: %s\n", signal_name, g_variant_print (parameters, TRUE));
+
+ if (g_strcmp0 (signal_name, "InterfacesAdded") == 0)
+ {
+ GVariant *ifaces_and_properties;
+ g_variant_get (parameters,
+ "(&o a{sa{sv}})",
+ &object_path,
+ &ifaces_and_properties);
+ add_interfaces (manager, object_path, ifaces_and_properties, manager->priv->name_owner);
+ g_variant_unref (ifaces_and_properties);
+ }
+ else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0)
+ {
+ const gchar **ifaces;
+ g_variant_get (parameters,
+ "(&o^a&s)",
+ &object_path,
+ &ifaces);
+ remove_interfaces (manager, object_path, ifaces);
+ g_free (ifaces);
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static const gchar *
+g_dbus_object_manager_client_get_object_path (GDBusObjectManager *_manager)
+{
+ GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
+ return manager->priv->object_path;
+}
+
+static GDBusObject *
+g_dbus_object_manager_client_get_object (GDBusObjectManager *_manager,
+ const gchar *object_path)
+{
+ GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
+ GDBusObject *ret;
+
+ ret = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
+ if (ret != NULL)
+ g_object_ref (ret);
+ return ret;
+}
+
+static GDBusInterface *
+g_dbus_object_manager_client_get_interface (GDBusObjectManager *_manager,
+ const gchar *object_path,
+ const gchar *interface_name)
+{
+ GDBusInterface *ret;
+ GDBusObject *object;
+
+ ret = NULL;
+
+ object = g_dbus_object_manager_get_object (_manager, object_path);
+ if (object == NULL)
+ goto out;
+
+ ret = g_dbus_object_get_interface (object, interface_name);
+ g_object_unref (object);
+
+ out:
+ return ret;
+}
+
+static GList *
+g_dbus_object_manager_client_get_objects (GDBusObjectManager *_manager)
+{
+ GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (_manager);
+ GList *ret;
+
+ g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager), NULL);
+
+ ret = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy);
+ g_list_foreach (ret, (GFunc) g_object_ref, NULL);
+ return ret;
+}
+
+
+static void
+dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
+{
+ iface->get_object_path = g_dbus_object_manager_client_get_object_path;
+ iface->get_objects = g_dbus_object_manager_client_get_objects;
+ iface->get_object = g_dbus_object_manager_client_get_object;
+ iface->get_interface = g_dbus_object_manager_client_get_interface;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
diff --git a/gio/gdbusobjectmanagerclient.h b/gio/gdbusobjectmanagerclient.h
new file mode 100644
index 0000000..386c63d
--- /dev/null
+++ b/gio/gdbusobjectmanagerclient.h
@@ -0,0 +1,129 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __G_DBUS_OBJECT_MANAGER_CLIENT_H__
+#define __G_DBUS_OBJECT_MANAGER_CLIENT_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_DBUS_OBJECT_MANAGER_CLIENT (g_dbus_object_manager_client_get_type ())
+#define G_DBUS_OBJECT_MANAGER_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_OBJECT_MANAGER_CLIENT, GDBusObjectManagerClient))
+#define G_DBUS_OBJECT_MANAGER_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_OBJECT_MANAGER_CLIENT, GDBusObjectManagerClientClass))
+#define G_DBUS_OBJECT_MANAGER_CLIENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_OBJECT_MANAGER_CLIENT, GDBusObjectManagerClientClass))
+#define G_IS_DBUS_OBJECT_MANAGER_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_OBJECT_MANAGER_CLIENT))
+#define G_IS_DBUS_OBJECT_MANAGER_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_OBJECT_MANAGER_CLIENT))
+
+typedef struct _GDBusObjectManagerClientClass GDBusObjectManagerClientClass;
+typedef struct _GDBusObjectManagerClientPrivate GDBusObjectManagerClientPrivate;
+
+/**
+ * GDBusObjectManagerClient:
+ *
+ * The #GDBusObjectManagerClient structure contains private data and should
+ * only be accessed using the provided API.
+ */
+struct _GDBusObjectManagerClient
+{
+ /*< private >*/
+ GObject parent_instance;
+ GDBusObjectManagerClientPrivate *priv;
+};
+
+/**
+ * GDBusObjectManagerClientClass:
+ * @parent_class: The parent class.
+ * @interface_proxy_signal: Signal class handler for the #GDBusObjectManagerClient::interface-proxy-signal signal.
+ * @interface_proxy_properties_changed: Signal class handler for the #GDBusObjectManagerClient::interface-proxy-properties-changed signal.
+ *
+ * Class structure for #GDBusObjectManagerClient.
+ */
+struct _GDBusObjectManagerClientClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (*interface_proxy_signal) (GDBusObjectManagerClient *manager,
+ GDBusObjectProxy *object_proxy,
+ GDBusProxy *interface_proxy,
+ const gchar *sender_name,
+ const gchar *signal_name,
+ GVariant *parameters);
+
+ void (*interface_proxy_properties_changed) (GDBusObjectManagerClient *manager,
+ GDBusObjectProxy *object_proxy,
+ GDBusProxy *interface_proxy,
+ GVariant *changed_properties,
+ const gchar* const *invalidated_properties);
+
+ /*< private >*/
+ gpointer padding[8];
+};
+
+GType g_dbus_object_manager_client_get_type (void) G_GNUC_CONST;
+void g_dbus_object_manager_client_new (GDBusConnection *connection,
+ GDBusObjectManagerClientFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GDBusProxyTypeFunc get_proxy_type_func,
+ gpointer get_proxy_type_user_data,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GDBusObjectManager *g_dbus_object_manager_client_new_finish (GAsyncResult *res,
+ GError **error);
+GDBusObjectManager *g_dbus_object_manager_client_new_sync (GDBusConnection *connection,
+ GDBusObjectManagerClientFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GDBusProxyTypeFunc get_proxy_type_func,
+ gpointer get_proxy_type_user_data,
+ GCancellable *cancellable,
+ GError **error);
+void g_dbus_object_manager_client_new_for_bus (GBusType bus_type,
+ GDBusObjectManagerClientFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GDBusProxyTypeFunc get_proxy_type_func,
+ gpointer get_proxy_type_user_data,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GDBusObjectManager *g_dbus_object_manager_client_new_for_bus_finish (GAsyncResult *res,
+ GError **error);
+GDBusObjectManager *g_dbus_object_manager_client_new_for_bus_sync (GBusType bus_type,
+ GDBusObjectManagerClientFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GDBusProxyTypeFunc get_proxy_type_func,
+ gpointer get_proxy_type_user_data,
+ GCancellable *cancellable,
+ GError **error);
+GDBusConnection *g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient *manager);
+GDBusObjectManagerClientFlags g_dbus_object_manager_client_get_flags (GDBusObjectManagerClient *manager);
+const gchar *g_dbus_object_manager_client_get_name (GDBusObjectManagerClient *manager);
+gchar *g_dbus_object_manager_client_get_name_owner (GDBusObjectManagerClient *manager);
+
+G_END_DECLS
+
+#endif /* __G_DBUS_OBJECT_MANAGER_CLIENT_H */
diff --git a/gio/gdbusobjectmanagerserver.c b/gio/gdbusobjectmanagerserver.c
new file mode 100644
index 0000000..ed7c575
--- /dev/null
+++ b/gio/gdbusobjectmanagerserver.c
@@ -0,0 +1,898 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include "gdbusobjectmanager.h"
+#include "gdbusobjectmanagerserver.h"
+#include "gdbusobject.h"
+#include "gdbusobjectstub.h"
+#include "gdbusinterfacestub.h"
+#include "gdbusconnection.h"
+#include "gdbusintrospection.h"
+#include "gdbusmethodinvocation.h"
+#include "gdbuserror.h"
+
+#include "glibintl.h"
+
+/**
+ * SECTION:gdbusobjectmanagerserver
+ * @short_description: Service-side object manager
+ * @include: gio/gio.h
+ *
+ * #GDBusObjectManagerServer is used to export #GDBusObject instances using
+ * the standardized <ulink
+ * url="http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager">org.freedesktop.DBus.ObjectManager</ulink>
+ * interface. For example, remote D-Bus clients can get all objects
+ * and properties in a single call. Additionally, any change in the
+ * object hierarchy is broadcast using signals. This means that D-Bus
+ * clients can keep caches up to date by only listening to D-Bus
+ * signals.
+ *
+ * See #GDBusObjectManagerClient for the client-side code that is intended to
+ * be used with #GDBusObjectManagerServer.
+ */
+
+typedef struct
+{
+ GDBusObjectStub *object;
+ GDBusObjectManagerServer *manager;
+ GHashTable *map_iface_name_to_iface;
+ gboolean exported;
+} RegistrationData;
+
+static void registration_data_free (RegistrationData *data);
+
+static void g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager,
+ RegistrationData *data,
+ const gchar *const *interfaces);
+
+static void g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager,
+ RegistrationData *data,
+ const gchar *const *interfaces);
+
+struct _GDBusObjectManagerServerPrivate
+{
+ GDBusConnection *connection;
+ gchar *object_path;
+ gchar *object_path_ending_in_slash;
+ GHashTable *map_object_path_to_data;
+ guint manager_reg_id;
+};
+
+enum
+{
+ PROP_0,
+ PROP_CONNECTION,
+ PROP_OBJECT_PATH
+};
+
+static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerServer, g_dbus_object_manager_server, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init));
+
+static void g_dbus_object_manager_server_constructed (GObject *object);
+
+static void
+g_dbus_object_manager_server_finalize (GObject *object)
+{
+ GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
+
+ g_hash_table_unref (manager->priv->map_object_path_to_data);
+ if (manager->priv->manager_reg_id > 0)
+ g_warn_if_fail (g_dbus_connection_unregister_object (manager->priv->connection, manager->priv->manager_reg_id));
+ g_object_unref (manager->priv->connection);
+ g_free (manager->priv->object_path);
+ g_free (manager->priv->object_path_ending_in_slash);
+
+ if (G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->finalize (object);
+}
+
+static void
+g_dbus_object_manager_server_get_property (GObject *_object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_object);
+
+ switch (prop_id)
+ {
+ case PROP_CONNECTION:
+ g_value_set_object (value, g_dbus_object_manager_server_get_connection (manager));
+ break;
+
+ case PROP_OBJECT_PATH:
+ g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_dbus_object_manager_server_set_property (GObject *_object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_object);
+
+ switch (prop_id)
+ {
+ case PROP_CONNECTION:
+ g_assert (manager->priv->connection == NULL);
+ g_assert (G_IS_DBUS_CONNECTION (g_value_get_object (value)));
+ manager->priv->connection = g_value_dup_object (value);
+ break;
+
+ case PROP_OBJECT_PATH:
+ g_assert (manager->priv->object_path == NULL);
+ g_assert (g_variant_is_object_path (g_value_get_string (value)));
+ manager->priv->object_path = g_value_dup_string (value);
+ manager->priv->object_path_ending_in_slash = g_strdup_printf ("%s/", manager->priv->object_path);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_dbus_object_manager_server_class_init (GDBusObjectManagerServerClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = g_dbus_object_manager_server_finalize;
+ gobject_class->constructed = g_dbus_object_manager_server_constructed;
+ gobject_class->set_property = g_dbus_object_manager_server_set_property;
+ gobject_class->get_property = g_dbus_object_manager_server_get_property;
+
+ /**
+ * GDBusObjectManagerServer:connection:
+ *
+ * The #GDBusConnection to export objects on.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_CONNECTION,
+ g_param_spec_object ("connection",
+ "Connection",
+ "The connection to export objects on",
+ G_TYPE_DBUS_CONNECTION,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GDBusObjectManagerServer:object-path:
+ *
+ * The object path to register the manager object at.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_OBJECT_PATH,
+ g_param_spec_string ("object-path",
+ "Object Path",
+ "The object path to register the manager object at",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_type_class_add_private (klass, sizeof (GDBusObjectManagerServerPrivate));
+}
+
+static void
+g_dbus_object_manager_server_init (GDBusObjectManagerServer *manager)
+{
+ manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
+ G_TYPE_DBUS_OBJECT_MANAGER_SERVER,
+ GDBusObjectManagerServerPrivate);
+ manager->priv->map_object_path_to_data = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) registration_data_free);
+}
+
+/**
+ * g_dbus_object_manager_server_new:
+ * @connection: A #GDBusConnection.
+ * @object_path: The object path to export the manager object at.
+ *
+ * Creates a new #GDBusObjectManagerServer object.
+ *
+ * TODO: make it so that the objects are not exported yet -
+ * e.g. start()/stop() semantics.
+ *
+ * Returns: A #GDBusObjectManagerServer object. Free with g_object_unref().
+ */
+GDBusObjectManagerServer *
+g_dbus_object_manager_server_new (GDBusConnection *connection,
+ const gchar *object_path)
+{
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
+ return G_DBUS_OBJECT_MANAGER_SERVER (g_object_new (G_TYPE_DBUS_OBJECT_MANAGER_SERVER,
+ "connection", connection,
+ "object-path", object_path,
+ NULL));
+}
+
+/**
+ * g_dbus_object_manager_server_get_connection:
+ * @manager: A #GDBusObjectManagerServer
+ *
+ * Gets the #GDBusConnection used by @manager.
+ *
+ * Returns: A #GDBusConnection object. Do not free, the object belongs
+ * to @manager.
+ */
+GDBusConnection *
+g_dbus_object_manager_server_get_connection (GDBusObjectManagerServer *manager)
+{
+ g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), NULL);
+ return manager->priv->connection;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+registration_data_export_interface (RegistrationData *data,
+ GDBusInterfaceStub *interface_stub)
+{
+ GDBusInterfaceInfo *info;
+ GError *error;
+ const gchar *object_path;
+
+ object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
+
+ info = g_dbus_interface_stub_get_info (interface_stub);
+ error = NULL;
+ if (!g_dbus_interface_stub_export (interface_stub,
+ data->manager->priv->connection,
+ object_path,
+ &error))
+ {
+ /* TODO: probably wrong to complain on stderr */
+ g_warning ("%s: Error registering object at %s with interface %s: %s",
+ G_STRLOC,
+ object_path,
+ info->name,
+ error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ g_assert (g_hash_table_lookup (data->map_iface_name_to_iface, info->name) == NULL);
+ g_hash_table_insert (data->map_iface_name_to_iface,
+ info->name,
+ g_object_ref (interface_stub));
+
+ /* if we are already exported, then... */
+ if (data->exported)
+ {
+ const gchar *interfaces[2];
+ /* emit InterfacesAdded on the ObjectManager object */
+ interfaces[0] = info->name;
+ interfaces[1] = NULL;
+ g_dbus_object_manager_server_emit_interfaces_added (data->manager, data, interfaces);
+ }
+
+ out:
+ ;
+}
+
+static void
+registration_data_unexport_interface (RegistrationData *data,
+ GDBusInterfaceStub *interface_stub)
+{
+ GDBusInterfaceInfo *info;
+ GDBusInterfaceStub *iface;
+
+ info = g_dbus_interface_stub_get_info (interface_stub);
+ iface = g_hash_table_lookup (data->map_iface_name_to_iface, info->name);
+ g_assert (iface != NULL);
+
+ g_dbus_interface_stub_unexport (iface);
+
+ g_warn_if_fail (g_hash_table_remove (data->map_iface_name_to_iface, info->name));
+
+ /* if we are already exported, then... */
+ if (data->exported)
+ {
+ const gchar *interfaces[2];
+ /* emit InterfacesRemoved on the ObjectManager object */
+ interfaces[0] = info->name;
+ interfaces[1] = NULL;
+ g_dbus_object_manager_server_emit_interfaces_removed (data->manager, data, interfaces);
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_interface_added (GDBusObject *object,
+ GDBusInterface *interface,
+ gpointer user_data)
+{
+ RegistrationData *data = user_data;
+ registration_data_export_interface (data, G_DBUS_INTERFACE_STUB (interface));
+}
+
+static void
+on_interface_removed (GDBusObject *object,
+ GDBusInterface *interface,
+ gpointer user_data)
+{
+ RegistrationData *data = user_data;
+ registration_data_unexport_interface (data, G_DBUS_INTERFACE_STUB (interface));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+
+static void
+registration_data_free (RegistrationData *data)
+{
+ GHashTableIter iter;
+ GDBusInterfaceStub *iface;
+
+ data->exported = FALSE;
+
+ g_hash_table_iter_init (&iter, data->map_iface_name_to_iface);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer) &iface))
+ g_dbus_interface_stub_unexport (iface);
+
+ g_signal_handlers_disconnect_by_func (data->object, G_CALLBACK (on_interface_added), data);
+ g_signal_handlers_disconnect_by_func (data->object, G_CALLBACK (on_interface_removed), data);
+ g_object_unref (data->object);
+ g_hash_table_destroy (data->map_iface_name_to_iface);
+ g_free (data);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_dbus_object_manager_server_export:
+ * @manager: A #GDBusObjectManagerServer.
+ * @object: A #GDBusObjectStub.
+ *
+ * Exports @object on @manager.
+ *
+ * If there is already a #GDBusObject exported at the object path,
+ * then the old object is removed.
+ *
+ * The object path for @object must be in the hierarchy rooted by the
+ * object path for @manager.
+ *
+ * Note that @manager will take a reference on @object for as long as
+ * it is exported.
+ */
+void
+g_dbus_object_manager_server_export (GDBusObjectManagerServer *manager,
+ GDBusObjectStub *object)
+{
+ RegistrationData *data;
+ GList *existing_interfaces;
+ GList *l;
+ GPtrArray *interface_names;
+ const gchar *object_path;
+
+ object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
+
+ g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
+ g_return_if_fail (G_IS_DBUS_OBJECT (object));
+ g_return_if_fail (g_str_has_prefix (object_path, manager->priv->object_path_ending_in_slash));
+
+ interface_names = g_ptr_array_new ();
+
+ data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
+ if (data != NULL)
+ g_dbus_object_manager_server_unexport (manager, object_path);
+
+ data = g_new0 (RegistrationData, 1);
+ data->object = g_object_ref (object);
+ data->manager = manager;
+ data->map_iface_name_to_iface = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ NULL,
+ (GDestroyNotify) g_object_unref);
+
+ g_signal_connect (object,
+ "interface-added",
+ G_CALLBACK (on_interface_added),
+ data);
+ g_signal_connect (object,
+ "interface-removed",
+ G_CALLBACK (on_interface_removed),
+ data);
+
+ /* Register all known interfaces - note that data->exported is FALSE so
+ * we don't emit any InterfacesAdded signals.
+ */
+ existing_interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (object));
+ for (l = existing_interfaces; l != NULL; l = l->next)
+ {
+ GDBusInterfaceStub *interface_stub = G_DBUS_INTERFACE_STUB (l->data);
+ registration_data_export_interface (data, interface_stub);
+ g_ptr_array_add (interface_names, g_dbus_interface_stub_get_info (interface_stub)->name);
+ }
+ g_list_foreach (existing_interfaces, (GFunc) g_object_unref, NULL);
+ g_list_free (existing_interfaces);
+ g_ptr_array_add (interface_names, NULL);
+
+ data->exported = TRUE;
+
+ /* now emit InterfacesAdded() for all the interfaces */
+ g_dbus_object_manager_server_emit_interfaces_added (manager, data, (const gchar *const *) interface_names->pdata);
+ g_ptr_array_unref (interface_names);
+
+ g_hash_table_insert (manager->priv->map_object_path_to_data,
+ g_strdup (object_path),
+ data);
+}
+
+/**
+ * g_dbus_object_manager_server_export_and_uniquify:
+ * @manager: A #GDBusObjectManagerServer.
+ * @object: An object.
+ *
+ * Like g_dbus_object_manager_server_export() but appends a string of
+ * the form <literal>_N</literal> (with N being a natural number) to
+ * @object<!-- -->'s object path if an object with the given path
+ * already exists. As such, the #GDBusObjectProxy:object-path property
+ * of @object may be modified.
+ */
+void
+g_dbus_object_manager_server_export_and_uniquify (GDBusObjectManagerServer *manager,
+ GDBusObjectStub *object)
+{
+ gchar *orig_object_path;
+ gchar *object_path;
+ guint count;
+ gboolean modified;
+
+ orig_object_path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
+
+ g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
+ g_return_if_fail (G_IS_DBUS_OBJECT (object));
+ g_return_if_fail (g_str_has_prefix (orig_object_path, manager->priv->object_path_ending_in_slash));
+
+ object_path = g_strdup (orig_object_path);
+ count = 1;
+ modified = FALSE;
+ while (TRUE)
+ {
+ RegistrationData *data;
+ data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
+ if (data == NULL)
+ {
+ break;
+ }
+ g_free (object_path);
+ object_path = g_strdup_printf ("%s_%d", orig_object_path, count++);
+ modified = TRUE;
+ }
+
+ if (modified)
+ g_dbus_object_stub_set_object_path (G_DBUS_OBJECT_STUB (object), object_path);
+
+ g_dbus_object_manager_server_export (manager, object);
+
+ g_free (object_path);
+ g_free (orig_object_path);
+}
+
+/**
+ * g_dbus_object_manager_server_unexport:
+ * @manager: A #GDBusObjectManagerServer.
+ * @object_path: An object path.
+ *
+ * If @manager has an object at @path, removes the object. Otherwise
+ * does nothing.
+ *
+ * Note that @object_path must be in the hierarchy rooted by the
+ * object path for @manager.
+ */
+void
+g_dbus_object_manager_server_unexport (GDBusObjectManagerServer *manager,
+ const gchar *object_path)
+{
+ RegistrationData *data;
+
+ g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
+ g_return_if_fail (g_variant_is_object_path (object_path));
+ g_return_if_fail (g_str_has_prefix (object_path, manager->priv->object_path_ending_in_slash));
+
+ data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
+ if (data != NULL)
+ {
+ GPtrArray *interface_names;
+ GHashTableIter iter;
+ const gchar *iface_name;
+
+ interface_names = g_ptr_array_new ();
+ g_hash_table_iter_init (&iter, data->map_iface_name_to_iface);
+ while (g_hash_table_iter_next (&iter, (gpointer) &iface_name, NULL))
+ g_ptr_array_add (interface_names, (gpointer) iface_name);
+ g_ptr_array_add (interface_names, NULL);
+ /* now emit InterfacesRemoved() for all the interfaces */
+ g_dbus_object_manager_server_emit_interfaces_removed (manager, data, (const gchar *const *) interface_names->pdata);
+ g_ptr_array_unref (interface_names);
+
+ g_hash_table_remove (manager->priv->map_object_path_to_data, object_path);
+ }
+}
+
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static const GDBusArgInfo manager_interfaces_added_signal_info_arg0 =
+{
+ -1,
+ "object_path",
+ "o",
+ (GDBusAnnotationInfo**) NULL,
+};
+
+static const GDBusArgInfo manager_interfaces_added_signal_info_arg1 =
+{
+ -1,
+ "interfaces_and_properties",
+ "a{sa{sv}}",
+ (GDBusAnnotationInfo**) NULL,
+};
+
+static const GDBusArgInfo * const manager_interfaces_added_signal_info_arg_pointers[] =
+{
+ &manager_interfaces_added_signal_info_arg0,
+ &manager_interfaces_added_signal_info_arg1,
+ NULL
+};
+
+static const GDBusSignalInfo manager_interfaces_added_signal_info =
+{
+ -1,
+ "InterfacesAdded",
+ (GDBusArgInfo**) &manager_interfaces_added_signal_info_arg_pointers,
+ (GDBusAnnotationInfo**) NULL
+};
+
+/* ---------- */
+
+static const GDBusArgInfo manager_interfaces_removed_signal_info_arg0 =
+{
+ -1,
+ "object_path",
+ "o",
+ (GDBusAnnotationInfo**) NULL,
+};
+
+static const GDBusArgInfo manager_interfaces_removed_signal_info_arg1 =
+{
+ -1,
+ "interfaces",
+ "as",
+ (GDBusAnnotationInfo**) NULL,
+};
+
+static const GDBusArgInfo * const manager_interfaces_removed_signal_info_arg_pointers[] =
+{
+ &manager_interfaces_removed_signal_info_arg0,
+ &manager_interfaces_removed_signal_info_arg1,
+ NULL
+};
+
+static const GDBusSignalInfo manager_interfaces_removed_signal_info =
+{
+ -1,
+ "InterfacesRemoved",
+ (GDBusArgInfo**) &manager_interfaces_removed_signal_info_arg_pointers,
+ (GDBusAnnotationInfo**) NULL
+};
+
+/* ---------- */
+
+static const GDBusSignalInfo * const manager_signal_info_pointers[] =
+{
+ &manager_interfaces_added_signal_info,
+ &manager_interfaces_removed_signal_info,
+ NULL
+};
+
+/* ---------- */
+
+static const GDBusArgInfo manager_get_all_method_info_out_arg0 =
+{
+ -1,
+ "object_paths_interfaces_and_properties",
+ "a{oa{sa{sv}}}",
+ (GDBusAnnotationInfo**) NULL,
+};
+
+static const GDBusArgInfo * const manager_get_all_method_info_out_arg_pointers[] =
+{
+ &manager_get_all_method_info_out_arg0,
+ NULL
+};
+
+static const GDBusMethodInfo manager_get_all_method_info =
+{
+ -1,
+ "GetManagedObjects",
+ (GDBusArgInfo**) NULL,
+ (GDBusArgInfo**) &manager_get_all_method_info_out_arg_pointers,
+ (GDBusAnnotationInfo**) NULL
+};
+
+static const GDBusMethodInfo * const manager_method_info_pointers[] =
+{
+ &manager_get_all_method_info,
+ NULL
+};
+
+/* ---------- */
+
+static const GDBusInterfaceInfo manager_interface_info =
+{
+ -1,
+ "org.freedesktop.DBus.ObjectManager",
+ (GDBusMethodInfo **) manager_method_info_pointers,
+ (GDBusSignalInfo **) manager_signal_info_pointers,
+ (GDBusPropertyInfo **) NULL,
+ (GDBusAnnotationInfo **) NULL
+};
+
+static void
+manager_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (user_data);
+ GVariantBuilder array_builder;
+ GHashTableIter object_iter;
+ RegistrationData *data;
+
+ if (g_strcmp0 (method_name, "GetManagedObjects") == 0)
+ {
+ g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a{oa{sa{sv}}}"));
+ g_hash_table_iter_init (&object_iter, manager->priv->map_object_path_to_data);
+ while (g_hash_table_iter_next (&object_iter, NULL, (gpointer) &data))
+ {
+ GVariantBuilder interfaces_builder;
+ GHashTableIter interface_iter;
+ GDBusInterfaceStub *iface;
+ const gchar *iter_object_path;
+
+ g_variant_builder_init (&interfaces_builder, G_VARIANT_TYPE ("a{sa{sv}}"));
+ g_hash_table_iter_init (&interface_iter, data->map_iface_name_to_iface);
+ while (g_hash_table_iter_next (&interface_iter, NULL, (gpointer) &iface))
+ {
+ g_variant_builder_add_value (&interfaces_builder,
+ g_variant_new ("{s a{sv}}",
+ g_dbus_interface_stub_get_info (iface)->name,
+ g_dbus_interface_stub_get_properties (iface)));
+ }
+ iter_object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
+ g_variant_builder_add (&array_builder,
+ "{oa{sa{sv}}}",
+ iter_object_path,
+ &interfaces_builder);
+ }
+
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("(a{oa{sa{sv}}})",
+ &array_builder));
+ }
+ else
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_UNKNOWN_METHOD,
+ "Unknown method %s - only GetManagedObjects() is supported",
+ method_name);
+ }
+}
+
+static const GDBusInterfaceVTable manager_interface_vtable =
+{
+ manager_method_call, /* handle_method_call */
+ NULL, /* get_property */
+ NULL /* set_property */
+};
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+g_dbus_object_manager_server_constructed (GObject *object)
+{
+ GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
+ GError *error;
+
+ error = NULL;
+ manager->priv->manager_reg_id = g_dbus_connection_register_object (manager->priv->connection,
+ manager->priv->object_path,
+ (GDBusInterfaceInfo *) &manager_interface_info,
+ &manager_interface_vtable,
+ manager,
+ NULL, /* user_data_free_func */
+ &error);
+ if (manager->priv->manager_reg_id == 0)
+ {
+ /* TODO: probably wrong to complain on stderr */
+ g_warning ("%s: Error registering manager at %s: %s",
+ G_STRLOC,
+ manager->priv->object_path,
+ error->message);
+ g_error_free (error);
+ }
+
+ if (G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed (object);
+}
+
+static void
+g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager,
+ RegistrationData *data,
+ const gchar *const *interfaces)
+{
+ GVariantBuilder array_builder;
+ GError *error;
+ guint n;
+ const gchar *object_path;
+
+ g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a{sa{sv}}"));
+ for (n = 0; interfaces[n] != NULL; n++)
+ {
+ GDBusInterfaceStub *iface;
+ iface = g_hash_table_lookup (data->map_iface_name_to_iface, interfaces[n]);
+ g_assert (iface != NULL);
+ g_variant_builder_add_value (&array_builder,
+ g_variant_new ("{s a{sv}}",
+ interfaces[n],
+ g_dbus_interface_stub_get_properties (iface)));
+ }
+
+ error = NULL;
+ object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
+ g_dbus_connection_emit_signal (data->manager->priv->connection,
+ NULL, /* destination_bus_name */
+ manager->priv->object_path,
+ manager_interface_info.name,
+ "InterfacesAdded",
+ g_variant_new ("(oa{sa{sv}})",
+ object_path,
+ &array_builder),
+ &error);
+ g_assert_no_error (error);
+}
+
+static void
+g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager,
+ RegistrationData *data,
+ const gchar *const *interfaces)
+{
+ GVariantBuilder array_builder;
+ GError *error;
+ guint n;
+ const gchar *object_path;
+
+ g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as"));
+ for (n = 0; interfaces[n] != NULL; n++)
+ g_variant_builder_add (&array_builder, "s", interfaces[n]);
+
+ error = NULL;
+ object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
+ g_dbus_connection_emit_signal (data->manager->priv->connection,
+ NULL, /* destination_bus_name */
+ manager->priv->object_path,
+ manager_interface_info.name,
+ "InterfacesRemoved",
+ g_variant_new ("(oas)",
+ object_path,
+ &array_builder),
+ &error);
+ g_assert_no_error (error);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GList *
+g_dbus_object_manager_server_get_objects (GDBusObjectManager *_manager)
+{
+ GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
+ GList *ret;
+ GHashTableIter iter;
+ RegistrationData *data;
+
+ ret = NULL;
+ g_hash_table_iter_init (&iter, manager->priv->map_object_path_to_data);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer) &data))
+ {
+ ret = g_list_prepend (ret, g_object_ref (data->object));
+ }
+
+ return ret;
+}
+
+static const gchar *
+g_dbus_object_manager_server_get_object_path (GDBusObjectManager *_manager)
+{
+ GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
+ return manager->priv->object_path;
+}
+
+static GDBusObject *
+g_dbus_object_manager_server_get_object (GDBusObjectManager *_manager,
+ const gchar *object_path)
+{
+ GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
+ GDBusObject *ret;
+ RegistrationData *data;
+
+ ret = NULL;
+ data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
+ if (data != NULL)
+ ret = g_object_ref (data->object);
+ return ret;
+}
+
+static GDBusInterface *
+g_dbus_object_manager_server_get_interface (GDBusObjectManager *_manager,
+ const gchar *object_path,
+ const gchar *interface_name)
+{
+ GDBusInterface *ret;
+ GDBusObject *object;
+
+ ret = NULL;
+
+ object = g_dbus_object_manager_get_object (_manager, object_path);
+ if (object == NULL)
+ goto out;
+
+ ret = g_dbus_object_get_interface (object, interface_name);
+ g_object_unref (object);
+
+ out:
+ return ret;
+}
+
+static void
+dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
+{
+ iface->get_object_path = g_dbus_object_manager_server_get_object_path;
+ iface->get_objects = g_dbus_object_manager_server_get_objects;
+ iface->get_object = g_dbus_object_manager_server_get_object;
+ iface->get_interface = g_dbus_object_manager_server_get_interface;
+}
diff --git a/gio/gdbusobjectmanagerserver.h b/gio/gdbusobjectmanagerserver.h
new file mode 100644
index 0000000..baf964e
--- /dev/null
+++ b/gio/gdbusobjectmanagerserver.h
@@ -0,0 +1,80 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __G_DBUS_OBJECT_MANAGER_SERVER_H__
+#define __G_DBUS_OBJECT_MANAGER_SERVER_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_DBUS_OBJECT_MANAGER_SERVER (g_dbus_object_manager_server_get_type ())
+#define G_DBUS_OBJECT_MANAGER_SERVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_OBJECT_MANAGER_SERVER, GDBusObjectManagerServer))
+#define G_DBUS_OBJECT_MANAGER_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_OBJECT_MANAGER_SERVER, GDBusObjectManagerServerClass))
+#define G_DBUS_OBJECT_MANAGER_SERVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_OBJECT_MANAGER_SERVER, GDBusObjectManagerServerClass))
+#define G_IS_DBUS_OBJECT_MANAGER_SERVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_OBJECT_MANAGER_SERVER))
+#define G_IS_DBUS_OBJECT_MANAGER_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_OBJECT_MANAGER_SERVER))
+
+typedef struct _GDBusObjectManagerServerClass GDBusObjectManagerServerClass;
+typedef struct _GDBusObjectManagerServerPrivate GDBusObjectManagerServerPrivate;
+
+/**
+ * GDBusObjectManagerServer:
+ *
+ * The #GDBusObjectManagerServer structure contains private data and should
+ * only be accessed using the provided API.
+ */
+struct _GDBusObjectManagerServer
+{
+ /*< private >*/
+ GObject parent_instance;
+ GDBusObjectManagerServerPrivate *priv;
+};
+
+/**
+ * GDBusObjectManagerServerClass:
+ * @parent_class: The parent class.
+ *
+ * Class structure for #GDBusObjectManagerServer.
+ */
+struct _GDBusObjectManagerServerClass
+{
+ GObjectClass parent_class;
+
+ /*< private >*/
+ gpointer padding[8];
+};
+
+GType g_dbus_object_manager_server_get_type (void) G_GNUC_CONST;
+GDBusObjectManagerServer *g_dbus_object_manager_server_new (GDBusConnection *connection,
+ const gchar *object_path);
+GDBusConnection *g_dbus_object_manager_server_get_connection (GDBusObjectManagerServer *manager);
+void g_dbus_object_manager_server_export (GDBusObjectManagerServer *manager,
+ GDBusObjectStub *object);
+void g_dbus_object_manager_server_export_and_uniquify (GDBusObjectManagerServer *manager,
+ GDBusObjectStub *object);
+void g_dbus_object_manager_server_unexport (GDBusObjectManagerServer *manager,
+ const gchar *object_path);
+
+G_END_DECLS
+
+#endif /* __G_DBUS_OBJECT_MANAGER_SERVER_H */
diff --git a/gio/gdbusobjectproxy.c b/gio/gdbusobjectproxy.c
new file mode 100644
index 0000000..3c26495
--- /dev/null
+++ b/gio/gdbusobjectproxy.c
@@ -0,0 +1,315 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include "gdbusobject.h"
+#include "gdbusobjectproxy.h"
+#include "gdbusconnection.h"
+#include "gdbusprivate.h"
+#include "gdbusutils.h"
+#include "gdbusproxy.h"
+
+#include "glibintl.h"
+
+/**
+ * SECTION:gdbusobjectproxy
+ * @short_description: Client-side D-Bus object
+ * @include: gio/gio.h
+ *
+ * A #GDBusObjectProxy is an object used to represent a remote object
+ * with one or more D-Bus interfaces. You cannot instantiate a
+ * #GDBusObjectProxy yourself - you need to use a
+ * #GDBusObjectManagerClient to get one.
+ */
+
+struct _GDBusObjectProxyPrivate
+{
+ GHashTable *map_name_to_iface;
+ gchar *object_path;
+ GDBusConnection *connection;
+};
+
+enum
+{
+ PROP_0,
+ PROP_OBJECT_PATH,
+ PROP_CONNECTION
+};
+
+static void dbus_object_interface_init (GDBusObjectIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GDBusObjectProxy, g_dbus_object_proxy, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT, dbus_object_interface_init));
+
+static void
+g_dbus_object_proxy_finalize (GObject *object)
+{
+ GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
+
+ g_hash_table_unref (proxy->priv->map_name_to_iface);
+
+ if (G_OBJECT_CLASS (g_dbus_object_proxy_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (g_dbus_object_proxy_parent_class)->finalize (object);
+}
+
+static void
+g_dbus_object_proxy_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
+
+ switch (prop_id)
+ {
+ case PROP_OBJECT_PATH:
+ g_value_set_string (value, proxy->priv->object_path);
+ break;
+
+ case PROP_CONNECTION:
+ g_value_set_object (value, g_dbus_object_proxy_get_connection (proxy));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_dbus_object_proxy_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_dbus_object_proxy_class_init (GDBusObjectProxyClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = g_dbus_object_proxy_finalize;
+ gobject_class->set_property = g_dbus_object_proxy_set_property;
+ gobject_class->get_property = g_dbus_object_proxy_get_property;
+
+ /**
+ * GDBusObjectProxy:object-path:
+ *
+ * The object path of the proxy.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_OBJECT_PATH,
+ g_param_spec_string ("object-path",
+ "Object Path",
+ "The object path of the proxy",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GDBusObjectProxy:connection:
+ *
+ * The connection of the proxy.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_CONNECTION,
+ g_param_spec_string ("connection",
+ "Connection",
+ "The connection of the proxy",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_type_class_add_private (klass, sizeof (GDBusObjectProxyPrivate));
+}
+
+static void
+g_dbus_object_proxy_init (GDBusObjectProxy *proxy)
+{
+ proxy->priv = G_TYPE_INSTANCE_GET_PRIVATE (proxy,
+ G_TYPE_DBUS_OBJECT_PROXY,
+ GDBusObjectProxyPrivate);
+ proxy->priv->map_name_to_iface = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) g_object_unref);
+}
+
+static const gchar *
+g_dbus_object_proxy_get_object_path (GDBusObject *object)
+{
+ GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
+ return proxy->priv->object_path;
+}
+
+/**
+ * g_dbus_object_proxy_get_connection:
+ * @proxy: A #GDBusObjectProxy.
+ *
+ * Gets the connection that @proxy is for.
+ *
+ * Returns: A #GDBusConnection. Do not free, the object is owned by @proxy.
+ */
+GDBusConnection *
+g_dbus_object_proxy_get_connection (GDBusObjectProxy *proxy)
+{
+ g_return_val_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy), NULL);
+ return proxy->priv->connection;
+}
+
+static GDBusInterface *
+g_dbus_object_proxy_get_interface (GDBusObject *object,
+ const gchar *interface_name)
+{
+ GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
+ GDBusProxy *ret;
+
+ g_return_val_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy), NULL);
+ g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
+
+ ret = g_hash_table_lookup (proxy->priv->map_name_to_iface, interface_name);
+ if (ret != NULL)
+ g_object_ref (ret);
+ return (GDBusInterface *) ret; /* TODO: proper cast */
+}
+
+static GList *
+g_dbus_object_proxy_get_interfaces (GDBusObject *object)
+{
+ GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
+ GList *ret;
+ GHashTableIter iter;
+ GDBusProxy *interface_proxy;
+
+ g_return_val_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy), NULL);
+
+ ret = NULL;
+
+ g_hash_table_iter_init (&iter, proxy->priv->map_name_to_iface);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer) &interface_proxy))
+ ret = g_list_prepend (ret, g_object_ref (interface_proxy));
+
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+GDBusObjectProxy *
+_g_dbus_object_proxy_new (GDBusConnection *connection,
+ const gchar *object_path)
+{
+ GDBusObjectProxy *proxy;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
+
+ proxy = G_DBUS_OBJECT_PROXY (g_object_new (G_TYPE_DBUS_OBJECT_PROXY, NULL));
+ proxy->priv->object_path = g_strdup (object_path);
+ proxy->priv->connection = g_object_ref (connection);
+ return proxy;
+}
+
+void
+_g_dbus_object_proxy_add_interface (GDBusObjectProxy *proxy,
+ GDBusProxy *interface_proxy)
+{
+ const gchar *interface_name;
+
+ g_return_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy));
+ g_return_if_fail (G_IS_DBUS_PROXY (interface_proxy));
+
+ interface_name = g_dbus_proxy_get_interface_name (interface_proxy);
+ _g_dbus_object_proxy_remove_interface (proxy, interface_name);
+ g_hash_table_insert (proxy->priv->map_name_to_iface,
+ g_strdup (interface_name),
+ g_object_ref (interface_proxy));
+ g_signal_emit_by_name (proxy, "interface-added", interface_proxy);
+}
+
+void
+_g_dbus_object_proxy_remove_interface (GDBusObjectProxy *proxy,
+ const gchar *interface_name)
+{
+ GDBusProxy *interface_proxy;
+
+ g_return_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy));
+ g_return_if_fail (g_dbus_is_interface_name (interface_name));
+
+ interface_proxy = g_hash_table_lookup (proxy->priv->map_name_to_iface, interface_name);
+ if (interface_proxy != NULL)
+ {
+ g_object_ref (interface_proxy);
+ g_warn_if_fail (g_hash_table_remove (proxy->priv->map_name_to_iface, interface_name));
+ g_signal_emit_by_name (proxy, "interface-removed", interface_proxy);
+ g_object_unref (interface_proxy);
+ }
+}
+
+static gpointer
+g_dbus_object_proxy_lookup_with_typecheck (GDBusObject *object,
+ const gchar *interface_name,
+ GType type)
+{
+ GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
+ GDBusProxy *ret;
+
+ g_return_val_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy), NULL);
+ g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
+
+ ret = g_hash_table_lookup (proxy->priv->map_name_to_iface, interface_name);
+ if (ret != NULL)
+ {
+ g_warn_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (ret, type));
+ g_object_ref (ret);
+ }
+ return ret;
+}
+
+static gpointer
+g_dbus_object_proxy_peek_with_typecheck (GDBusObject *object,
+ const gchar *interface_name,
+ GType type)
+{
+ GDBusProxy *ret;
+ ret = g_dbus_object_proxy_lookup_with_typecheck (object, interface_name, type);
+ if (ret != NULL)
+ g_object_unref (ret);
+ return ret;
+}
+
+static void
+dbus_object_interface_init (GDBusObjectIface *iface)
+{
+ iface->get_object_path = g_dbus_object_proxy_get_object_path;
+ iface->get_interfaces = g_dbus_object_proxy_get_interfaces;
+ iface->get_interface = g_dbus_object_proxy_get_interface;
+ iface->peek_with_typecheck = g_dbus_object_proxy_peek_with_typecheck;
+ iface->lookup_with_typecheck = g_dbus_object_proxy_lookup_with_typecheck;
+}
diff --git a/gio/gdbusobjectproxy.h b/gio/gdbusobjectproxy.h
new file mode 100644
index 0000000..d5cd619
--- /dev/null
+++ b/gio/gdbusobjectproxy.h
@@ -0,0 +1,72 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __G_DBUS_OBJECT_PROXY_H__
+#define __G_DBUS_OBJECT_PROXY_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_DBUS_OBJECT_PROXY (g_dbus_object_proxy_get_type ())
+#define G_DBUS_OBJECT_PROXY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_OBJECT_PROXY, GDBusObjectProxy))
+#define G_DBUS_OBJECT_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_OBJECT_PROXY, GDBusObjectProxyClass))
+#define G_DBUS_OBJECT_PROXY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_OBJECT_PROXY, GDBusObjectProxyClass))
+#define G_IS_DBUS_OBJECT_PROXY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_OBJECT_PROXY))
+#define G_IS_DBUS_OBJECT_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_OBJECT_PROXY))
+
+typedef struct _GDBusObjectProxyClass GDBusObjectProxyClass;
+typedef struct _GDBusObjectProxyPrivate GDBusObjectProxyPrivate;
+
+/**
+ * GDBusObjectProxy:
+ *
+ * The #GDBusObjectProxy structure contains private data and should
+ * only be accessed using the provided API.
+ */
+struct _GDBusObjectProxy
+{
+ /*< private >*/
+ GObject parent_instance;
+ GDBusObjectProxyPrivate *priv;
+};
+
+/**
+ * GDBusObjectProxyClass:
+ * @parent_class: The parent class.
+ *
+ * Class structure for #GDBusObjectProxy.
+ */
+struct _GDBusObjectProxyClass
+{
+ GObjectClass parent_class;
+
+ /*< private >*/
+ gpointer padding[8];
+};
+
+GType g_dbus_object_proxy_get_type (void) G_GNUC_CONST;
+GDBusConnection *g_dbus_object_proxy_get_connection (GDBusObjectProxy *proxy);
+
+G_END_DECLS
+
+#endif /* __G_DBUS_OBJECT_PROXY_H */
diff --git a/gio/gdbusobjectstub.c b/gio/gdbusobjectstub.c
new file mode 100644
index 0000000..7b60db5
--- /dev/null
+++ b/gio/gdbusobjectstub.c
@@ -0,0 +1,475 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include "gdbusobject.h"
+#include "gdbusobjectstub.h"
+#include "gdbusinterfacestub.h"
+#include "gio-marshal.h"
+#include "gdbusprivate.h"
+#include "gdbusmethodinvocation.h"
+#include "gdbusintrospection.h"
+#include "gdbusinterface.h"
+#include "gdbusutils.h"
+
+#include "glibintl.h"
+
+/**
+ * SECTION:gdbusobjectstub
+ * @short_description: Service-side D-Bus object
+ * @include: gio/gio.h
+ *
+ * A #GDBusObjectStub instance is essentially a group of D-Bus
+ * interfaces. The set of exported interfaces on the object may be
+ * dynamic and change at runtime.
+ *
+ * This type is intended to be used with #GDBusObjectManager.
+ */
+
+struct _GDBusObjectStubPrivate
+{
+ gchar *object_path;
+ GHashTable *map_name_to_iface;
+};
+
+enum
+{
+ PROP_0,
+ PROP_OBJECT_PATH
+};
+
+enum
+{
+ AUTHORIZE_METHOD_SIGNAL,
+ LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
+static void dbus_object_interface_init (GDBusObjectIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GDBusObjectStub, g_dbus_object_stub, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT, dbus_object_interface_init));
+
+
+static void
+g_dbus_object_stub_finalize (GObject *_object)
+{
+ GDBusObjectStub *object = G_DBUS_OBJECT_STUB (_object);
+
+ g_free (object->priv->object_path);
+ g_hash_table_unref (object->priv->map_name_to_iface);
+
+ if (G_OBJECT_CLASS (g_dbus_object_stub_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (g_dbus_object_stub_parent_class)->finalize (_object);
+}
+
+static void
+g_dbus_object_stub_get_property (GObject *_object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GDBusObjectStub *object = G_DBUS_OBJECT_STUB (_object);
+
+ switch (prop_id)
+ {
+ case PROP_OBJECT_PATH:
+ g_value_take_string (value, object->priv->object_path);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_dbus_object_stub_set_property (GObject *_object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GDBusObjectStub *object = G_DBUS_OBJECT_STUB (_object);
+
+ switch (prop_id)
+ {
+ case PROP_OBJECT_PATH:
+ g_dbus_object_stub_set_object_path (object, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+g_dbus_object_stub_authorize_method_default (GDBusObjectStub *object,
+ GDBusInterfaceStub *interface,
+ GDBusMethodInvocation *invocation)
+{
+ return TRUE;
+}
+
+static void
+g_dbus_object_stub_class_init (GDBusObjectStubClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = g_dbus_object_stub_finalize;
+ gobject_class->set_property = g_dbus_object_stub_set_property;
+ gobject_class->get_property = g_dbus_object_stub_get_property;
+
+ klass->authorize_method = g_dbus_object_stub_authorize_method_default;
+
+ /**
+ * GDBusObjectStub:object-path:
+ *
+ * The object path where the object is exported.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_OBJECT_PATH,
+ g_param_spec_string ("object-path",
+ "Object Path",
+ "The object path where the object is exported",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GDBusObjectStub::authorize-method:
+ * @object: The #GDBusObjectStub emitting the signal.
+ * @interface: The #GDBusInterfaceStub that @invocation is on.
+ * @invocation: A #GDBusMethodInvocation.
+ *
+ * Emitted when a method is invoked by a remote caller and used to
+ * determine if the method call is authorized.
+ *
+ * This signal is like #GDBusInterfaceStub<!-- -->'s
+ * #GDBusInterfaceStub::g-authorize-method signal, except that it is
+ * for the enclosing object.
+ *
+ * The default class handler just returns %TRUE.
+ *
+ * Returns: %TRUE if the call is authorized, %FALSE otherwise.
+ */
+ signals[AUTHORIZE_METHOD_SIGNAL] =
+ g_signal_new ("authorize-method",
+ G_TYPE_DBUS_OBJECT_STUB,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GDBusObjectStubClass, authorize_method),
+ _g_signal_accumulator_false_handled,
+ NULL,
+ _gio_marshal_BOOLEAN__OBJECT_OBJECT,
+ G_TYPE_BOOLEAN,
+ 2,
+ G_TYPE_DBUS_INTERFACE_STUB,
+ G_TYPE_DBUS_METHOD_INVOCATION);
+
+ g_type_class_add_private (klass, sizeof (GDBusObjectStubPrivate));
+}
+
+static void
+g_dbus_object_stub_init (GDBusObjectStub *object)
+{
+ object->priv = G_TYPE_INSTANCE_GET_PRIVATE (object, G_TYPE_DBUS_OBJECT_STUB, GDBusObjectStubPrivate);
+ object->priv->map_name_to_iface = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) g_object_unref);
+}
+
+/**
+ * g_dbus_object_stub_new:
+ * @object_path: An object path.
+ *
+ * Creates a new #GDBusObjectStub.
+ *
+ * Returns: A #GDBusObjectStub. Free with g_object_unref().
+ */
+GDBusObjectStub *
+g_dbus_object_stub_new (const gchar *object_path)
+{
+ g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
+ return G_DBUS_OBJECT_STUB (g_object_new (G_TYPE_DBUS_OBJECT_STUB,
+ "object-path", object_path,
+ NULL));
+}
+
+/**
+ * g_dbus_object_stub_set_object_path:
+ * @object: A #GDBusObjectStub.
+ * @object_path: A valid D-Bus object path.
+ *
+ * Sets the object path for @object.
+ */
+void
+g_dbus_object_stub_set_object_path (GDBusObjectStub *object,
+ const gchar *object_path)
+{
+ g_return_if_fail (G_IS_DBUS_OBJECT_STUB (object));
+ g_return_if_fail (object_path == NULL || g_variant_is_object_path (object_path));
+ /* TODO: fail if object is currently exported */
+ if (g_strcmp0 (object->priv->object_path, object_path) != 0)
+ {
+ g_free (object->priv->object_path);
+ object->priv->object_path = g_strdup (object_path);
+ g_object_notify (G_OBJECT (object), "object-path");
+ }
+}
+
+static const gchar *
+g_dbus_object_stub_get_object_path (GDBusObject *_object)
+{
+ GDBusObjectStub *object = G_DBUS_OBJECT_STUB (_object);
+ return object->priv->object_path;
+}
+
+/**
+ * g_dbus_object_stub_add_interface:
+ * @object: A #GDBusObjectStub.
+ * @interface: A #GDBusInterfaceStub.
+ *
+ * Adds @interface to @object.
+ *
+ * If @object already contains a #GDBusInterfaceStub with the same
+ * interface name, it is removed before @interface is added.
+ *
+ * Note that @object takes its own reference on @interface and holds
+ * it until removed.
+ */
+void
+g_dbus_object_stub_add_interface (GDBusObjectStub *object,
+ GDBusInterfaceStub *interface)
+{
+ GDBusInterfaceInfo *info;
+
+ g_return_if_fail (G_IS_DBUS_OBJECT_STUB (object));
+ g_return_if_fail (G_IS_DBUS_INTERFACE_STUB (interface));
+
+ info = g_dbus_interface_stub_get_info (interface);
+ g_object_ref (interface);
+ g_dbus_object_stub_remove_interface_by_name (object, info->name);
+ g_hash_table_insert (object->priv->map_name_to_iface,
+ g_strdup (info->name),
+ interface);
+ g_dbus_interface_set_object (G_DBUS_INTERFACE (interface), G_DBUS_OBJECT (object));
+ g_signal_emit_by_name (object,
+ "interface-added",
+ interface);
+}
+
+/**
+ * g_dbus_object_stub_remove_interface:
+ * @object: A #GDBusObjectStub.
+ * @interface: A #GDBusInterfaceStub.
+ *
+ * Removes @interface from @object.
+ */
+void
+g_dbus_object_stub_remove_interface (GDBusObjectStub *object,
+ GDBusInterfaceStub *interface)
+{
+ GDBusInterfaceStub *other_interface;
+ GDBusInterfaceInfo *info;
+
+ g_return_if_fail (G_IS_DBUS_OBJECT_STUB (object));
+ g_return_if_fail (G_IS_DBUS_INTERFACE (interface));
+
+ info = g_dbus_interface_stub_get_info (interface);
+
+ other_interface = g_hash_table_lookup (object->priv->map_name_to_iface, info->name);
+ if (other_interface == NULL)
+ {
+ g_warning ("Tried to remove interface with name %s from object "
+ "at path %s but no such interface exists",
+ info->name,
+ object->priv->object_path);
+ }
+ else if (other_interface != interface)
+ {
+ g_warning ("Tried to remove interface %p with name %s from object "
+ "at path %s but the object has the interface %p",
+ interface,
+ info->name,
+ object->priv->object_path,
+ other_interface);
+ }
+ else
+ {
+ g_object_ref (interface);
+ g_warn_if_fail (g_hash_table_remove (object->priv->map_name_to_iface, info->name));
+ g_dbus_interface_set_object (G_DBUS_INTERFACE (interface), NULL);
+ g_signal_emit_by_name (object,
+ "interface-removed",
+ interface);
+ g_object_unref (interface);
+ }
+}
+
+
+/**
+ * g_dbus_object_stub_remove_interface_by_name:
+ * @object: A #GDBusObjectStub.
+ * @interface_name: A D-Bus interface name.
+ *
+ * Removes the #GDBusInterface with @interface_name from @object.
+ *
+ * If no D-Bus interface of the given interface exists, this function
+ * does nothing.
+ */
+void
+g_dbus_object_stub_remove_interface_by_name (GDBusObjectStub *object,
+ const gchar *interface_name)
+{
+ GDBusInterface *interface;
+
+ g_return_if_fail (G_IS_DBUS_OBJECT_STUB (object));
+ g_return_if_fail (g_dbus_is_interface_name (interface_name));
+
+ interface = g_hash_table_lookup (object->priv->map_name_to_iface, interface_name);
+ if (interface != NULL)
+ {
+ g_object_ref (interface);
+ g_warn_if_fail (g_hash_table_remove (object->priv->map_name_to_iface, interface_name));
+ g_dbus_interface_set_object (interface, NULL);
+ g_signal_emit_by_name (object,
+ "interface-removed",
+ interface);
+ g_object_unref (interface);
+ }
+}
+
+static GDBusInterface *
+g_dbus_object_stub_get_interface (GDBusObject *_object,
+ const gchar *interface_name)
+{
+ GDBusObjectStub *object = G_DBUS_OBJECT_STUB (_object);
+ GDBusInterface *ret;
+
+ g_return_val_if_fail (G_IS_DBUS_OBJECT_STUB (object), NULL);
+ g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
+
+ ret = g_hash_table_lookup (object->priv->map_name_to_iface, interface_name);
+ if (ret != NULL)
+ g_object_ref (ret);
+ return ret;
+}
+
+static GList *
+g_dbus_object_stub_get_interfaces (GDBusObject *_object)
+{
+ GDBusObjectStub *object = G_DBUS_OBJECT_STUB (_object);
+ GList *ret;
+ GHashTableIter iter;
+ GDBusInterface *interface;
+
+ g_return_val_if_fail (G_IS_DBUS_OBJECT_STUB (object), NULL);
+
+ ret = NULL;
+
+ g_hash_table_iter_init (&iter, object->priv->map_name_to_iface);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer) &interface))
+ ret = g_list_prepend (ret, g_object_ref (interface));
+
+ return ret;
+}
+
+/**
+ * g_dbus_object_stub_flush:
+ * @object: A #GDBusObjectStub.
+ *
+ * This method simply calls g_dbus_interface_stub_flush() on all
+ * interfaces stubs belonging to @object. See that method for when
+ * flushing is useful.
+ */
+void
+g_dbus_object_stub_flush (GDBusObjectStub *object)
+{
+ GHashTableIter iter;
+ GDBusInterfaceStub *interface_stub;
+
+ g_hash_table_iter_init (&iter, object->priv->map_name_to_iface);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer) &interface_stub))
+ {
+ g_dbus_interface_stub_flush (interface_stub);
+ }
+}
+
+static gpointer
+g_dbus_object_stub_lookup_with_typecheck (GDBusObject *object,
+ const gchar *interface_name,
+ GType type)
+{
+ GDBusObjectStub *stub = G_DBUS_OBJECT_STUB (object);
+ GDBusProxy *ret;
+
+ ret = g_hash_table_lookup (stub->priv->map_name_to_iface, interface_name);
+ if (ret != NULL)
+ {
+ g_warn_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (ret, type));
+ g_object_ref (ret);
+ }
+ return ret;
+}
+
+static gpointer
+g_dbus_object_stub_peek_with_typecheck (GDBusObject *object,
+ const gchar *interface_name,
+ GType type)
+{
+ GDBusInterfaceStub *ret;
+ ret = g_dbus_object_stub_lookup_with_typecheck (object, interface_name, type);
+ if (ret != NULL)
+ g_object_unref (ret);
+ return ret;
+}
+
+static void
+dbus_object_interface_init (GDBusObjectIface *iface)
+{
+ iface->get_object_path = g_dbus_object_stub_get_object_path;
+ iface->get_interfaces = g_dbus_object_stub_get_interfaces;
+ iface->get_interface = g_dbus_object_stub_get_interface;
+ iface->lookup_with_typecheck = g_dbus_object_stub_lookup_with_typecheck;
+ iface->peek_with_typecheck = g_dbus_object_stub_peek_with_typecheck;
+}
+
+gboolean
+_g_dbus_object_stub_has_authorize_method_handlers (GDBusObjectStub *stub)
+{
+ gboolean has_handlers;
+ gboolean has_default_class_handler;
+
+ has_handlers = g_signal_has_handler_pending (stub,
+ signals[AUTHORIZE_METHOD_SIGNAL],
+ 0,
+ TRUE);
+ has_default_class_handler = (G_DBUS_OBJECT_STUB_GET_CLASS (stub)->authorize_method ==
+ g_dbus_object_stub_authorize_method_default);
+
+ return has_handlers || !has_default_class_handler;
+}
diff --git a/gio/gdbusobjectstub.h b/gio/gdbusobjectstub.h
new file mode 100644
index 0000000..e5ebfc4
--- /dev/null
+++ b/gio/gdbusobjectstub.h
@@ -0,0 +1,87 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __G_DBUS_OBJECT_STUB_H__
+#define __G_DBUS_OBJECT_STUB_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_DBUS_OBJECT_STUB (g_dbus_object_stub_get_type ())
+#define G_DBUS_OBJECT_STUB(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_OBJECT_STUB, GDBusObjectStub))
+#define G_DBUS_OBJECT_STUB_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_OBJECT_STUB, GDBusObjectStubClass))
+#define G_DBUS_OBJECT_STUB_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_OBJECT_STUB, GDBusObjectStubClass))
+#define G_IS_DBUS_OBJECT_STUB(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_OBJECT_STUB))
+#define G_IS_DBUS_OBJECT_STUB_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_OBJECT_STUB))
+
+typedef struct _GDBusObjectStubClass GDBusObjectStubClass;
+typedef struct _GDBusObjectStubPrivate GDBusObjectStubPrivate;
+
+/**
+ * GDBusObjectStub:
+ *
+ * The #GDBusObjectStub structure contains private data and should only be
+ * accessed using the provided API.
+ */
+struct _GDBusObjectStub
+{
+ /*< private >*/
+ GObject parent_instance;
+ GDBusObjectStubPrivate *priv;
+};
+
+/**
+ * GDBusObjectStubClass:
+ * @parent_class: The parent class.
+ * @authorize_method: Signal class handler for the #GDBusObjectStub::authorize-method signal.
+ *
+ * Class structure for #GDBusObjectStub.
+ */
+struct _GDBusObjectStubClass
+{
+ GObjectClass parent_class;
+
+ /* Signals */
+ gboolean (*authorize_method) (GDBusObjectStub *stub,
+ GDBusInterfaceStub *interface_stub,
+ GDBusMethodInvocation *invocation);
+
+ /*< private >*/
+ gpointer padding[8];
+};
+
+GType g_dbus_object_stub_get_type (void) G_GNUC_CONST;
+GDBusObjectStub *g_dbus_object_stub_new (const gchar *object_path);
+void g_dbus_object_stub_flush (GDBusObjectStub *object);
+void g_dbus_object_stub_add_interface (GDBusObjectStub *object,
+ GDBusInterfaceStub *interface);
+void g_dbus_object_stub_remove_interface (GDBusObjectStub *object,
+ GDBusInterfaceStub *interface);
+void g_dbus_object_stub_remove_interface_by_name (GDBusObjectStub *object,
+ const gchar *interface_name);
+void g_dbus_object_stub_set_object_path (GDBusObjectStub *object,
+ const gchar *object_path);
+
+G_END_DECLS
+
+#endif /* __G_DBUS_OBJECT_STUB_H */
diff --git a/gio/gdbusprivate.c b/gio/gdbusprivate.c
index 9c2c58c..1e5bcf8 100644
--- a/gio/gdbusprivate.c
+++ b/gio/gdbusprivate.c
@@ -1869,3 +1869,21 @@ read_message_print_transport_debug (gssize bytes_read,
out:
;
}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+gboolean
+_g_signal_accumulator_false_handled (GSignalInvocationHint *ihint,
+ GValue *return_accu,
+ const GValue *handler_return,
+ gpointer dummy)
+{
+ gboolean continue_emission;
+ gboolean signal_return;
+
+ signal_return = g_value_get_boolean (handler_return);
+ g_value_set_boolean (return_accu, signal_return);
+ continue_emission = signal_return;
+
+ return continue_emission;
+}
diff --git a/gio/gdbusprivate.h b/gio/gdbusprivate.h
index 659e9d4..a39c192 100644
--- a/gio/gdbusprivate.h
+++ b/gio/gdbusprivate.h
@@ -112,8 +112,6 @@ gchar *_g_dbus_get_machine_id (GError **error);
gchar *_g_dbus_enum_to_string (GType enum_type, gint value);
-G_END_DECLS
-
/* ---------------------------------------------------------------------------------------------------- */
GDBusMethodInvocation *_g_dbus_method_invocation_new (const gchar *sender,
@@ -126,4 +124,22 @@ GDBusMethodInvocation *_g_dbus_method_invocation_new (const gchar *sen
GVariant *parameters,
gpointer user_data);
+/* ---------------------------------------------------------------------------------------------------- */
+
+gboolean _g_signal_accumulator_false_handled (GSignalInvocationHint *ihint,
+ GValue *return_accu,
+ const GValue *handler_return,
+ gpointer dummy);
+
+gboolean _g_dbus_object_stub_has_authorize_method_handlers (GDBusObjectStub *stub);
+
+GDBusObjectProxy *_g_dbus_object_proxy_new (GDBusConnection *connection,
+ const gchar *object_path);
+void _g_dbus_object_proxy_add_interface (GDBusObjectProxy *proxy,
+ GDBusProxy *interface_proxy);
+void _g_dbus_object_proxy_remove_interface (GDBusObjectProxy *proxy,
+ const gchar *interface_name);
+
+G_END_DECLS
+
#endif /* __G_DBUS_PRIVATE_H__ */
diff --git a/gio/gdbusproxy.c b/gio/gdbusproxy.c
index 67af1fb..14cb2ba 100644
--- a/gio/gdbusproxy.c
+++ b/gio/gdbusproxy.c
@@ -38,6 +38,7 @@
#include "gasyncresult.h"
#include "gsimpleasyncresult.h"
#include "gcancellable.h"
+#include "gdbusinterface.h"
#include "glibintl.h"
@@ -129,10 +130,12 @@ enum
guint signals[LAST_SIGNAL] = {0};
+static void dbus_interface_iface_init (GDBusInterfaceIface *dbus_interface_iface);
static void initable_iface_init (GInitableIface *initable_iface);
static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
G_DEFINE_TYPE_WITH_CODE (GDBusProxy, g_dbus_proxy, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_INTERFACE, dbus_interface_iface_init)
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
);
@@ -2548,3 +2551,36 @@ g_dbus_proxy_call_sync (GDBusProxy *proxy,
}
/* ---------------------------------------------------------------------------------------------------- */
+/* Hack until this is merged into libgio (extending types at run-time isn't really safe in any way) */
+
+static GDBusInterfaceInfo *
+_g_dbus_proxy_get_info (GDBusInterface *interface)
+{
+ GDBusProxy *proxy = G_DBUS_PROXY (interface);
+ return g_dbus_proxy_get_interface_info (proxy);
+}
+
+static GDBusObject *
+_g_dbus_proxy_get_object (GDBusInterface *interface)
+{
+ /* TODO */
+ return g_object_get_data (G_OBJECT (interface), "-x-gdbus-binding-tool-object");
+}
+
+static void
+_g_dbus_proxy_set_object (GDBusInterface *interface,
+ GDBusObject *object)
+{
+ /* TODO */
+ g_object_set_data (G_OBJECT (interface), "-x-gdbus-binding-tool-object", object);
+}
+
+static void
+dbus_interface_iface_init (GDBusInterfaceIface *dbus_interface_iface)
+{
+ dbus_interface_iface->get_info = _g_dbus_proxy_get_info;
+ dbus_interface_iface->get_object = _g_dbus_proxy_get_object;
+ dbus_interface_iface->set_object = _g_dbus_proxy_set_object;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
diff --git a/gio/gio-marshal.list b/gio/gio-marshal.list
index 8a42ad7..ad6d185 100644
--- a/gio/gio-marshal.list
+++ b/gio/gio-marshal.list
@@ -29,3 +29,6 @@ VOID:UINT64
BOOLEAN:FLAGS
BOOLEAN:OBJECT,FLAGS
OBJECT:VOID
+VOID:OBJECT,OBJECT
+VOID:OBJECT,OBJECT,STRING,STRING,VARIANT
+VOID:OBJECT,OBJECT,VARIANT,BOXED
diff --git a/gio/gio.h b/gio/gio.h
index 288da44..70cfe9f 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -130,6 +130,14 @@
#include <gio/gvolumemonitor.h>
#include <gio/gzlibcompressor.h>
#include <gio/gzlibdecompressor.h>
+#include <gio/gdbusinterface.h>
+#include <gio/gdbusinterfacestub.h>
+#include <gio/gdbusobject.h>
+#include <gio/gdbusobjectstub.h>
+#include <gio/gdbusobjectproxy.h>
+#include <gio/gdbusobjectmanager.h>
+#include <gio/gdbusobjectmanagerclient.h>
+#include <gio/gdbusobjectmanagerserver.h>
#undef __GIO_GIO_H_INSIDE__
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 64275ae..dcc5ac8 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -2086,3 +2086,99 @@ g_time_zone_monitor_get_type G_GNUC_CONST
g_time_zone_monitor_get
#endif
#endif
+
+#if IN_HEADER(__G_DBUS_INTERFACE_H__)
+#if IN_FILE(__G_DBUS_INTERFACE_C__)
+g_dbus_interface_get_info
+g_dbus_interface_get_object
+g_dbus_interface_get_type
+g_dbus_interface_set_object
+g_dbus_gvalue_to_gvariant
+g_dbus_gvariant_to_gvalue
+#endif
+#endif
+
+#if IN_HEADER(__G_DBUS_INTERFACE_STUB_H__)
+#if IN_FILE(__G_DBUS_INTERFACE_STUB_C__)
+g_dbus_interface_stub_export
+g_dbus_interface_stub_flags_get_type
+g_dbus_interface_stub_flush
+g_dbus_interface_stub_get_connection
+g_dbus_interface_stub_get_flags
+g_dbus_interface_stub_get_info
+g_dbus_interface_stub_get_object_path
+g_dbus_interface_stub_get_properties
+g_dbus_interface_stub_get_type
+g_dbus_interface_stub_get_vtable
+g_dbus_interface_stub_set_flags
+g_dbus_interface_stub_unexport
+#endif
+#endif
+
+#if IN_HEADER(__G_DBUS_OBJECT_H__)
+#if IN_FILE(__G_DBUS_OBJECT_C__)
+g_dbus_object_get_interface
+g_dbus_object_get_interfaces
+g_dbus_object_get_object_path
+g_dbus_object_get_type
+g_dbus_object_lookup_with_typecheck
+g_dbus_object_peek_with_typecheck
+#endif
+#endif
+
+#if IN_HEADER(__G_DBUS_OBJECT_PROXY_H__)
+#if IN_FILE(__G_DBUS_OBJECT_PROXY_C__)
+g_dbus_object_proxy_get_connection
+g_dbus_object_proxy_get_type
+#endif
+#endif
+
+#if IN_HEADER(__G_DBUS_OBJECT_STUB_H__)
+#if IN_FILE(__G_DBUS_OBJECT_STUB_C__)
+g_dbus_object_stub_add_interface
+g_dbus_object_stub_flush
+g_dbus_object_stub_get_type
+g_dbus_object_stub_new
+g_dbus_object_stub_remove_interface
+g_dbus_object_stub_remove_interface_by_name
+g_dbus_object_stub_set_object_path
+#endif
+#endif
+
+#if IN_HEADER(__G_DBUS_OBJECT_MANAGER_H__)
+#if IN_FILE(__G_DBUS_OBJECT_MANAGER_C__)
+g_dbus_object_manager_get_interface
+g_dbus_object_manager_get_object
+g_dbus_object_manager_get_object_path
+g_dbus_object_manager_get_objects
+g_dbus_object_manager_get_type
+#endif
+#endif
+
+#if IN_HEADER(__G_DBUS_OBJECT_MANAGER_CLIENT_H__)
+#if IN_FILE(__G_DBUS_OBJECT_MANAGER_CLIENT_C__)
+g_dbus_object_manager_client_flags_get_type
+g_dbus_object_manager_client_get_connection
+g_dbus_object_manager_client_get_flags
+g_dbus_object_manager_client_get_name
+g_dbus_object_manager_client_get_name_owner
+g_dbus_object_manager_client_get_type
+g_dbus_object_manager_client_new
+g_dbus_object_manager_client_new_finish
+g_dbus_object_manager_client_new_for_bus
+g_dbus_object_manager_client_new_for_bus_finish
+g_dbus_object_manager_client_new_for_bus_sync
+g_dbus_object_manager_client_new_sync
+#endif
+#endif
+
+#if IN_HEADER(__G_DBUS_OBJECT_MANAGER_SERVER_H__)
+#if IN_FILE(__G_DBUS_OBJECT_MANAGER_SERVER_C__)
+g_dbus_object_manager_server_export
+g_dbus_object_manager_server_export_and_uniquify
+g_dbus_object_manager_server_get_connection
+g_dbus_object_manager_server_get_type
+g_dbus_object_manager_server_new
+g_dbus_object_manager_server_unexport
+#endif
+#endif
diff --git a/gio/gioenums.h b/gio/gioenums.h
index 0989799..8961914 100644
--- a/gio/gioenums.h
+++ b/gio/gioenums.h
@@ -1383,6 +1383,42 @@ typedef enum {
G_TLS_REHANDSHAKE_UNSAFELY
} GTlsRehandshakeMode;
+/**
+ * GDBusInterfaceStubFlags:
+ * @G_DBUS_INTERFACE_STUB_FLAGS_NONE: No flags set.
+ * @G_DBUS_INTERFACE_STUB_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD: Each method invocation is handled in
+ * a thread dedicated to the invocation. This means that the method implementation can use blocking IO
+ * without blocking any other part of the process. It also means that the method implementation must
+ * use locking to access data structures used by other threads.
+ *
+ * Flags describing the behavior of a #GDBusInterfaceStub class.
+ *
+ * Since: 2.30
+ */
+typedef enum
+{
+ G_DBUS_INTERFACE_STUB_FLAGS_NONE = 0,
+ G_DBUS_INTERFACE_STUB_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD = (1<<0)
+} GDBusInterfaceStubFlags;
+
+/**
+ * GDBusObjectManagerClientFlags:
+ * @G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE: No flags set.
+ * @G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START: If not set and the
+ * manager is for a well-known name, then request the bus to launch
+ * an owner for the name if no-one owns the name. This flag can only
+ * be used in managers for well-known names.
+ *
+ * Flags used when constructing a #GDBusObjectManagerClient.
+ *
+ * Since: 2.30
+ */
+typedef enum
+{
+ G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE = 0,
+ G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START = (1<<0),
+} GDBusObjectManagerClientFlags;
+
G_END_DECLS
#endif /* __GIO_ENUMS_H__ */
diff --git a/gio/giotypes.h b/gio/giotypes.h
index 1c35083..848336a 100644
--- a/gio/giotypes.h
+++ b/gio/giotypes.h
@@ -418,6 +418,39 @@ typedef gboolean (*GCancellableSourceFunc) (GCancellable *cancellable,
typedef gboolean (*GPollableSourceFunc) (GObject *pollable_stream,
gpointer user_data);
+typedef struct _GDBusInterface GDBusInterface; /* Dummy typedef */
+typedef struct _GDBusInterfaceStub GDBusInterfaceStub;
+typedef struct _GDBusObject GDBusObject; /* Dummy typedef */
+typedef struct _GDBusObjectStub GDBusObjectStub;
+typedef struct _GDBusObjectProxy GDBusObjectProxy;
+typedef struct _GDBusObjectManager GDBusObjectManager; /* Dummy typedef */
+typedef struct _GDBusObjectManagerClient GDBusObjectManagerClient;
+typedef struct _GDBusObjectManagerServer GDBusObjectManagerServer;
+
+/**
+ * GDBusProxyTypeFunc:
+ * @manager: A #GDBusObjectManagerClient.
+ * @object_path: The object path of the remote object.
+ * @interface_name: The interface name of the remote object.
+ * @user_data: User data.
+ *
+ * Function signature for a function used to determine the #GType to
+ * use for an interface proxy.
+ *
+ * This function is called in the
+ * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+ * that @manager was constructed in.
+ *
+ * Returns: A #GType to use for the remote object. The returned type
+ * must be a #GDBusProxy derived type.
+ *
+ * Since: 2.30
+ */
+typedef GType (*GDBusProxyTypeFunc) (GDBusObjectManagerClient *manager,
+ const gchar *object_path,
+ const gchar *interface_name,
+ gpointer user_data);
+
G_END_DECLS
#endif /* __GIO_TYPES_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]