[glib/gdbus] Add g_dbus_connection_signal_subscribe()



commit a0f212d091bd8ba55a340b04004ca9989ef5740f
Author: David Zeuthen <davidz redhat com>
Date:   Thu Apr 30 20:44:46 2009 -0400

    Add g_dbus_connection_signal_subscribe()
    
     o  Change the signature of GDBusProxy::g-dbus-proxy-signal to
        pass a GPtrArray of variants for the arguments
    
     o  This means we need to be able to store a GDBusVariant in
        a GDBusVariant
    
     o  Add a GDestroyNotify for both g_dbus_connection_signal_subscribe()
        and g_dbus_connection_dbus_1_signal_subscribe() to allow the user
        to free user_data when the subscription is removed
    
     o  Make get_value_from_iter() and append_value_to_iter() public (in
        the low-level bits) since we need them in gdbusconnection.c
    
     o  Port GDBusProxy to use g_dbus_connection_signal_subscribe()
    
     o  Ensure that matches on no sender or org.freedesktop.DBus are
        added back on reconnection. Also add test cases for this.
---
 docs/reference/gdbus/gdbus-docs.xml     |    1 +
 docs/reference/gdbus/gdbus-sections.txt |   13 +
 gdbus/Makefile.am                       |    3 +
 gdbus/gbusnameowner.c                   |    6 +-
 gdbus/gbusnamewatcher.c                 |    3 +-
 gdbus/gdbus-lowlevel.h                  |    1 +
 gdbus/gdbus.symbols                     |   13 +
 gdbus/gdbusconnection-lowlevel.h        |    3 +-
 gdbus/gdbusconnection.c                 |  372 ++++++++-
 gdbus/gdbusconnection.h                 |   30 +
 gdbus/gdbusctypemapping-lowlevel.h      |   46 +
 gdbus/gdbusctypemapping.c               | 1329 +++++++++++++++++++++++++++++
 gdbus/gdbusproxy.c                      | 1417 +-----------------------------
 gdbus/gdbusvariant.c                    |   68 ++
 gdbus/gdbusvariant.h                    |    5 +
 gdbus/tests/connection.c                |  127 +++-
 gdbus/tests/proxy.c                     |   30 +-
 gdbus/tests/testserver.py               |   16 +-
 18 files changed, 2026 insertions(+), 1457 deletions(-)

diff --git a/docs/reference/gdbus/gdbus-docs.xml b/docs/reference/gdbus/gdbus-docs.xml
index 860073f..12c3af8 100644
--- a/docs/reference/gdbus/gdbus-docs.xml
+++ b/docs/reference/gdbus/gdbus-docs.xml
@@ -31,6 +31,7 @@
     </chapter>
     <chapter id="cmapping">
         <title>C Object Mapping</title>
+        <xi:include href="xml/gdbusctypemapping.xml"/>
         <xi:include href="xml/gdbusproxy.xml"/>
         <xi:include href="xml/gdbusvariant.xml"/>
         <xi:include href="xml/gdbusstructure.xml"/>
diff --git a/docs/reference/gdbus/gdbus-sections.txt b/docs/reference/gdbus/gdbus-sections.txt
index 0e60e0b..015316f 100644
--- a/docs/reference/gdbus/gdbus-sections.txt
+++ b/docs/reference/gdbus/gdbus-sections.txt
@@ -37,6 +37,9 @@ g_dbus_connection_get_unique_name
 g_dbus_connection_get_exit_on_close
 g_dbus_connection_set_exit_on_close
 g_dbus_connection_get_is_initialized
+GDBusSignalCallback
+g_dbus_connection_signal_subscribe
+g_dbus_connection_signal_unsubscribe
 g_dbus_connection_get_dbus_1_connection
 g_dbus_connection_send_dbus_1_message
 g_dbus_connection_send_dbus_1_message_with_reply
@@ -95,6 +98,12 @@ g_dbus_unintegrate_dbus_1_server
 </SECTION>
 
 <SECTION>
+<FILE>gdbusctypemapping</FILE>
+g_dbus_c_type_mapping_get_value_from_iter
+g_dbus_c_type_mapping_append_value_to_iter
+</SECTION>
+
+<SECTION>
 <FILE>gdbusnameowning</FILE>
 GBusNameAcquiredCallback
 GBusNameLostCallback
@@ -193,6 +202,7 @@ g_dbus_variant_new_for_object_path
 g_dbus_variant_new_for_object_path_array
 g_dbus_variant_new_for_signature
 g_dbus_variant_new_for_signature_array
+g_dbus_variant_new_for_variant
 g_dbus_variant_get_string
 g_dbus_variant_get_byte
 g_dbus_variant_get_boolean
@@ -212,6 +222,7 @@ g_dbus_variant_get_object_path
 g_dbus_variant_get_object_path_array
 g_dbus_variant_get_signature
 g_dbus_variant_get_signature_array
+g_dbus_variant_get_variant
 g_dbus_variant_set_string
 g_dbus_variant_set_byte
 g_dbus_variant_set_boolean
@@ -231,6 +242,7 @@ g_dbus_variant_set_object_path
 g_dbus_variant_set_object_path_array
 g_dbus_variant_set_signature
 g_dbus_variant_set_signature_array
+g_dbus_variant_set_variant
 g_dbus_variant_is_unset
 g_dbus_variant_is_string
 g_dbus_variant_is_byte
@@ -251,6 +263,7 @@ g_dbus_variant_is_object_path
 g_dbus_variant_is_object_path_array
 g_dbus_variant_is_signature
 g_dbus_variant_is_signature_array
+g_dbus_variant_is_variant
 <SUBSECTION Standard>
 G_DBUS_VARIANT
 G_IS_DBUS_VARIANT
diff --git a/gdbus/Makefile.am b/gdbus/Makefile.am
index 343506f..11d69bb 100644
--- a/gdbus/Makefile.am
+++ b/gdbus/Makefile.am
@@ -97,6 +97,8 @@ libgdbus_2_0_la_SOURCES =						\
 	gdbuserror-lowlevel.h						\
 	gdbuserror.h			gdbuserror.c			\
 	gdbusmainloop-lowlevel.h	gdbusmainloop.c			\
+	gdbusctypemapping.h-lowlevel.h					\
+	gdbusctypemapping.h		gdbusctypemapping.c		\
 	gdbusconnection.h-lowlevel.h					\
 	gdbusconnection.h		gdbusconnection.c		\
 	gbusnameowner.h			gbusnameowner.c			\
@@ -167,6 +169,7 @@ gdbuslowlevel_headers = 		\
 	gdbuserror-lowlevel.h		\
 	gdbusconnection-lowlevel.h	\
 	gdbusmainloop-lowlevel.h	\
+	gdbusctypemapping-lowlevel.h	\
 	$(NULL)
 
 gdbuslowlevelincludedir=$(includedir)/dbus-1.0/gdbus-lowlevel/gdbus
diff --git a/gdbus/gbusnameowner.c b/gdbus/gbusnameowner.c
index f2c8e1b..249bf42 100644
--- a/gdbus/gbusnameowner.c
+++ b/gdbus/gbusnameowner.c
@@ -423,7 +423,8 @@ on_connection_opened (GDBusConnection *connection,
                                                DBUS_PATH_DBUS,
                                                owner->priv->name,
                                                on_name_lost_or_acquired,
-                                               owner);
+                                               owner,
+                                               NULL);
   owner->priv->name_acquired_subscription_id =
     g_dbus_connection_dbus_1_signal_subscribe (owner->priv->connection,
                                                DBUS_SERVICE_DBUS,
@@ -432,7 +433,8 @@ on_connection_opened (GDBusConnection *connection,
                                                DBUS_PATH_DBUS,
                                                owner->priv->name,
                                                on_name_lost_or_acquired,
-                                               owner);
+                                               owner,
+                                               NULL);
 
   flags = get_request_name_flags (owner->priv->flags);
   if ((message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
diff --git a/gdbus/gbusnamewatcher.c b/gdbus/gbusnamewatcher.c
index 0d2742f..9b77d58 100644
--- a/gdbus/gbusnamewatcher.c
+++ b/gdbus/gbusnamewatcher.c
@@ -362,7 +362,8 @@ on_connection_opened (GDBusConnection *connection,
                                                DBUS_PATH_DBUS,
                                                watcher->priv->name,
                                                on_name_owner_changed,
-                                               watcher);
+                                               watcher,
+                                               NULL);
 
   if ((message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                                DBUS_PATH_DBUS,
diff --git a/gdbus/gdbus-lowlevel.h b/gdbus/gdbus-lowlevel.h
index be4660b..187648e 100644
--- a/gdbus/gdbus-lowlevel.h
+++ b/gdbus/gdbus-lowlevel.h
@@ -33,6 +33,7 @@
 #include <gdbus/gdbus.h>
 #include <gdbus/gdbuserror-lowlevel.h>
 #include <gdbus/gdbusconnection-lowlevel.h>
+#include <gdbus/gdbusctypemapping-lowlevel.h>
 
 #undef __G_DBUS_G_DBUS_LOWLEVEL_H_INSIDE__
 
diff --git a/gdbus/gdbus.symbols b/gdbus/gdbus.symbols
index 6a32e5c..b72e063 100644
--- a/gdbus/gdbus.symbols
+++ b/gdbus/gdbus.symbols
@@ -25,6 +25,8 @@ g_dbus_connection_get_bus_type
 g_dbus_connection_get_exit_on_close
 g_dbus_connection_set_exit_on_close
 g_dbus_connection_get_is_initialized
+g_dbus_connection_signal_subscribe
+g_dbus_connection_signal_unsubscribe
 #endif
 #endif
 
@@ -41,6 +43,13 @@ g_dbus_connection_dbus_1_signal_unsubscribe
 #endif
 #endif
 
+#if IN_HEADER(__G_DBUS_C_TYPE_MAPPING_LOWLEVEL_H__)
+#if IN_FILE(__G_DBUS_C_TYPE_MAPPING_C__)
+g_dbus_c_type_mapping_get_value_from_iter
+g_dbus_c_type_mapping_append_value_to_iter
+#endif
+#endif
+
 #if IN_HEADER(__G_DBUS_MAINLOOP_LOWLEVEL_H__)
 #if IN_FILE(__G_DBUS_MAINLOOP_C__)
 g_dbus_integrate_dbus_1_connection
@@ -169,6 +178,7 @@ g_dbus_variant_get_signature_array
 g_dbus_variant_get_string
 g_dbus_variant_get_string_array
 g_dbus_variant_get_structure
+g_dbus_variant_get_variant
 g_dbus_variant_get_uint
 g_dbus_variant_get_uint16
 g_dbus_variant_get_uint64
@@ -189,6 +199,7 @@ g_dbus_variant_is_signature_array
 g_dbus_variant_is_string
 g_dbus_variant_is_string_array
 g_dbus_variant_is_structure
+g_dbus_variant_is_variant
 g_dbus_variant_is_uint
 g_dbus_variant_is_uint16
 g_dbus_variant_is_uint64
@@ -210,6 +221,7 @@ g_dbus_variant_new_for_signature_array
 g_dbus_variant_new_for_string
 g_dbus_variant_new_for_string_array
 g_dbus_variant_new_for_structure
+g_dbus_variant_new_for_variant
 g_dbus_variant_new_for_uint
 g_dbus_variant_new_for_uint16
 g_dbus_variant_new_for_uint64
@@ -229,6 +241,7 @@ g_dbus_variant_set_signature_array
 g_dbus_variant_set_string
 g_dbus_variant_set_string_array
 g_dbus_variant_set_structure
+g_dbus_variant_set_variant
 g_dbus_variant_set_uint
 g_dbus_variant_set_uint16
 g_dbus_variant_set_uint64
diff --git a/gdbus/gdbusconnection-lowlevel.h b/gdbus/gdbusconnection-lowlevel.h
index 05a708b..b818788 100644
--- a/gdbus/gdbusconnection-lowlevel.h
+++ b/gdbus/gdbusconnection-lowlevel.h
@@ -67,7 +67,8 @@ guint            g_dbus_connection_dbus_1_signal_subscribe               (GDBusC
                                                                           const gchar        *object_path,
                                                                           const gchar        *arg0,
                                                                           GDBusSignalCallback1 callback,
-                                                                          gpointer            user_data);
+                                                                          gpointer            user_data,
+                                                                          GDestroyNotify      user_data_free_func);
 void             g_dbus_connection_dbus_1_signal_unsubscribe             (GDBusConnection    *connection,
                                                                           guint               subscription_id);
 
diff --git a/gdbus/gdbusconnection.c b/gdbus/gdbusconnection.c
index 4fca538..00f65d3 100644
--- a/gdbus/gdbusconnection.c
+++ b/gdbus/gdbusconnection.c
@@ -29,9 +29,10 @@
 #include "gdbusconnection.h"
 #include "gdbusconnection-lowlevel.h"
 #include "gdbusmainloop-lowlevel.h"
+#include "gdbusctypemapping-lowlevel.h"
 #include "gdbuserror.h"
-#include "gdbusprivate.h"
 #include "gdbusenumtypes.h"
+#include "gdbusprivate.h"
 
 #include "gdbusalias.h"
 
@@ -103,6 +104,8 @@ static void distribute_signals (GDBusConnection *connection,
                                 DBusMessage     *message);
 
 static void purge_all_signal_subscriptions (GDBusConnection *connection);
+static void purge_all_signal_subscriptions_for_unique_names (GDBusConnection *connection);
+static void add_current_signal_subscriptions (GDBusConnection *connection);
 
 G_LOCK_DEFINE_STATIC (connection_lock);
 static GDBusConnection *the_session_bus = NULL;
@@ -584,6 +587,10 @@ attempt_connect (GDBusConnection  *connection,
     {
       g_dbus_connection_set_dbus_1_connection (connection, dbus_1_connection);
       dbus_connection_unref (dbus_1_connection);
+
+      /* add match rules for current subscriptions */
+      add_current_signal_subscriptions (connection);
+
       g_signal_emit (connection, signals[OPENED_SIGNAL], 0);
       g_object_notify (G_OBJECT (connection), "is-open");
       ret = TRUE;
@@ -699,7 +706,7 @@ process_message (GDBusConnection *connection,
 
           //g_object_notify (G_OBJECT (bus), "unique-name");
 
-          purge_all_signal_subscriptions (connection);
+          purge_all_signal_subscriptions_for_unique_names (connection);
 
           g_object_notify (G_OBJECT (connection), "is-open");
           g_signal_emit (connection, signals[CLOSED_SIGNAL], 0);
@@ -711,8 +718,6 @@ process_message (GDBusConnection *connection,
 
   /* distribute to signal subscribers */
   distribute_signals (connection, message);
-
-
 }
 
 static gboolean
@@ -1409,6 +1414,7 @@ typedef struct
 {
   GDBusSignalCallback1 callback;
   gpointer user_data;
+  GDestroyNotify user_data_free_func;
   guint id;
 } SignalSubscriber;
 
@@ -1590,28 +1596,32 @@ is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
  * g_dbus_connection_dbus_1_signal_subscribe:
  * @connection: A #GDBusConnection.
  * @sender: Sender name to match on. Must be either <literal>org.freedesktop.DBus</literal> (for listening to signals from the message bus daemon) or a unique name or %NULL to listen from all senders.
- * @interface_name: D-Bus interface name to match on or %NULL or to match on all interfaces.
+ * @interface_name: D-Bus interface name to match on or %NULL to match on all interfaces.
  * @member: D-Bus signal name to match on or %NULL to match on all signals.
  * @object_path: Object path to match on or %NULL to match on all object paths.
  * @arg0: Contents of first string argument to match on or %NULL to match on all kinds of arguments.
  * @callback: Callback to invoke when there is a signal matching the requested data.
  * @user_data: User data to pass to @callback.
+ * @user_data_free_func: Function to free @user_data when subscription is removed or %NULL.
  *
  * <para><note>
  * This function is marked as unstable API. You must include <literal>gdbus/gdbus-lowlevel.h</literal> to use it.
  * </note></para>
  *
  * Subscribes to signals on @connection and invokes @callback with a #DBusMessage whenever the signal
- * is fired. This function handles setting up match rules on the bus.
+ * is received. This function handles setting up match rules on the bus including adding them back
+ * if the connection is closed and opens again. Note that subscriptions on unique names are never
+ * added back. Specifically, all subscriptions on unique names are removed when the connection is
+ * closed so @user_data_free_func may be invoked at any time.
  *
  * It is considered a programming error to use this function if @connection is not open.
  *
  * Note that if @sender is not <literal>org.freedesktop.DBus</literal> (for listening to signals from the
- * message bus daemon), then it needs to be a unique bus name - you cannot pass a name like
- * <literal>com.example.MyApp</literal>.
+ * message bus daemon), then it needs to be a unique bus name or %NULL (for listening to signals from any
+ * name) - you cannot pass a name like <literal>com.example.MyApp</literal>.
  * Use #GBusNameWatcher to find the unique name for the owner of the name you are interested in. Also note
  * that this function does not remove a subscription if @sender vanishes from the bus. You have to manually
- * call g_dbus_connection_dbus_1_signal_unsubscribe().
+ * call g_dbus_connection_dbus_1_signal_unsubscribe() to remove a subscription.
  *
  * Returns: A subscription identifier that can be used with g_dbus_connection_dbus_1_signal_unsubscribe().
  **/
@@ -1623,7 +1633,8 @@ g_dbus_connection_dbus_1_signal_subscribe (GDBusConnection     *connection,
                                            const gchar         *object_path,
                                            const gchar         *arg0,
                                            GDBusSignalCallback1 callback,
-                                           gpointer             user_data)
+                                           gpointer             user_data,
+                                           GDestroyNotify       user_data_free_func)
 {
   gchar *rule;
   SignalData *signal_data;
@@ -1657,6 +1668,7 @@ g_dbus_connection_dbus_1_signal_subscribe (GDBusConnection     *connection,
 
   subscriber.callback = callback;
   subscriber.user_data = user_data;
+  subscriber.user_data_free_func = user_data_free_func;
   subscriber.id = _global_subscriber_id++; /* TODO: overflow etc. */
 
   /* see if we've already have this rule */
@@ -1713,27 +1725,16 @@ g_dbus_connection_dbus_1_signal_subscribe (GDBusConnection     *connection,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-/**
- * g_dbus_connection_dbus_1_signal_unsubscribe:
- * @connection: A #GDBusConnection.
- * @subscription_id: A subscription id obtained from g_dbus_connection_dbus_1_signal_subscribe().
- *
- * <para><note>
- * This function is marked as unstable API. You must include <literal>gdbus/gdbus-lowlevel.h</literal> to use it.
- * </note></para>
- *
- * Unsubscribes from signals.
- **/
-void
-g_dbus_connection_dbus_1_signal_unsubscribe (GDBusConnection    *connection,
-                                             guint               subscription_id)
+/* must hold lock when calling this */
+static void
+unsubscribe_id_internal (GDBusConnection    *connection,
+                         guint               subscription_id,
+                         GArray             *out_removed_subscribers)
 {
   SignalData *signal_data;
   GPtrArray *signal_data_array;
   guint n;
 
-  G_LOCK (connection_lock);
-
   signal_data = g_hash_table_lookup (connection->priv->map_id_to_signal_data,
                                      GUINT_TO_POINTER (subscription_id));
   if (signal_data == NULL)
@@ -1752,6 +1753,7 @@ g_dbus_connection_dbus_1_signal_unsubscribe (GDBusConnection    *connection,
 
       g_assert (g_hash_table_remove (connection->priv->map_id_to_signal_data,
                                      GUINT_TO_POINTER (subscription_id)));
+      g_array_append_val (out_removed_subscribers, *subscriber);
       g_array_remove_index (signal_data->subscribers, n);
 
       if (signal_data->subscribers->len == 0)
@@ -1766,7 +1768,8 @@ g_dbus_connection_dbus_1_signal_unsubscribe (GDBusConnection    *connection,
         g_assert (g_hash_table_remove (connection->priv->map_sender_to_signal_data_array, signal_data->sender));
 
       /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */
-      if (!is_signal_data_for_name_lost_or_acquired (signal_data))
+      if (!is_signal_data_for_name_lost_or_acquired (signal_data) &&
+          connection->priv->dbus_1_connection != NULL)
         remove_match_rule (connection, signal_data->rule);
 
       signal_data_free (signal_data);
@@ -1777,10 +1780,50 @@ g_dbus_connection_dbus_1_signal_unsubscribe (GDBusConnection    *connection,
   g_assert_not_reached ();
 
  out:
-  G_UNLOCK (connection_lock);
   ;
 }
 
+/**
+ * g_dbus_connection_dbus_1_signal_unsubscribe:
+ * @connection: A #GDBusConnection.
+ * @subscription_id: A subscription id obtained from g_dbus_connection_dbus_1_signal_subscribe().
+ *
+ * <para><note>
+ * This function is marked as unstable API. You must include <literal>gdbus/gdbus-lowlevel.h</literal> to use it.
+ * </note></para>
+ *
+ * Unsubscribes from signals.
+ **/
+void
+g_dbus_connection_dbus_1_signal_unsubscribe (GDBusConnection    *connection,
+                                             guint               subscription_id)
+{
+  GArray *subscribers;
+  guint n;
+
+  subscribers = g_array_new (FALSE, FALSE, sizeof (SignalSubscriber));
+
+  G_LOCK (connection_lock);
+  unsubscribe_id_internal (connection,
+                           subscription_id,
+                           subscribers);
+  G_UNLOCK (connection_lock);
+
+  /* invariant */
+  g_assert (subscribers->len == 0 || subscribers->len == 1);
+
+  /* call GDestroyNotify without lock held */
+  for (n = 0; n < subscribers->len; n++)
+    {
+      SignalSubscriber *subscriber;
+      subscriber = &(g_array_index (subscribers, SignalSubscriber, n));
+      if (subscriber->user_data_free_func != NULL)
+        subscriber->user_data_free_func (subscriber->user_data);
+    }
+
+  g_array_free (subscribers, TRUE);
+}
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
@@ -1884,29 +1927,284 @@ out:
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-/* called when disconnected from the bus and in finalize() */
+/* called from finalize(), removes all subscriptions */
 static void
 purge_all_signal_subscriptions (GDBusConnection *connection)
 {
   GHashTableIter iter;
   gpointer key;
+  GArray *ids;
+  GArray *subscribers;
+  guint n;
+
+  G_LOCK (connection_lock);
+  ids = g_array_new (FALSE, FALSE, sizeof (guint));
+  g_hash_table_iter_init (&iter, connection->priv->map_id_to_signal_data);
+  while (g_hash_table_iter_next (&iter, &key, NULL))
+    {
+      guint subscription_id = GPOINTER_TO_UINT (key);
+      g_array_append_val (ids, subscription_id);
+    }
+
+  subscribers = g_array_new (FALSE, FALSE, sizeof (SignalSubscriber));
+  for (n = 0; n < ids->len; n++)
+    {
+      guint subscription_id = g_array_index (ids, guint, n);
+      unsubscribe_id_internal (connection,
+                               subscription_id,
+                               subscribers);
+    }
+  g_array_free (ids, TRUE);
+
+  G_UNLOCK (connection_lock);
+
+  /* call GDestroyNotify without lock held */
+  for (n = 0; n < subscribers->len; n++)
+    {
+      SignalSubscriber *subscriber;
+      subscriber = &(g_array_index (subscribers, SignalSubscriber, n));
+      if (subscriber->user_data_free_func != NULL)
+        subscriber->user_data_free_func (subscriber->user_data);
+    }
+
+  g_array_free (subscribers, TRUE);
+}
+
+/* called when disconnected, removes all subscriptions for rules using unique names */
+static void
+purge_all_signal_subscriptions_for_unique_names (GDBusConnection *connection)
+{
+  GHashTableIter iter;
+  gpointer key;
   gpointer value;
+  GArray *ids;
+  GArray *subscribers;
+  guint n;
 
-  g_hash_table_iter_init (&iter, connection->priv->map_rule_to_signal_data);
+  G_LOCK (connection_lock);
+  ids = g_array_new (FALSE, FALSE, sizeof (guint));
+  g_hash_table_iter_init (&iter, connection->priv->map_id_to_signal_data);
   while (g_hash_table_iter_next (&iter, &key, &value))
-      signal_data_free (value);
-  g_hash_table_remove_all (connection->priv->map_rule_to_signal_data);
+    {
+      guint subscription_id = GPOINTER_TO_UINT (key);
+      SignalData *signal_data = value;
+      if (signal_data->sender != NULL && signal_data->sender[0] == ':')
+        {
+          g_array_append_val (ids, subscription_id);
+        }
+    }
 
-  g_hash_table_remove_all (connection->priv->map_id_to_signal_data);
+  subscribers = g_array_new (FALSE, FALSE, sizeof (SignalSubscriber));
+  for (n = 0; n < ids->len; n++)
+    {
+      guint subscription_id = g_array_index (ids, guint, n);
+      unsubscribe_id_internal (connection,
+                               subscription_id,
+                               subscribers);
+    }
+  g_array_free (ids, TRUE);
 
-  g_hash_table_iter_init (&iter, connection->priv->map_sender_to_signal_data_array);
-  while (g_hash_table_iter_next (&iter, &key, &value))
+  G_UNLOCK (connection_lock);
+
+  /* call GDestroyNotify without lock held */
+  for (n = 0; n < subscribers->len; n++)
     {
-      g_ptr_array_free (value, TRUE);
+      SignalSubscriber *subscriber;
+      subscriber = &(g_array_index (subscribers, SignalSubscriber, n));
+      if (subscriber->user_data_free_func != NULL)
+        subscriber->user_data_free_func (subscriber->user_data);
+    }
+
+  g_array_free (subscribers, TRUE);
+}
+
+/* called when connection, adds match rules for current subscriptions (guaranteed to not be using unique names) */
+static void
+add_current_signal_subscriptions (GDBusConnection *connection)
+{
+  GHashTableIter iter;
+  gpointer key;
+
+  G_LOCK (connection_lock);
+  g_hash_table_iter_init (&iter, connection->priv->map_rule_to_signal_data);
+  while (g_hash_table_iter_next (&iter, &key, NULL))
+    {
+      const gchar *match_rule = key;
+      add_match_rule (connection, match_rule);
+    }
+  G_UNLOCK (connection_lock);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* TODO: mark this function as (skip) so it won't show up in bindings
+ *       cf. http://bugzilla.gnome.org/show_bug.cgi?id=556628
+ */
+
+typedef struct
+{
+  GDBusSignalCallback callback;
+  gpointer user_data;
+  GDestroyNotify user_data_free_func;
+} CSignalSubscriber;
+
+static void
+c_signal_cb (GDBusConnection *connection,
+             DBusMessage     *message,
+             gpointer         user_data)
+{
+  CSignalSubscriber *subscriber = user_data;
+  GPtrArray *p;
+  DBusMessageIter iter;
+  guint n;
+
+  p = g_ptr_array_new_with_free_func (g_object_unref);
+
+  dbus_message_iter_init (message, &iter);
+
+  n = 0;
+  while (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
+    {
+      GValue value = {0};
+      GError *error;
+      char *arg_signature;
+      GDBusVariant *variant;
+
+      error = NULL;
+      if (!g_dbus_c_type_mapping_get_value_from_iter (&iter,
+                                                      &value,
+                                                      &error))
+        {
+          g_warning ("Error getting argument %d from %s signal: %s",
+                     n,
+                     dbus_message_get_member (message),
+                     error->message);
+          g_error_free (error);
+          goto out;
+        }
+
+      arg_signature = dbus_message_iter_get_signature (&iter);
+      variant = _g_dbus_variant_new_for_gvalue (&value, arg_signature);
+      dbus_free (arg_signature);
+
+      g_value_unset (&value);
+
+      g_ptr_array_add (p, variant);
+
+      dbus_message_iter_next (&iter);
+      n++;
+    }
+
+  subscriber->callback (connection,
+                        dbus_message_get_member (message),
+                        dbus_message_get_signature (message),
+                        p,
+                        subscriber->user_data);
+
+ out:
+  g_ptr_array_free (p, TRUE);
+}
+
+static void
+free_c_subscriber (CSignalSubscriber *subscriber)
+{
+  if (subscriber->user_data_free_func != NULL)
+    subscriber->user_data_free_func (subscriber->user_data);
+  g_free (subscriber);
+}
+
+/**
+ * g_dbus_connection_signal_subscribe:
+ * @connection: A #GDBusConnection.
+ * @sender: Sender name to match on. Must be either <literal>org.freedesktop.DBus</literal> (for listening to signals from the message bus daemon) or a unique name or %NULL to listen from all senders.
+ * @interface_name: D-Bus interface name to match on or %NULL to match on all interfaces.
+ * @member: D-Bus signal name to match on or %NULL to match on all signals.
+ * @object_path: Object path to match on or %NULL to match on all object paths.
+ * @arg0: Contents of first string argument to match on or %NULL to match on all kinds of arguments.
+ * @callback: Callback to invoke when there is a signal matching the requested data.
+ * @user_data: User data to pass to @callback.
+ * @user_data_free_func: Function to free @user_data when subscription is removed or %NULL.
+ *
+ * Subscribes to signals on @connection and invokes @callback with a the contents of the signal whenever
+ * it is received. This function handles setting up match rules on the bus including adding them back
+ * if the connection is closed and opens again. Note that subscriptions on unique names are never
+ * added back. Specifically, all subscriptions on unique names are removed when the connection is
+ * closed so @user_data_free_func may be invoked at any time.
+ *
+ * It is considered a programming error to use this function if @connection is not open.
+ *
+ * Note that if @sender is not <literal>org.freedesktop.DBus</literal> (for listening to signals from the
+ * message bus daemon), then it needs to be a unique bus name or %NULL (for listening to signals from any
+ * name) - you cannot pass a name like <literal>com.example.MyApp</literal>.
+ * Use #GBusNameWatcher to find the unique name for the owner of the name you are interested in. Also note
+ * that this function does not remove a subscription if @sender vanishes from the bus. You have to manually
+ * call g_dbus_connection_signal_unsubscribe() to remove a subscription.
+ *
+ * Returns: A subscription identifier that can be used with g_dbus_connection_signal_unsubscribe().
+ **/
+guint
+g_dbus_connection_signal_subscribe (GDBusConnection     *connection,
+                                    const gchar         *sender,
+                                    const gchar         *interface_name,
+                                    const gchar         *member,
+                                    const gchar         *object_path,
+                                    const gchar         *arg0,
+                                    GDBusSignalCallback  callback,
+                                    gpointer             user_data,
+                                    GDestroyNotify       user_data_free_func)
+{
+  CSignalSubscriber *subscriber;
+  guint subscription_id;
+
+  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
+  g_return_val_if_fail (g_dbus_connection_get_is_open (connection), 0);
+  g_return_val_if_fail (callback != NULL, 0);
+
+  subscriber = g_new0 (CSignalSubscriber, 1);
+  subscriber->callback = callback;
+  subscriber->user_data = user_data;
+  subscriber->user_data_free_func = user_data_free_func;
+
+  subscription_id = g_dbus_connection_dbus_1_signal_subscribe (connection,
+                                                               sender,
+                                                               interface_name,
+                                                               member,
+                                                               object_path,
+                                                               arg0,
+                                                               c_signal_cb,
+                                                               subscriber,
+                                                               (GDestroyNotify) free_c_subscriber);
+
+  if (subscription_id == 0)
+    {
+      g_free (subscriber);
+      goto out;
     }
-  g_hash_table_remove_all (connection->priv->map_sender_to_signal_data_array);
+
+ out:
+  return subscription_id;
+}
+
+/* TODO: mark this function as (skip) so it won't show up in bindings
+ *       cf. http://bugzilla.gnome.org/show_bug.cgi?id=556628
+ */
+
+/**
+ * g_dbus_connection_signal_unsubscribe:
+ * @connection: A #GDBusConnection.
+ * @subscription_id: A subscription id obtained from g_dbus_connection_signal_subscribe().
+ *
+ * Unsubscribes from signals.
+ **/
+void
+g_dbus_connection_signal_unsubscribe (GDBusConnection     *connection,
+                                      guint                subscription_id)
+{
+  /* TODO: free CSignalSubscriber */
+  g_dbus_connection_dbus_1_signal_unsubscribe (connection, subscription_id);
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
 
 #define __G_DBUS_CONNECTION_C__
 #include "gdbusaliasdef.c"
diff --git a/gdbus/gdbusconnection.h b/gdbus/gdbusconnection.h
index 137ad03..fbca69a 100644
--- a/gdbus/gdbusconnection.h
+++ b/gdbus/gdbusconnection.h
@@ -98,6 +98,36 @@ gboolean         g_dbus_connection_get_exit_on_close          (GDBusConnection
 void             g_dbus_connection_set_exit_on_close          (GDBusConnection    *connection,
                                                                gboolean            exit_on_close);
 
+/* The following is only for the C object mapping and should not be bound to other languages */
+
+/**
+ * GDBusSignalCallback:
+ * @connection: A #GDBusConnection.
+ * @name: The name of the signal.
+ * @signature: The signature of the signal.
+ * @args: A #GPtrArray containing one #GDBusVariant for each argument of the signal.
+ * @user_data: User data passed when subscribing to the signal.
+ *
+ * Signature for callback function used in g_dbus_connection_signal_subscribe().
+ */
+typedef void (*GDBusSignalCallback) (GDBusConnection  *connection,
+                                     const gchar      *name,
+                                     const gchar      *signature,
+                                     GPtrArray        *args,
+                                     gpointer          user_data);
+
+guint            g_dbus_connection_signal_subscribe           (GDBusConnection     *connection,
+                                                               const gchar         *sender,
+                                                               const gchar         *interface_name,
+                                                               const gchar         *member,
+                                                               const gchar         *object_path,
+                                                               const gchar         *arg0,
+                                                               GDBusSignalCallback  callback,
+                                                               gpointer             user_data,
+                                                               GDestroyNotify      user_data_free_func);
+void             g_dbus_connection_signal_unsubscribe         (GDBusConnection     *connection,
+                                                               guint                subscription_id);
+
 G_END_DECLS
 
 #endif /* __G_DBUS_CONNECTION_H__ */
diff --git a/gdbus/gdbusctypemapping-lowlevel.h b/gdbus/gdbusctypemapping-lowlevel.h
new file mode 100644
index 0000000..e52a22c
--- /dev/null
+++ b/gdbus/gdbusctypemapping-lowlevel.h
@@ -0,0 +1,46 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 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>
+ */
+
+#if !defined (__G_DBUS_G_DBUS_LOWLEVEL_H_INSIDE__) && !defined (G_DBUS_COMPILATION)
+#error "Only <gdbus/gdbus-lowlevel.h> can be included directly."
+#endif
+
+#ifndef __G_DBUS_C_TYPE_MAPPING_LOWLEVEL_H__
+#define __G_DBUS_C_TYPE_MAPPING_LOWLEVEL_H__
+
+#include <gdbus/gdbus-lowlevel.h>
+
+G_BEGIN_DECLS
+
+gboolean g_dbus_c_type_mapping_get_value_from_iter  (DBusMessageIter   *iter,
+                                                     GValue            *out_value,
+                                                     GError           **error);
+
+gboolean g_dbus_c_type_mapping_append_value_to_iter (DBusMessageIter   *iter,
+                                                     const gchar       *signature,
+                                                     const GValue      *value,
+                                                     GError           **error);
+
+
+G_END_DECLS
+
+#endif /* __G_DBUS_C_TYPE_MAPPING_LOWLEVEL_H__ */
diff --git a/gdbus/gdbusctypemapping.c b/gdbus/gdbusctypemapping.c
new file mode 100644
index 0000000..bdb11bd
--- /dev/null
+++ b/gdbus/gdbusctypemapping.c
@@ -0,0 +1,1329 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 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 <stdlib.h>
+#include <glib/gi18n.h>
+#include <gobject/gvaluecollector.h>
+
+#include "gdbuserror.h"
+#include "gdbusctypemapping-lowlevel.h"
+#include "gdbusprivate.h"
+
+#include "gdbusalias.h"
+
+/**
+ * SECTION:gdbusctypemapping
+ * @title: Mapping GType to D-Bus
+ * @short_description: Encode and decode D-Bus messages
+ * @include: gdbus/gdbus-lowlevel.h
+ * @stability: Unstable
+ *
+ * Functions for mapping D-Bus messages to the GLib type system.
+ */
+
+static guint
+get_element_size (gchar dbus_type_code)
+{
+  guint ret;
+
+  switch (dbus_type_code)
+    {
+    case DBUS_TYPE_BYTE:
+      ret = 1;
+      break;
+    case DBUS_TYPE_BOOLEAN:
+      ret = sizeof (gboolean);
+      break;
+    case DBUS_TYPE_INT16:
+    case DBUS_TYPE_UINT16:
+      ret = sizeof (gint16);
+      break;
+    case DBUS_TYPE_INT32:
+    case DBUS_TYPE_UINT32:
+      ret = sizeof (gint);
+      break;
+    case DBUS_TYPE_INT64:
+    case DBUS_TYPE_UINT64:
+      ret = sizeof (gint64);
+      break;
+    case DBUS_TYPE_DOUBLE:
+      ret = sizeof (gdouble);
+      break;
+    default:
+      g_assert_not_reached ();
+    }
+
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_dbus_c_type_mapping_get_value_from_iter:
+ * @iter: A #DBusMessageIter
+ * @out_value: Return location for result (must be initialized to zeroes).
+ * @error: Return location for error or %NULL.
+ *
+ * Constructs a #GValue for the single complete type pointed to by @iter. Note that @iter is not
+ * advanced to the next position.
+ *
+ * Returns: %TRUE on success, %FALSE if @error is set.
+ **/
+gboolean
+g_dbus_c_type_mapping_get_value_from_iter (DBusMessageIter   *iter,
+                                           GValue            *out_value,
+                                           GError           **error)
+{
+  int arg_type;
+  int array_arg_type;
+  dbus_bool_t bool_val;
+  const char *str_val;
+  guchar uint8_val;
+  dbus_int16_t int16_val;
+  dbus_uint16_t uint16_val;
+  dbus_int32_t int32_val;
+  dbus_uint32_t uint32_val;
+  dbus_int64_t int64_val;
+  dbus_uint64_t uint64_val;
+  double double_val;
+  gboolean ret;
+
+  /* TODO: - fill in @error instead of using g_assert_not_reached() */
+
+  g_return_val_if_fail (iter != NULL, FALSE);
+  g_return_val_if_fail (out_value != NULL, FALSE);
+
+  ret = FALSE;
+
+  arg_type = dbus_message_iter_get_arg_type (iter);
+
+  switch (arg_type)
+    {
+    case DBUS_TYPE_STRING:
+      g_value_init (out_value, G_TYPE_STRING);
+      dbus_message_iter_get_basic (iter, &str_val);
+      g_value_set_string (out_value, str_val);
+      break;
+
+    case DBUS_TYPE_OBJECT_PATH:
+      g_value_init (out_value, G_TYPE_STRING); // TODO:o
+      dbus_message_iter_get_basic (iter, &str_val);
+      g_value_set_string (out_value, str_val);
+      break;
+
+    case DBUS_TYPE_SIGNATURE:
+      g_value_init (out_value, G_TYPE_STRING); // TODO:g
+      dbus_message_iter_get_basic (iter, &str_val);
+      g_value_set_string (out_value, str_val);
+      break;
+
+    case DBUS_TYPE_BOOLEAN:
+      g_value_init (out_value, G_TYPE_BOOLEAN);
+      dbus_message_iter_get_basic (iter, &bool_val);
+      g_value_set_boolean (out_value, bool_val);
+      break;
+
+    case DBUS_TYPE_BYTE:
+      g_value_init (out_value, G_TYPE_UCHAR);
+      dbus_message_iter_get_basic (iter, &uint8_val);
+      g_value_set_uchar (out_value, uint8_val);
+      break;
+
+    case DBUS_TYPE_INT16:
+      g_value_init (out_value, G_TYPE_INT); // TODO:16
+      dbus_message_iter_get_basic (iter, &int16_val);
+      g_value_set_int (out_value, int16_val);
+      break;
+
+    case DBUS_TYPE_UINT16:
+      g_value_init (out_value, G_TYPE_UINT); // TODO:16
+      dbus_message_iter_get_basic (iter, &uint16_val);
+      g_value_set_uint (out_value, uint16_val);
+      break;
+
+    case DBUS_TYPE_INT32:
+      g_value_init (out_value, G_TYPE_INT);
+      dbus_message_iter_get_basic (iter, &int32_val);
+      g_value_set_int (out_value, int32_val);
+      break;
+
+    case DBUS_TYPE_UINT32:
+      g_value_init (out_value, G_TYPE_UINT);
+      dbus_message_iter_get_basic (iter, &uint32_val);
+      g_value_set_uint (out_value, uint32_val);
+      break;
+
+    case DBUS_TYPE_INT64:
+      g_value_init (out_value, G_TYPE_INT64);
+      dbus_message_iter_get_basic (iter, &int64_val);
+      g_value_set_int64 (out_value, int64_val);
+      break;
+
+    case DBUS_TYPE_UINT64:
+      g_value_init (out_value, G_TYPE_UINT64);
+      dbus_message_iter_get_basic (iter, &uint64_val);
+      g_value_set_uint64 (out_value, uint64_val);
+      break;
+
+    case DBUS_TYPE_DOUBLE:
+      g_value_init (out_value, G_TYPE_DOUBLE);
+      dbus_message_iter_get_basic (iter, &double_val);
+      g_value_set_double (out_value, double_val);
+      break;
+
+    case DBUS_TYPE_STRUCT:
+      {
+        DBusMessageIter struct_iter;
+        char *struct_signature;
+        GDBusStructure *structure;
+        GArray *a;
+
+        struct_signature = dbus_message_iter_get_signature (iter);
+
+        a = g_array_new (FALSE,
+                         TRUE,
+                         sizeof (GValue));
+
+        dbus_message_iter_recurse (iter, &struct_iter);
+
+        /* now collect all the elements in the structure as GValue objects */
+        while (dbus_message_iter_get_arg_type (&struct_iter) != DBUS_TYPE_INVALID)
+          {
+            GValue *value;
+
+            g_array_set_size (a, a->len + 1);
+            value = &g_array_index (a, GValue, a->len - 1);
+
+            /* doing the recursive dance! */
+            if (!g_dbus_c_type_mapping_get_value_from_iter (&struct_iter, value, error))
+              goto out;
+
+            dbus_message_iter_next (&struct_iter);
+          }
+
+        /* takes ownership of elems */
+        structure = _g_dbus_structure_new_for_values (struct_signature,
+                                                      a->len,
+                                                      (GValue *) a->data);
+        g_assert (structure != NULL);
+
+        g_array_free (a, FALSE);
+
+        g_value_init (out_value, G_TYPE_DBUS_STRUCTURE);
+        g_value_take_object (out_value, structure);
+
+        dbus_free (struct_signature);
+      }
+      break;
+
+    case DBUS_TYPE_ARRAY:
+      array_arg_type = dbus_message_iter_get_element_type (iter);
+      if (array_arg_type == DBUS_TYPE_STRING ||
+          array_arg_type == DBUS_TYPE_OBJECT_PATH ||
+          array_arg_type == DBUS_TYPE_SIGNATURE)
+        {
+          GPtrArray *p;
+          DBusMessageIter array_iter;
+          GType boxed_type;
+
+          if (array_arg_type == DBUS_TYPE_STRING)
+            boxed_type = G_TYPE_STRV;
+          else if (array_arg_type == DBUS_TYPE_OBJECT_PATH)
+            boxed_type = G_TYPE_STRV; // TODO:o EGG_DBUS_TYPE_OBJECT_PATH_ARRAY;
+          else if (array_arg_type == DBUS_TYPE_SIGNATURE)
+            boxed_type = G_TYPE_STRV; // TODO:g EGG_DBUS_TYPE_SIGNATURE_ARRAY;
+          else
+            g_assert_not_reached ();
+
+          dbus_message_iter_recurse (iter, &array_iter);
+          p = g_ptr_array_new ();
+          while (dbus_message_iter_get_arg_type (&array_iter) != DBUS_TYPE_INVALID)
+            {
+              dbus_message_iter_get_basic (&array_iter, &str_val);
+              g_ptr_array_add (p, (void *) g_strdup (str_val));
+              dbus_message_iter_next (&array_iter);
+            }
+          g_ptr_array_add (p, NULL);
+          g_value_init (out_value, boxed_type);
+          g_value_take_boxed (out_value, p->pdata);
+          g_ptr_array_free (p, FALSE);
+        }
+      else if (array_arg_type == DBUS_TYPE_BYTE ||
+               array_arg_type == DBUS_TYPE_INT16 ||
+               array_arg_type == DBUS_TYPE_UINT16 ||
+               array_arg_type == DBUS_TYPE_INT32 ||
+               array_arg_type == DBUS_TYPE_UINT32 ||
+               array_arg_type == DBUS_TYPE_INT64 ||
+               array_arg_type == DBUS_TYPE_UINT64 ||
+               array_arg_type == DBUS_TYPE_BOOLEAN ||
+               array_arg_type == DBUS_TYPE_DOUBLE)
+        {
+          GArray *a;
+          DBusMessageIter array_iter;
+          gconstpointer data;
+          gint num_items;
+
+          dbus_message_iter_recurse (iter, &array_iter);
+          dbus_message_iter_get_fixed_array (&array_iter,
+                                             &data,
+                                             (int*) &num_items);
+          a = g_array_sized_new (FALSE, FALSE, get_element_size (array_arg_type), num_items);
+          g_array_append_vals (a, data, num_items);
+          g_value_init (out_value, G_TYPE_ARRAY);
+          g_value_take_boxed (out_value, a);
+        }
+      else if (array_arg_type == DBUS_TYPE_STRUCT)
+        {
+          DBusMessageIter array_iter;
+          char *struct_signature;
+          GPtrArray *p;
+
+          p = g_ptr_array_new_with_free_func (g_object_unref);
+
+          dbus_message_iter_recurse (iter, &array_iter);
+
+          struct_signature = dbus_message_iter_get_signature (&array_iter);
+
+          /* now collect all the elements in the structure.
+           */
+          while (dbus_message_iter_get_arg_type (&array_iter) != DBUS_TYPE_INVALID)
+            {
+              GValue elem_value = {0};
+
+              /* recurse */
+              if (!g_dbus_c_type_mapping_get_value_from_iter (&array_iter, &elem_value, error))
+                {
+                  dbus_free (struct_signature);
+                  g_ptr_array_unref (p);
+                  goto out;
+                }
+
+              g_ptr_array_add (p, g_value_get_object (&elem_value));
+
+              dbus_message_iter_next (&array_iter);
+            }
+
+          g_value_init (out_value, G_TYPE_PTR_ARRAY);
+          g_value_take_boxed (out_value, p);
+
+          dbus_free (struct_signature);
+        }
+      else if (array_arg_type == DBUS_TYPE_DICT_ENTRY)
+        {
+          DBusMessageIter array_iter;
+          GHashTable *hash;
+          char key_sig[2];
+          char *val_sig;
+          char *array_sig;
+          GHashFunc hash_func;
+          GEqualFunc equal_func;
+          GDestroyNotify key_free_func;
+          GDestroyNotify val_free_func;
+
+          dbus_message_iter_recurse (iter, &array_iter);
+
+          array_sig = dbus_message_iter_get_signature (&array_iter);
+
+          /* keys are guaranteed by the D-Bus spec to be primitive types */
+          key_sig[0] = array_sig[1];
+          key_sig[1] = '\0';
+          val_sig = g_strdup (array_sig + 2);
+          val_sig[strlen (val_sig) - 1] = '\0';
+
+          /* set up the hash table */
+
+          switch (key_sig[0])
+            {
+            case DBUS_TYPE_BOOLEAN:
+            case DBUS_TYPE_BYTE:
+            case DBUS_TYPE_INT16:
+            case DBUS_TYPE_UINT16:
+            case DBUS_TYPE_INT32:
+            case DBUS_TYPE_UINT32:
+              key_free_func = NULL;
+              hash_func = g_direct_hash;
+              equal_func = g_direct_equal;
+              break;
+
+            case DBUS_TYPE_INT64:
+            case DBUS_TYPE_UINT64:
+              hash_func = g_int64_hash;
+              equal_func = g_int64_equal;
+              key_free_func = g_free;
+              break;
+
+            case DBUS_TYPE_DOUBLE:
+              hash_func = g_double_hash;
+              equal_func = g_double_equal;
+              key_free_func = g_free;
+              break;
+
+            case DBUS_TYPE_STRING:
+            case DBUS_TYPE_OBJECT_PATH:
+            case DBUS_TYPE_SIGNATURE:
+              hash_func = g_str_hash;
+              equal_func = g_str_equal;
+              key_free_func = g_free;
+              break;
+
+            default:
+              g_assert_not_reached ();
+              break;
+            }
+
+          switch (val_sig[0])
+            {
+            case DBUS_TYPE_BOOLEAN:
+            case DBUS_TYPE_BYTE:
+            case DBUS_TYPE_INT16:
+            case DBUS_TYPE_UINT16:
+            case DBUS_TYPE_INT32:
+            case DBUS_TYPE_UINT32:
+              val_free_func = NULL;
+              break;
+
+            case DBUS_TYPE_INT64:
+            case DBUS_TYPE_UINT64:
+            case DBUS_TYPE_DOUBLE:
+            case DBUS_TYPE_STRING:
+            case DBUS_TYPE_OBJECT_PATH:
+            case DBUS_TYPE_SIGNATURE:
+              val_free_func = g_free;
+              break;
+
+            case DBUS_TYPE_ARRAY:
+              switch (val_sig[1])
+                {
+                case DBUS_TYPE_STRING:
+                case DBUS_TYPE_OBJECT_PATH:
+                case DBUS_TYPE_SIGNATURE:
+                  val_free_func = (GDestroyNotify) g_strfreev;
+                  break;
+
+                case DBUS_TYPE_BOOLEAN:
+                case DBUS_TYPE_BYTE:
+                case DBUS_TYPE_INT16:
+                case DBUS_TYPE_UINT16:
+                case DBUS_TYPE_INT32:
+                case DBUS_TYPE_UINT32:
+                case DBUS_TYPE_INT64:
+                case DBUS_TYPE_UINT64:
+                case DBUS_TYPE_DOUBLE:
+                  val_free_func = (GDestroyNotify) g_array_unref;
+                  break;
+
+                case DBUS_STRUCT_BEGIN_CHAR:
+                case DBUS_DICT_ENTRY_BEGIN_CHAR:
+                  val_free_func = (GDestroyNotify) g_ptr_array_unref;
+                  break;
+
+                case DBUS_TYPE_VARIANT:
+                  val_free_func = (GDestroyNotify) g_ptr_array_unref;
+                  break;
+
+                case DBUS_TYPE_ARRAY:
+                  val_free_func = (GDestroyNotify) g_ptr_array_unref;
+                  break;
+
+                default:
+                  g_assert_not_reached ();
+                  break;
+                }
+              break;
+
+            case DBUS_STRUCT_BEGIN_CHAR:
+              val_free_func = g_object_unref;
+              break;
+
+            case DBUS_TYPE_VARIANT:
+              val_free_func = g_object_unref;
+              break;
+
+            default:
+              g_assert_not_reached ();
+              break;
+            }
+
+          hash = g_hash_table_new_full (hash_func,
+                                        equal_func,
+                                        key_free_func,
+                                        val_free_func);
+
+          while (dbus_message_iter_get_arg_type (&array_iter) != DBUS_TYPE_INVALID)
+            {
+              DBusMessageIter hash_iter;
+              gpointer key, value;
+              const char *str_val;
+
+              dbus_message_iter_recurse (&array_iter, &hash_iter);
+
+              switch (key_sig[0])
+                {
+                case DBUS_TYPE_BOOLEAN:
+                  dbus_message_iter_get_basic (&hash_iter, &bool_val);
+                  key = GINT_TO_POINTER (bool_val);
+                  break;
+
+                case DBUS_TYPE_BYTE:
+                  dbus_message_iter_get_basic (&hash_iter, &uint8_val);
+                  key = GINT_TO_POINTER (uint8_val);
+                  break;
+
+                case DBUS_TYPE_INT16:
+                  dbus_message_iter_get_basic (&hash_iter, &int16_val);
+                  key = GINT_TO_POINTER (int16_val);
+                  break;
+
+                case DBUS_TYPE_UINT16:
+                  dbus_message_iter_get_basic (&hash_iter, &uint16_val);
+                  key = GINT_TO_POINTER (uint16_val);
+                  break;
+
+                case DBUS_TYPE_INT32:
+                  dbus_message_iter_get_basic (&hash_iter, &int32_val);
+                  key = GINT_TO_POINTER (int32_val);
+                  break;
+
+                case DBUS_TYPE_UINT32:
+                  dbus_message_iter_get_basic (&hash_iter, &uint32_val);
+                  key = GINT_TO_POINTER (uint32_val);
+                  break;
+
+                case DBUS_TYPE_INT64:
+                  dbus_message_iter_get_basic (&hash_iter, &int64_val);
+                  key = g_memdup (&int64_val, sizeof (gint64));
+                  break;
+
+                case DBUS_TYPE_UINT64:
+                  dbus_message_iter_get_basic (&hash_iter, &uint64_val);
+                  key = g_memdup (&uint64_val, sizeof (guint64));
+                  break;
+
+                case DBUS_TYPE_DOUBLE:
+                  dbus_message_iter_get_basic (&hash_iter, &double_val);
+                  key = g_memdup (&double_val, sizeof (gdouble));
+                  break;
+
+                case DBUS_TYPE_STRING:
+                  dbus_message_iter_get_basic (&hash_iter, &str_val);
+                  key = g_strdup (str_val);
+                  break;
+
+                case DBUS_TYPE_OBJECT_PATH:
+                  dbus_message_iter_get_basic (&hash_iter, &str_val);
+                  key = g_strdup (str_val);
+                  break;
+
+                case DBUS_TYPE_SIGNATURE:
+                  dbus_message_iter_get_basic (&hash_iter, &str_val);
+                  key = g_strdup (str_val);
+                  break;
+
+                default:
+                  g_assert_not_reached ();
+                  break;
+                }
+
+              dbus_message_iter_next (&hash_iter);
+
+              switch (val_sig[0])
+                {
+                case DBUS_TYPE_BOOLEAN:
+                  dbus_message_iter_get_basic (&hash_iter, &bool_val);
+                  value = GINT_TO_POINTER (bool_val);
+                  break;
+
+                case DBUS_TYPE_BYTE:
+                  dbus_message_iter_get_basic (&hash_iter, &uint8_val);
+                  value = GINT_TO_POINTER (uint8_val);
+                  break;
+
+                case DBUS_TYPE_INT16:
+                  dbus_message_iter_get_basic (&hash_iter, &int16_val);
+                  value = GINT_TO_POINTER (int16_val);
+                  break;
+
+                case DBUS_TYPE_UINT16:
+                  dbus_message_iter_get_basic (&hash_iter, &uint16_val);
+                  value = GINT_TO_POINTER (uint16_val);
+                  break;
+
+                case DBUS_TYPE_INT32:
+                  dbus_message_iter_get_basic (&hash_iter, &int32_val);
+                  value = GINT_TO_POINTER (int32_val);
+                  break;
+
+                case DBUS_TYPE_INT64:
+                  dbus_message_iter_get_basic (&hash_iter, &int64_val);
+                  value = g_memdup (&int64_val, sizeof (gint64));
+                  break;
+
+                case DBUS_TYPE_UINT64:
+                  dbus_message_iter_get_basic (&hash_iter, &uint64_val);
+                  value = g_memdup (&uint64_val, sizeof (guint64));
+                  break;
+
+                case DBUS_TYPE_DOUBLE:
+                  dbus_message_iter_get_basic (&hash_iter, &double_val);
+                  value = g_memdup (&double_val, sizeof (gdouble));
+                  break;
+
+                case DBUS_TYPE_UINT32:
+                  dbus_message_iter_get_basic (&hash_iter, &uint32_val);
+                  value = GINT_TO_POINTER (uint32_val);
+                  break;
+
+                case DBUS_TYPE_STRING:
+                  dbus_message_iter_get_basic (&hash_iter, &str_val);
+                  value = g_strdup (str_val);
+                  break;
+
+                case DBUS_TYPE_OBJECT_PATH:
+                  dbus_message_iter_get_basic (&hash_iter, &str_val);
+                  value = g_strdup (str_val);
+                  break;
+
+                case DBUS_TYPE_SIGNATURE:
+                  dbus_message_iter_get_basic (&hash_iter, &str_val);
+                  value = g_strdup (str_val);
+                  break;
+
+                case DBUS_TYPE_ARRAY:
+                  {
+                    GValue array_val = {0};
+                    /* recurse */
+                    if (!g_dbus_c_type_mapping_get_value_from_iter (&hash_iter, &array_val, error))
+                      goto out;
+                    switch (val_sig[1])
+                      {
+                      case DBUS_TYPE_BOOLEAN:
+                      case DBUS_TYPE_BYTE:
+                      case DBUS_TYPE_INT16:
+                      case DBUS_TYPE_UINT16:
+                      case DBUS_TYPE_INT32:
+                      case DBUS_TYPE_UINT32:
+                      case DBUS_TYPE_INT64:
+                      case DBUS_TYPE_UINT64:
+                      case DBUS_TYPE_DOUBLE:
+                      case DBUS_STRUCT_BEGIN_CHAR:
+                      case DBUS_DICT_ENTRY_BEGIN_CHAR:
+                      case DBUS_TYPE_STRING:
+                      case DBUS_TYPE_OBJECT_PATH:
+                      case DBUS_TYPE_SIGNATURE:
+                      case DBUS_TYPE_VARIANT:
+                      case DBUS_TYPE_ARRAY:
+                        value = g_value_get_boxed (&array_val);
+                        break;
+
+                      default:
+                        g_assert_not_reached ();
+                        break;
+                      }
+                  }
+                  break;
+
+                case DBUS_STRUCT_BEGIN_CHAR:
+                  {
+                    GValue object_val = {0};
+                    /* recurse */
+                    if (!g_dbus_c_type_mapping_get_value_from_iter (&hash_iter, &object_val, error))
+                      goto out;
+                    value = g_value_get_object (&object_val);
+                  }
+                  break;
+
+                case DBUS_TYPE_VARIANT:
+                  {
+                    GValue object_val = {0};
+                    /* recurse */
+                    if (!g_dbus_c_type_mapping_get_value_from_iter (&hash_iter, &object_val, error))
+                      goto out;
+                    value = g_value_get_object (&object_val);
+                  }
+                  break;
+
+                default:
+                  g_assert_not_reached ();
+                  break;
+                }
+
+              g_hash_table_insert (hash, key, value);
+              dbus_message_iter_next (&array_iter);
+            }
+
+          g_value_init (out_value, G_TYPE_HASH_TABLE);
+          g_value_take_boxed (out_value, hash);
+
+          dbus_free (array_sig);
+          g_free (val_sig);
+
+        }
+      else if (array_arg_type == DBUS_TYPE_ARRAY)
+        {
+          GPtrArray *p;
+          DBusMessageIter array_iter;
+          GDestroyNotify elem_free_func;
+
+          /* handling array of arrays, e.g.
+           *
+           * - aas:    GPtrArray of GStrv (gchar **)
+           * - aao:    GPtrArray of GStrv (gchar **) TODO:o
+           * - aao:    GPtrArray of GStrv (gchar **) TODO:g
+           * - aa{ss}: GPtrArray of GHashTable
+           * - aai:    GPtrArray of GArray
+           * - aa(ii): GPtrArray of GPtrArray containg GObject-derived type
+           * - aaas:   GPtrArray of GPtrArray of GStrv (gchar **)
+           *
+           */
+
+          dbus_message_iter_recurse (iter, &array_iter);
+
+          elem_free_func = NULL;
+
+          p = g_ptr_array_new ();
+          while (dbus_message_iter_get_arg_type (&array_iter) != DBUS_TYPE_INVALID)
+            {
+              GValue elem_val = {0};
+
+              /* recurse */
+              if (!g_dbus_c_type_mapping_get_value_from_iter (&array_iter, &elem_val, error))
+                goto out;
+
+              if (G_VALUE_TYPE (&elem_val) == G_TYPE_STRV)
+                {
+                  g_ptr_array_add (p, g_value_get_boxed (&elem_val));
+                  elem_free_func = (GDestroyNotify) g_strfreev;
+                }
+              else if (G_VALUE_TYPE (&elem_val) == G_TYPE_ARRAY)
+                {
+                  g_ptr_array_add (p, g_value_get_boxed (&elem_val));
+                  elem_free_func = (GDestroyNotify) g_array_unref;
+                }
+              else if (G_VALUE_TYPE (&elem_val) == G_TYPE_PTR_ARRAY)
+                {
+                  g_ptr_array_add (p, g_value_get_boxed (&elem_val));
+                  elem_free_func = (GDestroyNotify) g_ptr_array_unref;
+                }
+              else if (G_VALUE_TYPE (&elem_val) == G_TYPE_HASH_TABLE)
+                {
+                  g_ptr_array_add (p, g_value_get_boxed (&elem_val));
+                  elem_free_func = (GDestroyNotify) g_hash_table_unref;
+                }
+              else
+                {
+                  g_assert_not_reached ();
+                }
+
+              dbus_message_iter_next (&array_iter);
+            } /* for all elements in array */
+          g_ptr_array_set_free_func (p, elem_free_func);
+          g_value_init (out_value, G_TYPE_PTR_ARRAY);
+          g_value_take_boxed (out_value, p);
+        }
+      else if (array_arg_type == DBUS_TYPE_VARIANT)
+        {
+          GPtrArray *p;
+          DBusMessageIter array_iter;
+          char *elem_signature;
+
+          /* array of variants */
+
+          dbus_message_iter_recurse (iter, &array_iter);
+
+          elem_signature = dbus_message_iter_get_signature (&array_iter);
+
+          p = g_ptr_array_new_with_free_func (g_object_unref);
+          while (dbus_message_iter_get_arg_type (&array_iter) != DBUS_TYPE_INVALID)
+            {
+              GValue elem_val = {0};
+
+              /* recurse */
+              if (!g_dbus_c_type_mapping_get_value_from_iter (&array_iter, &elem_val, error))
+                goto out;
+
+              g_ptr_array_add (p, g_value_get_object (&elem_val));
+
+              dbus_message_iter_next (&array_iter);
+            } /* for all elements in array */
+
+          g_value_init (out_value, G_TYPE_PTR_ARRAY);
+          g_value_take_boxed (out_value, p);
+
+          dbus_free (elem_signature);
+        }
+      else
+        {
+          char *signature;
+          signature = dbus_message_iter_get_signature (iter);
+          g_set_error (error,
+                       G_DBUS_ERROR,
+                       G_DBUS_ERROR_FAILED,
+                       "Cannot decode message with array of signature %s", signature);
+          g_free (signature);
+          goto out;
+        }
+      break;
+
+    case DBUS_TYPE_VARIANT:
+      {
+        GValue variant_val = {0};
+        GDBusVariant *variant;
+        DBusMessageIter variant_iter;
+        gchar *variant_signature;
+
+        dbus_message_iter_recurse (iter, &variant_iter);
+
+        variant_signature = dbus_message_iter_get_signature (&variant_iter);
+
+        /* recurse */
+        if (!g_dbus_c_type_mapping_get_value_from_iter (&variant_iter, &variant_val, error))
+          goto out;
+
+        variant = _g_dbus_variant_new_for_gvalue (&variant_val, variant_signature);
+
+        g_value_init (out_value, G_TYPE_DBUS_VARIANT);
+        g_value_take_object (out_value, variant);
+
+        dbus_free (variant_signature);
+      }
+      break;
+
+    default:
+      {
+        char *signature;
+        signature = dbus_message_iter_get_signature (iter);
+        g_set_error (error,
+                     G_DBUS_ERROR,
+                     G_DBUS_ERROR_FAILED,
+                     "Cannot decode message with signature %s", signature);
+        dbus_free (signature);
+        goto out;
+      }
+      break;
+    }
+
+  ret = TRUE;
+
+ out:
+
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_dbus_c_type_mapping_append_value_to_iter:
+ * @iter: A #DBusMessageIter.
+ * @signature: A D-Bus signature corresponding to @value.
+ * @value: A #GValue with the value to set
+ * @error: Return location for error or %NULL.
+ *
+ * Appens @value to @iter.
+ *
+ * Returns: %TRUE on success, %FALSE if @error is set.
+ **/
+gboolean
+g_dbus_c_type_mapping_append_value_to_iter (DBusMessageIter   *iter,
+                                            const gchar       *signature,
+                                            const GValue      *value,
+                                            GError           **error)
+{
+  gboolean ret;
+
+  /* TODO: - fill in @error instead of using g_assert_not_reached()
+   *       - validate object paths and signatures (to shield app developers
+   *         from getting disconnected from the bus)
+   *       - perhaps access GValue directly (trading off safety for performance)
+   */
+
+  //g_debug ("_append_value_to_iter: signature=%s -> value=%s", signature, g_strdup_value_contents (value));
+
+  ret = FALSE;
+
+  /* TODO: we could probably speed this up by accessing the GValue directly */
+  switch (signature[0])
+    {
+    case DBUS_TYPE_STRING:
+      {
+        const char *val = g_value_get_string (value);
+        dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &val);
+      }
+      break;
+
+    case DBUS_TYPE_OBJECT_PATH:
+      {
+        const char *val = g_value_get_string (value); // TODO:o
+        dbus_message_iter_append_basic (iter, DBUS_TYPE_OBJECT_PATH, &val);
+      }
+      break;
+
+    case DBUS_TYPE_SIGNATURE:
+      {
+        const char *val = g_value_get_string (value); // TODO:g
+        dbus_message_iter_append_basic (iter, DBUS_TYPE_SIGNATURE, &val);
+      }
+      break;
+
+    case DBUS_TYPE_BYTE:
+      {
+        guchar val = g_value_get_uchar (value);
+        dbus_message_iter_append_basic (iter, DBUS_TYPE_BYTE, &val);
+      }
+      break;
+
+    case DBUS_TYPE_BOOLEAN:
+      {
+        dbus_bool_t val = g_value_get_boolean (value);
+        dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &val);
+      }
+      break;
+
+    case DBUS_TYPE_INT16:
+      {
+        dbus_int16_t val = g_value_get_int (value); // TODO:16
+        dbus_message_iter_append_basic (iter, DBUS_TYPE_INT16, &val);
+      }
+      break;
+
+    case DBUS_TYPE_UINT16:
+      {
+        dbus_uint16_t val = g_value_get_uint (value); // TODO:16
+        dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT16, &val);
+      }
+      break;
+
+    case DBUS_TYPE_INT32:
+      {
+        dbus_int32_t val = g_value_get_int (value);
+        dbus_message_iter_append_basic (iter, DBUS_TYPE_INT32, &val);
+      }
+      break;
+
+    case DBUS_TYPE_UINT32:
+      {
+        dbus_uint32_t val;
+        if (value->g_type == G_TYPE_UINT)
+          {
+            val = g_value_get_uint (value);
+          }
+        else if (G_TYPE_IS_ENUM (value->g_type))
+          {
+            val = g_value_get_enum (value);
+          }
+        else if (G_TYPE_IS_FLAGS (value->g_type))
+          {
+            val = g_value_get_flags (value);
+          }
+        dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT32, &val);
+      }
+      break;
+
+    case DBUS_TYPE_INT64:
+      {
+        dbus_int64_t val = g_value_get_int64 (value);
+        dbus_message_iter_append_basic (iter, DBUS_TYPE_INT64, &val);
+      }
+      break;
+
+    case DBUS_TYPE_UINT64:
+      {
+        dbus_uint64_t val = g_value_get_uint64 (value);
+        dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT64, &val);
+      }
+      break;
+
+    case DBUS_TYPE_DOUBLE:
+      {
+        double val = g_value_get_double (value);
+        dbus_message_iter_append_basic (iter, DBUS_TYPE_DOUBLE, &val);
+      }
+      break;
+
+    /* ---------------------------------------------------------------------------------------------------- */
+    case DBUS_TYPE_ARRAY:
+      if (signature[1] == DBUS_TYPE_BYTE   ||
+          signature[1] == DBUS_TYPE_INT16  ||
+          signature[1] == DBUS_TYPE_UINT16 ||
+          signature[1] == DBUS_TYPE_INT32  ||
+          signature[1] == DBUS_TYPE_UINT32 ||
+          signature[1] == DBUS_TYPE_INT64  ||
+          signature[1] == DBUS_TYPE_UINT64 ||
+          signature[1] == DBUS_TYPE_DOUBLE ||
+          signature[1] == DBUS_TYPE_BOOLEAN)
+        {
+          DBusMessageIter array_iter;
+          GArray *a;
+
+          a = (GArray *) g_value_get_boxed (value);
+
+          if (a != NULL && a->len > 0 && get_element_size (signature[1]) != g_array_get_element_size (a))
+            {
+              g_set_error (error,
+                           G_DBUS_ERROR,
+                           G_DBUS_ERROR_FAILED,
+                           "GArray has element size %d but element size %d was expected",
+                           get_element_size (signature[1]),
+                           g_array_get_element_size (a));
+              goto out;
+            }
+
+          dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, signature + 1, &array_iter);
+          dbus_message_iter_append_fixed_array (&array_iter, signature[1], &(a->data), a->len);
+          dbus_message_iter_close_container (iter, &array_iter);
+        }
+      else if (signature[1] == DBUS_TYPE_STRING ||
+               signature[1] == DBUS_TYPE_OBJECT_PATH ||
+               signature[1] == DBUS_TYPE_SIGNATURE)
+        {
+          DBusMessageIter array_iter;
+          gchar **strv;
+          guint n;
+
+          strv = (gchar **) g_value_get_boxed (value);
+          dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, signature + 1, &array_iter);
+          for (n = 0; strv[n] != NULL; n++)
+            dbus_message_iter_append_basic (&array_iter, signature[1], &(strv[n]));
+          dbus_message_iter_close_container (iter, &array_iter);
+        }
+      else if (signature[1] == DBUS_STRUCT_BEGIN_CHAR)
+        {
+          DBusMessageIter array_iter;
+          GPtrArray *p;
+          guint n;
+
+          p = g_value_get_boxed (value);
+          dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, signature + 1, &array_iter);
+          for (n = 0; n < p->len; n++)
+            {
+              GValue val = {0};
+              g_value_init (&val, G_TYPE_DBUS_STRUCTURE);
+              g_value_take_object (&val, G_DBUS_STRUCTURE (p->pdata[n]));
+              /* recursive dance */
+              if (!g_dbus_c_type_mapping_append_value_to_iter (&array_iter, signature + 1, &val, error))
+                goto out;
+            }
+          dbus_message_iter_close_container (iter, &array_iter);
+        }
+      else if (signature[1] == DBUS_DICT_ENTRY_BEGIN_CHAR)
+        {
+          DBusMessageIter array_iter;
+          GHashTable *hash_table;
+          GHashTableIter hash_iter;
+          gpointer hash_key;
+          gpointer hash_value;
+          char *value_signature;
+
+          value_signature = g_strdup (signature + 3);
+          value_signature[strlen (value_signature) - 1] = '\0';
+
+          hash_table = g_value_get_boxed (value);
+
+          //g_debug ("signature='%s' value_signature='%s'", signature, value_signature);
+
+          dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, signature + 1, &array_iter);
+          g_hash_table_iter_init (&hash_iter, hash_table);
+          while (g_hash_table_iter_next (&hash_iter, &hash_key, &hash_value))
+            {
+              GValue val = {0};
+              DBusMessageIter dict_iter;
+
+              dbus_message_iter_open_container (&array_iter,
+                                                DBUS_TYPE_DICT_ENTRY,
+                                                NULL,
+                                                &dict_iter);
+              switch (signature[2])
+                {
+                case DBUS_TYPE_STRING:
+                case DBUS_TYPE_OBJECT_PATH:
+                case DBUS_TYPE_SIGNATURE:
+                case DBUS_TYPE_BYTE:
+                case DBUS_TYPE_BOOLEAN:
+                case DBUS_TYPE_INT16:
+                case DBUS_TYPE_UINT16:
+                case DBUS_TYPE_INT32:
+                case DBUS_TYPE_UINT32:
+                  dbus_message_iter_append_basic (&dict_iter, signature[2], &hash_key);
+                  break;
+
+                case DBUS_TYPE_INT64:
+                case DBUS_TYPE_UINT64:
+                case DBUS_TYPE_DOUBLE:
+                  dbus_message_iter_append_basic (&dict_iter, signature[2], hash_key);
+                  break;
+
+                default:
+                  /* the D-Bus spec says the hash_key must be a basic type */
+                  g_assert_not_reached ();
+                  break;
+                }
+
+              //g_debug ("value_signature='%s'", value_signature);
+              switch (value_signature[0])
+                {
+                case DBUS_TYPE_STRING:
+                case DBUS_TYPE_OBJECT_PATH:
+                case DBUS_TYPE_SIGNATURE:
+                case DBUS_TYPE_BYTE:
+                case DBUS_TYPE_BOOLEAN:
+                case DBUS_TYPE_INT16:
+                case DBUS_TYPE_UINT16:
+                case DBUS_TYPE_INT32:
+                case DBUS_TYPE_UINT32:
+                  dbus_message_iter_append_basic (&dict_iter, signature[2], &hash_value);
+                  break;
+
+                case DBUS_TYPE_INT64:
+                case DBUS_TYPE_UINT64:
+                case DBUS_TYPE_DOUBLE:
+                  dbus_message_iter_append_basic (&dict_iter, signature[2], hash_value);
+                  break;
+
+                case DBUS_STRUCT_BEGIN_CHAR:
+                  g_value_init (&val, G_TYPE_DBUS_STRUCTURE);
+                  g_value_take_object (&val, G_DBUS_STRUCTURE (hash_value));
+                  /* recursive dance */
+                  if (!g_dbus_c_type_mapping_append_value_to_iter (&dict_iter, value_signature, &val, error))
+                    goto out;
+                  break;
+
+                case DBUS_TYPE_ARRAY:
+                  if (value_signature[1] == DBUS_TYPE_BYTE ||
+                      value_signature[1] == DBUS_TYPE_INT16 ||
+                      value_signature[1] == DBUS_TYPE_UINT16 ||
+                      value_signature[1] == DBUS_TYPE_INT32 ||
+                      value_signature[1] == DBUS_TYPE_UINT32 ||
+                      value_signature[1] == DBUS_TYPE_INT64 ||
+                      value_signature[1] == DBUS_TYPE_UINT64 ||
+                      value_signature[1] == DBUS_TYPE_BOOLEAN ||
+                      value_signature[1] == DBUS_TYPE_DOUBLE)
+                    {
+                      g_value_init (&val, G_TYPE_ARRAY);
+                      g_value_take_boxed (&val, hash_value);
+                      /* recurse */
+                      if (!g_dbus_c_type_mapping_append_value_to_iter (&dict_iter, value_signature, &val, error))
+                        goto out;
+                    }
+                  else if (value_signature[1] == DBUS_TYPE_STRING ||
+                           value_signature[1] == DBUS_TYPE_OBJECT_PATH ||
+                           value_signature[1] == DBUS_TYPE_SIGNATURE)
+                    {
+                      GType boxed_type;
+
+                      if (value_signature[1] == DBUS_TYPE_STRING)
+                        boxed_type = G_TYPE_STRV;
+                      else if (value_signature[1] == DBUS_TYPE_OBJECT_PATH)
+                        boxed_type = G_TYPE_STRV; // TODO:o EGG_DBUS_TYPE_OBJECT_PATH_ARRAY;
+                      else if (value_signature[1] == DBUS_TYPE_SIGNATURE)
+                        boxed_type = G_TYPE_STRV; // TODO:o EGG_DBUS_TYPE_SIGNATURE_ARRAY;
+                      else
+                        g_assert_not_reached ();
+
+                      g_value_init (&val, boxed_type);
+                      g_value_set_static_boxed (&val, hash_value);
+                      /* recurse */
+                      if (!g_dbus_c_type_mapping_append_value_to_iter (&dict_iter, value_signature, &val, error))
+                        goto out;
+                    }
+                  else if (value_signature[1] == DBUS_STRUCT_BEGIN_CHAR)
+                    {
+                      g_value_init (&val, G_TYPE_PTR_ARRAY);
+                      g_value_take_boxed (&val, hash_value);
+                      /* recurse */
+                      if (!g_dbus_c_type_mapping_append_value_to_iter (&dict_iter, value_signature, &val, error))
+                        goto out;
+                    }
+                  else if (value_signature[1] == DBUS_DICT_ENTRY_BEGIN_CHAR)
+                    {
+                      g_value_init (&val, G_TYPE_HASH_TABLE);
+                      g_value_take_boxed (&val, hash_value);
+                      /* recurse */
+                      if (!g_dbus_c_type_mapping_append_value_to_iter (&dict_iter, value_signature, &val, error))
+                        goto out;
+                    }
+                  else if (value_signature[1] == DBUS_TYPE_VARIANT)
+                    {
+                      g_value_init (&val, G_TYPE_PTR_ARRAY);
+                      g_value_take_boxed (&val, hash_value);
+                      /* recurse */
+                      if (!g_dbus_c_type_mapping_append_value_to_iter (&dict_iter, value_signature, &val, error))
+                        goto out;
+                    }
+                  else if (value_signature[1] == DBUS_TYPE_ARRAY)
+                    {
+                      g_value_init (&val, G_TYPE_PTR_ARRAY);
+                      g_value_take_boxed (&val, hash_value);
+                      /* recurse */
+                      if (!g_dbus_c_type_mapping_append_value_to_iter (&dict_iter, value_signature, &val, error))
+                        goto out;
+                    }
+                  else
+                    {
+                      g_assert_not_reached ();
+                    }
+                  break;
+
+                case DBUS_TYPE_VARIANT:
+                  g_value_init (&val, G_TYPE_DBUS_VARIANT);
+                  g_value_take_object (&val, hash_value);
+                  /* recurse */
+                  if (!g_dbus_c_type_mapping_append_value_to_iter (&dict_iter, value_signature, &val, error))
+                    goto out;
+                  break;
+
+                default:
+                  g_assert_not_reached ();
+                  break;
+                }
+
+              dbus_message_iter_close_container (&array_iter, &dict_iter);
+            }
+          dbus_message_iter_close_container (iter, &array_iter);
+
+          g_free (value_signature);
+        }
+      else if (signature[1] == DBUS_TYPE_ARRAY) /* array of an array */
+        {
+          DBusMessageIter array_iter;
+          GPtrArray *p;
+          guint n;
+
+          p = g_value_get_boxed (value);
+          dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, signature + 1, &array_iter);
+          for (n = 0; n < p->len; n++)
+            {
+              GValue val = {0};
+
+              g_value_init (&val, _g_dbus_signature_get_gtype (signature + 1));
+
+              /* this can either be boxed (for GStrv, GArray) or an object (for e.g. structs, variants) */
+              if (g_type_is_a (G_VALUE_TYPE (&val), G_TYPE_BOXED))
+                g_value_take_boxed (&val, p->pdata[n]);
+              else if (g_type_is_a (G_VALUE_TYPE (&val), G_TYPE_OBJECT))
+                g_value_take_object (&val, p->pdata[n]);
+              else
+                g_assert_not_reached ();
+
+              /* recursive dance */
+              if (!g_dbus_c_type_mapping_append_value_to_iter (&array_iter, signature + 1, &val, error))
+                goto out;
+            }
+
+          dbus_message_iter_close_container (iter, &array_iter);
+        }
+      else if (signature[1] == DBUS_TYPE_VARIANT ) /* array of variants */
+        {
+          DBusMessageIter array_iter;
+          GPtrArray *p;
+          guint n;
+
+          p = g_value_get_boxed (value);
+          dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, signature + 1, &array_iter);
+          for (n = 0; n < p->len; n++)
+            {
+              GValue val = {0};
+
+              g_value_init (&val, G_TYPE_DBUS_VARIANT);
+              g_value_take_object (&val, p->pdata[n]);
+
+              /* recursive dance */
+              if (!g_dbus_c_type_mapping_append_value_to_iter (&array_iter, signature + 1, &val, error))
+                goto out;
+            }
+
+          dbus_message_iter_close_container (iter, &array_iter);
+        }
+      else
+        {
+          g_warning ("Don't know append an array with elements with with signature %s", signature + 1);
+          g_assert_not_reached ();
+        }
+      break;
+
+    /* ---------------------------------------------------------------------------------------------------- */
+    case DBUS_STRUCT_BEGIN_CHAR:
+      {
+        DBusMessageIter struct_iter;
+        GDBusStructure *structure;
+        guint n;
+        guint num_elems;
+
+        structure = G_DBUS_STRUCTURE (g_value_get_object (value));
+
+        num_elems = g_dbus_structure_get_num_elements (structure);
+
+        dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, &struct_iter);
+        for (n = 0; n < num_elems; n++)
+          {
+            const GValue *val;
+            const gchar *sig_for_elem;
+
+            val = _g_dbus_structure_get_gvalue_for_element (structure, n);
+            sig_for_elem = g_dbus_structure_get_signature_for_element (structure, n);
+            /* recurse */
+            if (!g_dbus_c_type_mapping_append_value_to_iter (&struct_iter, sig_for_elem, val, error))
+              goto out;
+          }
+        dbus_message_iter_close_container (iter, &struct_iter);
+      }
+      break;
+
+    /* ---------------------------------------------------------------------------------------------------- */
+    case DBUS_TYPE_VARIANT:
+      {
+        GDBusVariant *variant;
+        DBusMessageIter variant_iter;
+        const gchar *variant_signature;
+        GValue val = {0};
+
+        g_value_init (&val, G_TYPE_DBUS_VARIANT);
+        variant = g_value_get_object (value);
+
+        variant_signature = g_dbus_variant_get_variant_signature (variant);
+
+        dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, variant_signature, &variant_iter);
+        /* recurse */
+        if (!g_dbus_c_type_mapping_append_value_to_iter (&variant_iter,
+                                                         variant_signature,
+                                                         _g_dbus_variant_get_gvalue (variant),
+                                                         error))
+          goto out;
+        dbus_message_iter_close_container (iter, &variant_iter);
+      }
+      break;
+
+    default:
+      g_warning ("Don't know append a value with signature %s", signature);
+      g_assert_not_reached ();
+      break;
+    }
+
+  ret = TRUE;
+
+ out:
+  return ret;
+}
+
+
+#define __G_DBUS_C_TYPE_MAPPING_C__
+#include "gdbusaliasdef.c"
diff --git a/gdbus/gdbusproxy.c b/gdbus/gdbusproxy.c
index 1689497..4f13b40 100644
--- a/gdbus/gdbusproxy.c
+++ b/gdbus/gdbusproxy.c
@@ -30,6 +30,7 @@
 #include "gdbusenumtypes.h"
 #include "gdbusconnection.h"
 #include "gdbusconnection-lowlevel.h"
+#include "gdbusctypemapping-lowlevel.h"
 #include "gdbuserror.h"
 #include "gdbusstructure.h"
 #include "gdbusvariant.h"
@@ -90,9 +91,6 @@ enum
 };
 
 static void g_dbus_proxy_constructed (GObject *object);
-static gboolean get_value_from_iter (DBusMessageIter *iter,
-                                     GValue          *out_value,
-                                     GError         **error);
 
 guint signals[LAST_SIGNAL] = {0};
 
@@ -113,14 +111,14 @@ g_dbus_proxy_finalize (GObject *object)
 
   if (proxy->priv->properties_changed_subscriber_id > 0)
     {
-      g_dbus_connection_dbus_1_signal_unsubscribe (proxy->priv->connection,
-                                                   proxy->priv->properties_changed_subscriber_id);
+      g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
+                                            proxy->priv->properties_changed_subscriber_id);
     }
 
   if (proxy->priv->signals_subscriber_id > 0)
     {
-      g_dbus_connection_dbus_1_signal_unsubscribe (proxy->priv->connection,
-                                                   proxy->priv->signals_subscriber_id);
+      g_dbus_connection_signal_unsubscribe (proxy->priv->connection,
+                                            proxy->priv->signals_subscriber_id);
     }
 
   g_object_unref (proxy->priv->connection);
@@ -391,8 +389,8 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass)
    * GDBusProxy::g-dbus-proxy-signal:
    * @proxy: The #GDBusProxy emitting the signal.
    * @name: The name of the signal.
-   * @signature: The signature of the signal.
-   * @args: A #GValueArray containing the arguments for the signal.
+   * @signature: The D-Bus signature of the signal.
+   * @args: A #GPtrArray containing one #GDBusVariant for each argument of the signal.
    *
    * Emitted when a signal from the remote object and interface that @proxy is for, has been received.
    **/
@@ -407,7 +405,7 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass)
                                          3,
                                          G_TYPE_STRING,
                                          G_TYPE_STRING,
-                                         G_TYPE_VALUE_ARRAY);
+                                         G_TYPE_PTR_ARRAY);
 
 
   g_type_class_add_private (klass, sizeof (GDBusProxyPrivate));
@@ -526,75 +524,39 @@ get_all_cb (GDBusProxy   *proxy,
 
 static void
 on_signal_received (GDBusConnection  *connection,
-                    DBusMessage      *message,
+                    const gchar      *name,
+                    const gchar      *signature,
+                    GPtrArray        *args,
                     gpointer          user_data)
 {
   GDBusProxy *proxy = G_DBUS_PROXY (user_data);
-  GValueArray *value_array;
-  DBusMessageIter iter;
-  guint n;
-
-  value_array = g_value_array_new (0);
-
-  dbus_message_iter_init (message, &iter);
-
-  n = 0;
-  while (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
-    {
-      GValue value = {0};
-      GError *error;
-
-      error = NULL;
-      if (!get_value_from_iter (&iter,
-                                &value,
-                                &error))
-        {
-          g_warning ("Error getting argument %d from %s signal: %s",
-                     n,
-                     dbus_message_get_member (message),
-                     error->message);
-          g_error_free (error);
-          goto out;
-        }
-
-      g_value_array_append (value_array, &value);
-      g_value_unset (&value);
-
-      dbus_message_iter_next (&iter);
-      n++;
-    }
 
   g_signal_emit (proxy,
                  signals[SIGNAL_SIGNAL],
                  0,
-                 dbus_message_get_member (message),
-                 dbus_message_get_signature (message),
-                 value_array);
-
- out:
-  g_value_array_free (value_array);
+                 name,
+                 signature,
+                 args);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
 on_properties_changed (GDBusConnection  *connection,
-                       DBusMessage      *message,
+                       const gchar      *name,
+                       const gchar      *signature,
+                       GPtrArray        *args,
                        gpointer          user_data)
 {
   GDBusProxy *proxy = G_DBUS_PROXY (user_data);
-  DBusMessageIter iter;
   GError *error;
-  GValue value;
-  gchar *interface_name;
+  const gchar *interface_name;
   GHashTable *changed_properties;
   GHashTableIter hash_iter;
   gchar *property_name;
   GDBusVariant *property_value;
 
   error = NULL;
-  interface_name = NULL;
-  changed_properties = NULL;
 
   /* Ignore this signal if properties are not yet available
    *
@@ -604,26 +566,18 @@ on_properties_changed (GDBusConnection  *connection,
   if (!proxy->priv->properties_available)
     goto out;
 
-  dbus_message_iter_init (message, &iter);
-  memset (&value, '\0', sizeof (GValue));
-  if (!get_value_from_iter (&iter,
-                            &value,
-                            &error))
+  if (args->len != 2)
     {
-      g_warning ("Error getting argument 1 of PropertiesChanged() signal: %s",
-                 error->message);
-      g_error_free (error);
+      g_warning ("Incorrect number of values in PropertiesChanged() signal");
       goto out;
     }
-  if (G_VALUE_TYPE (&value) != G_TYPE_STRING)
+
+  if (!g_dbus_variant_is_string (G_DBUS_VARIANT (args->pdata[0])))
     {
-      g_warning ("Expected a string for argument 1 of PropertiesChanged() but got %s",
-                 g_type_name (G_VALUE_TYPE (&value)));
-      g_value_unset (&value);
+      g_warning ("Expected a string for argument 1 of PropertiesChanged()");
       goto out;
     }
-  interface_name = g_value_dup_string (&value);
-  g_value_unset (&value);
+  interface_name = g_dbus_variant_get_string (G_DBUS_VARIANT (args->pdata[0]));
 
   if (g_strcmp0 (interface_name, proxy->priv->interface_name) != 0)
     {
@@ -633,27 +587,12 @@ on_properties_changed (GDBusConnection  *connection,
       goto out;
     }
 
-  dbus_message_iter_next (&iter);
-
-  memset (&value, '\0', sizeof (GValue));
-  if (!get_value_from_iter (&iter,
-                            &value,
-                            &error))
+  if (!g_dbus_variant_is_hash_table (G_DBUS_VARIANT (args->pdata[1])))
     {
-      g_warning ("Error getting argument 2 of PropertiesChanged() signal: %s",
-                 error->message);
-      g_error_free (error);
+      g_warning ("Expected a hash table for argument 2 of PropertiesChanged()");
       goto out;
     }
-  if (G_VALUE_TYPE (&value) != G_TYPE_HASH_TABLE)
-    {
-      g_warning ("Expected a hash table for argument 2 of PropertiesChanged() but got %s",
-                 g_type_name (G_VALUE_TYPE (&value)));
-      g_value_unset (&value);
-      goto out;
-    }
-  changed_properties = g_value_dup_boxed (&value);
-  g_value_unset (&value);
+  changed_properties = g_dbus_variant_get_hash_table (G_DBUS_VARIANT (args->pdata[1]));
 
   /* update local cache */
   g_hash_table_iter_init (&hash_iter, changed_properties);
@@ -670,9 +609,7 @@ on_properties_changed (GDBusConnection  *connection,
   g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL], 0, changed_properties);
 
  out:
-  g_free (interface_name);
-  if (changed_properties != NULL)
-    g_hash_table_unref (changed_properties);
+  ;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -692,14 +629,15 @@ on_watcher_name_appeared (GBusNameWatcher *watcher,
 
       /* subscribe to PropertiesChanged() */
       proxy->priv->properties_changed_subscriber_id =
-        g_dbus_connection_dbus_1_signal_subscribe (proxy->priv->connection,
-                                                   g_bus_name_watcher_get_name_owner (proxy->priv->watcher),
-                                                   "org.freedesktop.DBus.Properties",
-                                                   "PropertiesChanged",
-                                                   proxy->priv->object_path,
-                                                   proxy->priv->interface_name,
-                                                   on_properties_changed,
-                                                   proxy);
+        g_dbus_connection_signal_subscribe (proxy->priv->connection,
+                                            g_bus_name_watcher_get_name_owner (proxy->priv->watcher),
+                                            "org.freedesktop.DBus.Properties",
+                                            "PropertiesChanged",
+                                            proxy->priv->object_path,
+                                            proxy->priv->interface_name,
+                                            on_properties_changed,
+                                            proxy,
+                                            NULL);
 
       /* start loading properties */
       proxy->priv->property_loading_pending_call_id =
@@ -722,14 +660,15 @@ on_watcher_name_appeared (GBusNameWatcher *watcher,
 
       /* subscribe to all signals for the object */
       proxy->priv->signals_subscriber_id =
-        g_dbus_connection_dbus_1_signal_subscribe (proxy->priv->connection,
-                                                   g_bus_name_watcher_get_name_owner (proxy->priv->watcher),
-                                                   proxy->priv->interface_name,
-                                                   NULL,                        /* member */
-                                                   proxy->priv->object_path,
-                                                   NULL,                        /* arg0 */
-                                                   on_signal_received,
-                                                   proxy);
+        g_dbus_connection_signal_subscribe (proxy->priv->connection,
+                                            g_bus_name_watcher_get_name_owner (proxy->priv->watcher),
+                                            proxy->priv->interface_name,
+                                            NULL,                        /* member */
+                                            proxy->priv->object_path,
+                                            NULL,                        /* arg0 */
+                                            on_signal_received,
+                                            proxy,
+                                            NULL);
     }
 
   g_object_notify (G_OBJECT (proxy), "g-dbus-proxy-name-owner");
@@ -1014,1266 +953,6 @@ g_dbus_proxy_get_properties_available (GDBusProxy *proxy)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-static guint
-get_element_size (gchar dbus_type_code)
-{
-  guint ret;
-
-  switch (dbus_type_code)
-    {
-    case DBUS_TYPE_BYTE:
-      ret = 1;
-      break;
-    case DBUS_TYPE_BOOLEAN:
-      ret = sizeof (gboolean);
-      break;
-    case DBUS_TYPE_INT16:
-    case DBUS_TYPE_UINT16:
-      ret = sizeof (gint16);
-      break;
-    case DBUS_TYPE_INT32:
-    case DBUS_TYPE_UINT32:
-      ret = sizeof (gint);
-      break;
-    case DBUS_TYPE_INT64:
-    case DBUS_TYPE_UINT64:
-      ret = sizeof (gint64);
-      break;
-    case DBUS_TYPE_DOUBLE:
-      ret = sizeof (gdouble);
-      break;
-    default:
-      g_assert_not_reached ();
-    }
-
-  return ret;
-}
-
-static gboolean
-get_value_from_iter (DBusMessageIter *iter,
-                     GValue          *out_value,
-                     GError         **error)
-{
-  int arg_type;
-  int array_arg_type;
-  dbus_bool_t bool_val;
-  const char *str_val;
-  guchar uint8_val;
-  dbus_int16_t int16_val;
-  dbus_uint16_t uint16_val;
-  dbus_int32_t int32_val;
-  dbus_uint32_t uint32_val;
-  dbus_int64_t int64_val;
-  dbus_uint64_t uint64_val;
-  double double_val;
-  gboolean ret;
-
-  /* TODO: - fill in @error instead of using g_assert_not_reached() */
-
-  g_return_val_if_fail (iter != NULL, FALSE);
-  g_return_val_if_fail (out_value != NULL, FALSE);
-
-  ret = FALSE;
-
-  arg_type = dbus_message_iter_get_arg_type (iter);
-
-  switch (arg_type)
-    {
-    case DBUS_TYPE_STRING:
-      g_value_init (out_value, G_TYPE_STRING);
-      dbus_message_iter_get_basic (iter, &str_val);
-      g_value_set_string (out_value, str_val);
-      break;
-
-    case DBUS_TYPE_OBJECT_PATH:
-      g_value_init (out_value, G_TYPE_STRING); // TODO:o
-      dbus_message_iter_get_basic (iter, &str_val);
-      g_value_set_string (out_value, str_val);
-      break;
-
-    case DBUS_TYPE_SIGNATURE:
-      g_value_init (out_value, G_TYPE_STRING); // TODO:g
-      dbus_message_iter_get_basic (iter, &str_val);
-      g_value_set_string (out_value, str_val);
-      break;
-
-    case DBUS_TYPE_BOOLEAN:
-      g_value_init (out_value, G_TYPE_BOOLEAN);
-      dbus_message_iter_get_basic (iter, &bool_val);
-      g_value_set_boolean (out_value, bool_val);
-      break;
-
-    case DBUS_TYPE_BYTE:
-      g_value_init (out_value, G_TYPE_UCHAR);
-      dbus_message_iter_get_basic (iter, &uint8_val);
-      g_value_set_uchar (out_value, uint8_val);
-      break;
-
-    case DBUS_TYPE_INT16:
-      g_value_init (out_value, G_TYPE_INT); // TODO:16
-      dbus_message_iter_get_basic (iter, &int16_val);
-      g_value_set_int (out_value, int16_val);
-      break;
-
-    case DBUS_TYPE_UINT16:
-      g_value_init (out_value, G_TYPE_UINT); // TODO:16
-      dbus_message_iter_get_basic (iter, &uint16_val);
-      g_value_set_uint (out_value, uint16_val);
-      break;
-
-    case DBUS_TYPE_INT32:
-      g_value_init (out_value, G_TYPE_INT);
-      dbus_message_iter_get_basic (iter, &int32_val);
-      g_value_set_int (out_value, int32_val);
-      break;
-
-    case DBUS_TYPE_UINT32:
-      g_value_init (out_value, G_TYPE_UINT);
-      dbus_message_iter_get_basic (iter, &uint32_val);
-      g_value_set_uint (out_value, uint32_val);
-      break;
-
-    case DBUS_TYPE_INT64:
-      g_value_init (out_value, G_TYPE_INT64);
-      dbus_message_iter_get_basic (iter, &int64_val);
-      g_value_set_int64 (out_value, int64_val);
-      break;
-
-    case DBUS_TYPE_UINT64:
-      g_value_init (out_value, G_TYPE_UINT64);
-      dbus_message_iter_get_basic (iter, &uint64_val);
-      g_value_set_uint64 (out_value, uint64_val);
-      break;
-
-    case DBUS_TYPE_DOUBLE:
-      g_value_init (out_value, G_TYPE_DOUBLE);
-      dbus_message_iter_get_basic (iter, &double_val);
-      g_value_set_double (out_value, double_val);
-      break;
-
-    case DBUS_TYPE_STRUCT:
-      {
-        DBusMessageIter struct_iter;
-        char *struct_signature;
-        GDBusStructure *structure;
-        GArray *a;
-
-        struct_signature = dbus_message_iter_get_signature (iter);
-
-        a = g_array_new (FALSE,
-                         TRUE,
-                         sizeof (GValue));
-
-        dbus_message_iter_recurse (iter, &struct_iter);
-
-        /* now collect all the elements in the structure as GValue objects */
-        while (dbus_message_iter_get_arg_type (&struct_iter) != DBUS_TYPE_INVALID)
-          {
-            GValue *value;
-
-            g_array_set_size (a, a->len + 1);
-            value = &g_array_index (a, GValue, a->len - 1);
-
-            /* doing the recursive dance! */
-            if (!get_value_from_iter (&struct_iter, value, error))
-              goto out;
-
-            dbus_message_iter_next (&struct_iter);
-          }
-
-        /* takes ownership of elems */
-        structure = _g_dbus_structure_new_for_values (struct_signature,
-                                                      a->len,
-                                                      (GValue *) a->data);
-        g_assert (structure != NULL);
-
-        g_array_free (a, FALSE);
-
-        g_value_init (out_value, G_TYPE_DBUS_STRUCTURE);
-        g_value_take_object (out_value, structure);
-
-        dbus_free (struct_signature);
-      }
-      break;
-
-    case DBUS_TYPE_ARRAY:
-      array_arg_type = dbus_message_iter_get_element_type (iter);
-      if (array_arg_type == DBUS_TYPE_STRING ||
-          array_arg_type == DBUS_TYPE_OBJECT_PATH ||
-          array_arg_type == DBUS_TYPE_SIGNATURE)
-        {
-          GPtrArray *p;
-          DBusMessageIter array_iter;
-          GType boxed_type;
-
-          if (array_arg_type == DBUS_TYPE_STRING)
-            boxed_type = G_TYPE_STRV;
-          else if (array_arg_type == DBUS_TYPE_OBJECT_PATH)
-            boxed_type = G_TYPE_STRV; // TODO:o EGG_DBUS_TYPE_OBJECT_PATH_ARRAY;
-          else if (array_arg_type == DBUS_TYPE_SIGNATURE)
-            boxed_type = G_TYPE_STRV; // TODO:g EGG_DBUS_TYPE_SIGNATURE_ARRAY;
-          else
-            g_assert_not_reached ();
-
-          dbus_message_iter_recurse (iter, &array_iter);
-          p = g_ptr_array_new ();
-          while (dbus_message_iter_get_arg_type (&array_iter) != DBUS_TYPE_INVALID)
-            {
-              dbus_message_iter_get_basic (&array_iter, &str_val);
-              g_ptr_array_add (p, (void *) g_strdup (str_val));
-              dbus_message_iter_next (&array_iter);
-            }
-          g_ptr_array_add (p, NULL);
-          g_value_init (out_value, boxed_type);
-          g_value_take_boxed (out_value, p->pdata);
-          g_ptr_array_free (p, FALSE);
-        }
-      else if (array_arg_type == DBUS_TYPE_BYTE ||
-               array_arg_type == DBUS_TYPE_INT16 ||
-               array_arg_type == DBUS_TYPE_UINT16 ||
-               array_arg_type == DBUS_TYPE_INT32 ||
-               array_arg_type == DBUS_TYPE_UINT32 ||
-               array_arg_type == DBUS_TYPE_INT64 ||
-               array_arg_type == DBUS_TYPE_UINT64 ||
-               array_arg_type == DBUS_TYPE_BOOLEAN ||
-               array_arg_type == DBUS_TYPE_DOUBLE)
-        {
-          GArray *a;
-          DBusMessageIter array_iter;
-          gconstpointer data;
-          gint num_items;
-
-          dbus_message_iter_recurse (iter, &array_iter);
-          dbus_message_iter_get_fixed_array (&array_iter,
-                                             &data,
-                                             (int*) &num_items);
-          a = g_array_sized_new (FALSE, FALSE, get_element_size (array_arg_type), num_items);
-          g_array_append_vals (a, data, num_items);
-          g_value_init (out_value, G_TYPE_ARRAY);
-          g_value_take_boxed (out_value, a);
-        }
-      else if (array_arg_type == DBUS_TYPE_STRUCT)
-        {
-          DBusMessageIter array_iter;
-          char *struct_signature;
-          GPtrArray *p;
-
-          p = g_ptr_array_new_with_free_func (g_object_unref);
-
-          dbus_message_iter_recurse (iter, &array_iter);
-
-          struct_signature = dbus_message_iter_get_signature (&array_iter);
-
-          /* now collect all the elements in the structure.
-           */
-          while (dbus_message_iter_get_arg_type (&array_iter) != DBUS_TYPE_INVALID)
-            {
-              GValue elem_value = {0};
-
-              /* recurse */
-              if (!get_value_from_iter (&array_iter, &elem_value, error))
-                {
-                  dbus_free (struct_signature);
-                  g_ptr_array_unref (p);
-                  goto out;
-                }
-
-              g_ptr_array_add (p, g_value_get_object (&elem_value));
-
-              dbus_message_iter_next (&array_iter);
-            }
-
-          g_value_init (out_value, G_TYPE_PTR_ARRAY);
-          g_value_take_boxed (out_value, p);
-
-          dbus_free (struct_signature);
-        }
-      else if (array_arg_type == DBUS_TYPE_DICT_ENTRY)
-        {
-          DBusMessageIter array_iter;
-          GHashTable *hash;
-          char key_sig[2];
-          char *val_sig;
-          char *array_sig;
-          GHashFunc hash_func;
-          GEqualFunc equal_func;
-          GDestroyNotify key_free_func;
-          GDestroyNotify val_free_func;
-
-          dbus_message_iter_recurse (iter, &array_iter);
-
-          array_sig = dbus_message_iter_get_signature (&array_iter);
-
-          /* keys are guaranteed by the D-Bus spec to be primitive types */
-          key_sig[0] = array_sig[1];
-          key_sig[1] = '\0';
-          val_sig = g_strdup (array_sig + 2);
-          val_sig[strlen (val_sig) - 1] = '\0';
-
-          /* set up the hash table */
-
-          switch (key_sig[0])
-            {
-            case DBUS_TYPE_BOOLEAN:
-            case DBUS_TYPE_BYTE:
-            case DBUS_TYPE_INT16:
-            case DBUS_TYPE_UINT16:
-            case DBUS_TYPE_INT32:
-            case DBUS_TYPE_UINT32:
-              key_free_func = NULL;
-              hash_func = g_direct_hash;
-              equal_func = g_direct_equal;
-              break;
-
-            case DBUS_TYPE_INT64:
-            case DBUS_TYPE_UINT64:
-              hash_func = g_int64_hash;
-              equal_func = g_int64_equal;
-              key_free_func = g_free;
-              break;
-
-            case DBUS_TYPE_DOUBLE:
-              hash_func = g_double_hash;
-              equal_func = g_double_equal;
-              key_free_func = g_free;
-              break;
-
-            case DBUS_TYPE_STRING:
-            case DBUS_TYPE_OBJECT_PATH:
-            case DBUS_TYPE_SIGNATURE:
-              hash_func = g_str_hash;
-              equal_func = g_str_equal;
-              key_free_func = g_free;
-              break;
-
-            default:
-              g_assert_not_reached ();
-              break;
-            }
-
-          switch (val_sig[0])
-            {
-            case DBUS_TYPE_BOOLEAN:
-            case DBUS_TYPE_BYTE:
-            case DBUS_TYPE_INT16:
-            case DBUS_TYPE_UINT16:
-            case DBUS_TYPE_INT32:
-            case DBUS_TYPE_UINT32:
-              val_free_func = NULL;
-              break;
-
-            case DBUS_TYPE_INT64:
-            case DBUS_TYPE_UINT64:
-            case DBUS_TYPE_DOUBLE:
-            case DBUS_TYPE_STRING:
-            case DBUS_TYPE_OBJECT_PATH:
-            case DBUS_TYPE_SIGNATURE:
-              val_free_func = g_free;
-              break;
-
-            case DBUS_TYPE_ARRAY:
-              switch (val_sig[1])
-                {
-                case DBUS_TYPE_STRING:
-                case DBUS_TYPE_OBJECT_PATH:
-                case DBUS_TYPE_SIGNATURE:
-                  val_free_func = (GDestroyNotify) g_strfreev;
-                  break;
-
-                case DBUS_TYPE_BOOLEAN:
-                case DBUS_TYPE_BYTE:
-                case DBUS_TYPE_INT16:
-                case DBUS_TYPE_UINT16:
-                case DBUS_TYPE_INT32:
-                case DBUS_TYPE_UINT32:
-                case DBUS_TYPE_INT64:
-                case DBUS_TYPE_UINT64:
-                case DBUS_TYPE_DOUBLE:
-                  val_free_func = (GDestroyNotify) g_array_unref;
-                  break;
-
-                case DBUS_STRUCT_BEGIN_CHAR:
-                case DBUS_DICT_ENTRY_BEGIN_CHAR:
-                  val_free_func = (GDestroyNotify) g_ptr_array_unref;
-                  break;
-
-                case DBUS_TYPE_VARIANT:
-                  val_free_func = (GDestroyNotify) g_ptr_array_unref;
-                  break;
-
-                case DBUS_TYPE_ARRAY:
-                  val_free_func = (GDestroyNotify) g_ptr_array_unref;
-                  break;
-
-                default:
-                  g_assert_not_reached ();
-                  break;
-                }
-              break;
-
-            case DBUS_STRUCT_BEGIN_CHAR:
-              val_free_func = g_object_unref;
-              break;
-
-            case DBUS_TYPE_VARIANT:
-              val_free_func = g_object_unref;
-              break;
-
-            default:
-              g_assert_not_reached ();
-              break;
-            }
-
-          hash = g_hash_table_new_full (hash_func,
-                                        equal_func,
-                                        key_free_func,
-                                        val_free_func);
-
-          while (dbus_message_iter_get_arg_type (&array_iter) != DBUS_TYPE_INVALID)
-            {
-              DBusMessageIter hash_iter;
-              gpointer key, value;
-              const char *str_val;
-
-              dbus_message_iter_recurse (&array_iter, &hash_iter);
-
-              switch (key_sig[0])
-                {
-                case DBUS_TYPE_BOOLEAN:
-                  dbus_message_iter_get_basic (&hash_iter, &bool_val);
-                  key = GINT_TO_POINTER (bool_val);
-                  break;
-
-                case DBUS_TYPE_BYTE:
-                  dbus_message_iter_get_basic (&hash_iter, &uint8_val);
-                  key = GINT_TO_POINTER (uint8_val);
-                  break;
-
-                case DBUS_TYPE_INT16:
-                  dbus_message_iter_get_basic (&hash_iter, &int16_val);
-                  key = GINT_TO_POINTER (int16_val);
-                  break;
-
-                case DBUS_TYPE_UINT16:
-                  dbus_message_iter_get_basic (&hash_iter, &uint16_val);
-                  key = GINT_TO_POINTER (uint16_val);
-                  break;
-
-                case DBUS_TYPE_INT32:
-                  dbus_message_iter_get_basic (&hash_iter, &int32_val);
-                  key = GINT_TO_POINTER (int32_val);
-                  break;
-
-                case DBUS_TYPE_UINT32:
-                  dbus_message_iter_get_basic (&hash_iter, &uint32_val);
-                  key = GINT_TO_POINTER (uint32_val);
-                  break;
-
-                case DBUS_TYPE_INT64:
-                  dbus_message_iter_get_basic (&hash_iter, &int64_val);
-                  key = g_memdup (&int64_val, sizeof (gint64));
-                  break;
-
-                case DBUS_TYPE_UINT64:
-                  dbus_message_iter_get_basic (&hash_iter, &uint64_val);
-                  key = g_memdup (&uint64_val, sizeof (guint64));
-                  break;
-
-                case DBUS_TYPE_DOUBLE:
-                  dbus_message_iter_get_basic (&hash_iter, &double_val);
-                  key = g_memdup (&double_val, sizeof (gdouble));
-                  break;
-
-                case DBUS_TYPE_STRING:
-                  dbus_message_iter_get_basic (&hash_iter, &str_val);
-                  key = g_strdup (str_val);
-                  break;
-
-                case DBUS_TYPE_OBJECT_PATH:
-                  dbus_message_iter_get_basic (&hash_iter, &str_val);
-                  key = g_strdup (str_val);
-                  break;
-
-                case DBUS_TYPE_SIGNATURE:
-                  dbus_message_iter_get_basic (&hash_iter, &str_val);
-                  key = g_strdup (str_val);
-                  break;
-
-                default:
-                  g_assert_not_reached ();
-                  break;
-                }
-
-              dbus_message_iter_next (&hash_iter);
-
-              switch (val_sig[0])
-                {
-                case DBUS_TYPE_BOOLEAN:
-                  dbus_message_iter_get_basic (&hash_iter, &bool_val);
-                  value = GINT_TO_POINTER (bool_val);
-                  break;
-
-                case DBUS_TYPE_BYTE:
-                  dbus_message_iter_get_basic (&hash_iter, &uint8_val);
-                  value = GINT_TO_POINTER (uint8_val);
-                  break;
-
-                case DBUS_TYPE_INT16:
-                  dbus_message_iter_get_basic (&hash_iter, &int16_val);
-                  value = GINT_TO_POINTER (int16_val);
-                  break;
-
-                case DBUS_TYPE_UINT16:
-                  dbus_message_iter_get_basic (&hash_iter, &uint16_val);
-                  value = GINT_TO_POINTER (uint16_val);
-                  break;
-
-                case DBUS_TYPE_INT32:
-                  dbus_message_iter_get_basic (&hash_iter, &int32_val);
-                  value = GINT_TO_POINTER (int32_val);
-                  break;
-
-                case DBUS_TYPE_INT64:
-                  dbus_message_iter_get_basic (&hash_iter, &int64_val);
-                  value = g_memdup (&int64_val, sizeof (gint64));
-                  break;
-
-                case DBUS_TYPE_UINT64:
-                  dbus_message_iter_get_basic (&hash_iter, &uint64_val);
-                  value = g_memdup (&uint64_val, sizeof (guint64));
-                  break;
-
-                case DBUS_TYPE_DOUBLE:
-                  dbus_message_iter_get_basic (&hash_iter, &double_val);
-                  value = g_memdup (&double_val, sizeof (gdouble));
-                  break;
-
-                case DBUS_TYPE_UINT32:
-                  dbus_message_iter_get_basic (&hash_iter, &uint32_val);
-                  value = GINT_TO_POINTER (uint32_val);
-                  break;
-
-                case DBUS_TYPE_STRING:
-                  dbus_message_iter_get_basic (&hash_iter, &str_val);
-                  value = g_strdup (str_val);
-                  break;
-
-                case DBUS_TYPE_OBJECT_PATH:
-                  dbus_message_iter_get_basic (&hash_iter, &str_val);
-                  value = g_strdup (str_val);
-                  break;
-
-                case DBUS_TYPE_SIGNATURE:
-                  dbus_message_iter_get_basic (&hash_iter, &str_val);
-                  value = g_strdup (str_val);
-                  break;
-
-                case DBUS_TYPE_ARRAY:
-                  {
-                    GValue array_val = {0};
-                    /* recurse */
-                    if (!get_value_from_iter (&hash_iter, &array_val, error))
-                      goto out;
-                    switch (val_sig[1])
-                      {
-                      case DBUS_TYPE_BOOLEAN:
-                      case DBUS_TYPE_BYTE:
-                      case DBUS_TYPE_INT16:
-                      case DBUS_TYPE_UINT16:
-                      case DBUS_TYPE_INT32:
-                      case DBUS_TYPE_UINT32:
-                      case DBUS_TYPE_INT64:
-                      case DBUS_TYPE_UINT64:
-                      case DBUS_TYPE_DOUBLE:
-                      case DBUS_STRUCT_BEGIN_CHAR:
-                      case DBUS_DICT_ENTRY_BEGIN_CHAR:
-                      case DBUS_TYPE_STRING:
-                      case DBUS_TYPE_OBJECT_PATH:
-                      case DBUS_TYPE_SIGNATURE:
-                      case DBUS_TYPE_VARIANT:
-                      case DBUS_TYPE_ARRAY:
-                        value = g_value_get_boxed (&array_val);
-                        break;
-
-                      default:
-                        g_assert_not_reached ();
-                        break;
-                      }
-                  }
-                  break;
-
-                case DBUS_STRUCT_BEGIN_CHAR:
-                  {
-                    GValue object_val = {0};
-                    /* recurse */
-                    if (!get_value_from_iter (&hash_iter, &object_val, error))
-                      goto out;
-                    value = g_value_get_object (&object_val);
-                  }
-                  break;
-
-                case DBUS_TYPE_VARIANT:
-                  {
-                    GValue object_val = {0};
-                    /* recurse */
-                    if (!get_value_from_iter (&hash_iter, &object_val, error))
-                      goto out;
-                    value = g_value_get_object (&object_val);
-                  }
-                  break;
-
-                default:
-                  g_assert_not_reached ();
-                  break;
-                }
-
-              g_hash_table_insert (hash, key, value);
-              dbus_message_iter_next (&array_iter);
-            }
-
-          g_value_init (out_value, G_TYPE_HASH_TABLE);
-          g_value_take_boxed (out_value, hash);
-
-          dbus_free (array_sig);
-          g_free (val_sig);
-
-        }
-      else if (array_arg_type == DBUS_TYPE_ARRAY)
-        {
-          GPtrArray *p;
-          DBusMessageIter array_iter;
-          GDestroyNotify elem_free_func;
-
-          /* handling array of arrays, e.g.
-           *
-           * - aas:    GPtrArray of GStrv (gchar **)
-           * - aao:    GPtrArray of GStrv (gchar **) TODO:o
-           * - aao:    GPtrArray of GStrv (gchar **) TODO:g
-           * - aa{ss}: GPtrArray of GHashTable
-           * - aai:    GPtrArray of GArray
-           * - aa(ii): GPtrArray of GPtrArray containg GObject-derived type
-           * - aaas:   GPtrArray of GPtrArray of GStrv (gchar **)
-           *
-           */
-
-          dbus_message_iter_recurse (iter, &array_iter);
-
-          elem_free_func = NULL;
-
-          p = g_ptr_array_new ();
-          while (dbus_message_iter_get_arg_type (&array_iter) != DBUS_TYPE_INVALID)
-            {
-              GValue elem_val = {0};
-
-              /* recurse */
-              if (!get_value_from_iter (&array_iter, &elem_val, error))
-                goto out;
-
-              if (G_VALUE_TYPE (&elem_val) == G_TYPE_STRV)
-                {
-                  g_ptr_array_add (p, g_value_get_boxed (&elem_val));
-                  elem_free_func = (GDestroyNotify) g_strfreev;
-                }
-              else if (G_VALUE_TYPE (&elem_val) == G_TYPE_ARRAY)
-                {
-                  g_ptr_array_add (p, g_value_get_boxed (&elem_val));
-                  elem_free_func = (GDestroyNotify) g_array_unref;
-                }
-              else if (G_VALUE_TYPE (&elem_val) == G_TYPE_PTR_ARRAY)
-                {
-                  g_ptr_array_add (p, g_value_get_boxed (&elem_val));
-                  elem_free_func = (GDestroyNotify) g_ptr_array_unref;
-                }
-              else if (G_VALUE_TYPE (&elem_val) == G_TYPE_HASH_TABLE)
-                {
-                  g_ptr_array_add (p, g_value_get_boxed (&elem_val));
-                  elem_free_func = (GDestroyNotify) g_hash_table_unref;
-                }
-              else
-                {
-                  g_assert_not_reached ();
-                }
-
-              dbus_message_iter_next (&array_iter);
-            } /* for all elements in array */
-          g_ptr_array_set_free_func (p, elem_free_func);
-          g_value_init (out_value, G_TYPE_PTR_ARRAY);
-          g_value_take_boxed (out_value, p);
-        }
-      else if (array_arg_type == DBUS_TYPE_VARIANT)
-        {
-          GPtrArray *p;
-          DBusMessageIter array_iter;
-          char *elem_signature;
-
-          /* array of variants */
-
-          dbus_message_iter_recurse (iter, &array_iter);
-
-          elem_signature = dbus_message_iter_get_signature (&array_iter);
-
-          p = g_ptr_array_new_with_free_func (g_object_unref);
-          while (dbus_message_iter_get_arg_type (&array_iter) != DBUS_TYPE_INVALID)
-            {
-              GValue elem_val = {0};
-
-              /* recurse */
-              if (!get_value_from_iter (&array_iter, &elem_val, error))
-                goto out;
-
-              g_ptr_array_add (p, g_value_get_object (&elem_val));
-
-              dbus_message_iter_next (&array_iter);
-            } /* for all elements in array */
-
-          g_value_init (out_value, G_TYPE_PTR_ARRAY);
-          g_value_take_boxed (out_value, p);
-
-          dbus_free (elem_signature);
-        }
-      else
-        {
-          char *signature;
-          signature = dbus_message_iter_get_signature (iter);
-          g_set_error (error,
-                       G_DBUS_ERROR,
-                       G_DBUS_ERROR_FAILED,
-                       "Cannot decode message with array of signature %s", signature);
-          g_free (signature);
-          goto out;
-        }
-      break;
-
-    case DBUS_TYPE_VARIANT:
-      {
-        GValue variant_val = {0};
-        GDBusVariant *variant;
-        DBusMessageIter variant_iter;
-        gchar *variant_signature;
-
-        dbus_message_iter_recurse (iter, &variant_iter);
-
-        variant_signature = dbus_message_iter_get_signature (&variant_iter);
-
-        /* recurse */
-        if (!get_value_from_iter (&variant_iter, &variant_val, error))
-          goto out;
-
-        variant = _g_dbus_variant_new_for_gvalue (&variant_val, variant_signature);
-
-        g_value_init (out_value, G_TYPE_DBUS_VARIANT);
-        g_value_take_object (out_value, variant);
-
-        dbus_free (variant_signature);
-      }
-      break;
-
-    default:
-      {
-        char *signature;
-        signature = dbus_message_iter_get_signature (iter);
-        g_set_error (error,
-                     G_DBUS_ERROR,
-                     G_DBUS_ERROR_FAILED,
-                     "Cannot decode message with signature %s", signature);
-        dbus_free (signature);
-        goto out;
-      }
-      break;
-    }
-
-  ret = TRUE;
-
- out:
-
-  return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gboolean
-append_value_to_iter (DBusMessageIter              *iter,
-                      const gchar                  *signature,
-                      const GValue                 *value,
-                      GError                      **error)
-{
-  gboolean ret;
-
-  /* TODO: - fill in @error instead of using g_assert_not_reached()
-   *       - validate object paths and signatures (to shield app developers
-   *         from getting disconnected from the bus)
-   *       - perhaps access GValue directly (trading off safety for performance)
-   */
-
-  //g_debug ("_append_value_to_iter: signature=%s -> value=%s", signature, g_strdup_value_contents (value));
-
-  ret = FALSE;
-
-  /* TODO: we could probably speed this up by accessing the GValue directly */
-  switch (signature[0])
-    {
-    case DBUS_TYPE_STRING:
-      {
-        const char *val = g_value_get_string (value);
-        dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &val);
-      }
-      break;
-
-    case DBUS_TYPE_OBJECT_PATH:
-      {
-        const char *val = g_value_get_string (value); // TODO:o
-        dbus_message_iter_append_basic (iter, DBUS_TYPE_OBJECT_PATH, &val);
-      }
-      break;
-
-    case DBUS_TYPE_SIGNATURE:
-      {
-        const char *val = g_value_get_string (value); // TODO:g
-        dbus_message_iter_append_basic (iter, DBUS_TYPE_SIGNATURE, &val);
-      }
-      break;
-
-    case DBUS_TYPE_BYTE:
-      {
-        guchar val = g_value_get_uchar (value);
-        dbus_message_iter_append_basic (iter, DBUS_TYPE_BYTE, &val);
-      }
-      break;
-
-    case DBUS_TYPE_BOOLEAN:
-      {
-        dbus_bool_t val = g_value_get_boolean (value);
-        dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &val);
-      }
-      break;
-
-    case DBUS_TYPE_INT16:
-      {
-        dbus_int16_t val = g_value_get_int (value); // TODO:16
-        dbus_message_iter_append_basic (iter, DBUS_TYPE_INT16, &val);
-      }
-      break;
-
-    case DBUS_TYPE_UINT16:
-      {
-        dbus_uint16_t val = g_value_get_uint (value); // TODO:16
-        dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT16, &val);
-      }
-      break;
-
-    case DBUS_TYPE_INT32:
-      {
-        dbus_int32_t val = g_value_get_int (value);
-        dbus_message_iter_append_basic (iter, DBUS_TYPE_INT32, &val);
-      }
-      break;
-
-    case DBUS_TYPE_UINT32:
-      {
-        dbus_uint32_t val;
-        if (value->g_type == G_TYPE_UINT)
-          {
-            val = g_value_get_uint (value);
-          }
-        else if (G_TYPE_IS_ENUM (value->g_type))
-          {
-            val = g_value_get_enum (value);
-          }
-        else if (G_TYPE_IS_FLAGS (value->g_type))
-          {
-            val = g_value_get_flags (value);
-          }
-        dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT32, &val);
-      }
-      break;
-
-    case DBUS_TYPE_INT64:
-      {
-        dbus_int64_t val = g_value_get_int64 (value);
-        dbus_message_iter_append_basic (iter, DBUS_TYPE_INT64, &val);
-      }
-      break;
-
-    case DBUS_TYPE_UINT64:
-      {
-        dbus_uint64_t val = g_value_get_uint64 (value);
-        dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT64, &val);
-      }
-      break;
-
-    case DBUS_TYPE_DOUBLE:
-      {
-        double val = g_value_get_double (value);
-        dbus_message_iter_append_basic (iter, DBUS_TYPE_DOUBLE, &val);
-      }
-      break;
-
-    /* ---------------------------------------------------------------------------------------------------- */
-    case DBUS_TYPE_ARRAY:
-      if (signature[1] == DBUS_TYPE_BYTE   ||
-          signature[1] == DBUS_TYPE_INT16  ||
-          signature[1] == DBUS_TYPE_UINT16 ||
-          signature[1] == DBUS_TYPE_INT32  ||
-          signature[1] == DBUS_TYPE_UINT32 ||
-          signature[1] == DBUS_TYPE_INT64  ||
-          signature[1] == DBUS_TYPE_UINT64 ||
-          signature[1] == DBUS_TYPE_DOUBLE ||
-          signature[1] == DBUS_TYPE_BOOLEAN)
-        {
-          DBusMessageIter array_iter;
-          GArray *a;
-
-          a = (GArray *) g_value_get_boxed (value);
-
-          if (a != NULL && a->len > 0 && get_element_size (signature[1]) != g_array_get_element_size (a))
-            {
-              g_set_error (error,
-                           G_DBUS_ERROR,
-                           G_DBUS_ERROR_FAILED,
-                           "GArray has element size %d but element size %d was expected",
-                           get_element_size (signature[1]),
-                           g_array_get_element_size (a));
-              goto out;
-            }
-
-          dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, signature + 1, &array_iter);
-          dbus_message_iter_append_fixed_array (&array_iter, signature[1], &(a->data), a->len);
-          dbus_message_iter_close_container (iter, &array_iter);
-        }
-      else if (signature[1] == DBUS_TYPE_STRING ||
-               signature[1] == DBUS_TYPE_OBJECT_PATH ||
-               signature[1] == DBUS_TYPE_SIGNATURE)
-        {
-          DBusMessageIter array_iter;
-          gchar **strv;
-          guint n;
-
-          strv = (gchar **) g_value_get_boxed (value);
-          dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, signature + 1, &array_iter);
-          for (n = 0; strv[n] != NULL; n++)
-            dbus_message_iter_append_basic (&array_iter, signature[1], &(strv[n]));
-          dbus_message_iter_close_container (iter, &array_iter);
-        }
-      else if (signature[1] == DBUS_STRUCT_BEGIN_CHAR)
-        {
-          DBusMessageIter array_iter;
-          GPtrArray *p;
-          guint n;
-
-          p = g_value_get_boxed (value);
-          dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, signature + 1, &array_iter);
-          for (n = 0; n < p->len; n++)
-            {
-              GValue val = {0};
-              g_value_init (&val, G_TYPE_DBUS_STRUCTURE);
-              g_value_take_object (&val, G_DBUS_STRUCTURE (p->pdata[n]));
-              /* recursive dance */
-              if (!append_value_to_iter (&array_iter, signature + 1, &val, error))
-                goto out;
-            }
-          dbus_message_iter_close_container (iter, &array_iter);
-        }
-      else if (signature[1] == DBUS_DICT_ENTRY_BEGIN_CHAR)
-        {
-          DBusMessageIter array_iter;
-          GHashTable *hash_table;
-          GHashTableIter hash_iter;
-          gpointer hash_key;
-          gpointer hash_value;
-          char *value_signature;
-
-          value_signature = g_strdup (signature + 3);
-          value_signature[strlen (value_signature) - 1] = '\0';
-
-          hash_table = g_value_get_boxed (value);
-
-          //g_debug ("signature='%s' value_signature='%s'", signature, value_signature);
-
-          dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, signature + 1, &array_iter);
-          g_hash_table_iter_init (&hash_iter, hash_table);
-          while (g_hash_table_iter_next (&hash_iter, &hash_key, &hash_value))
-            {
-              GValue val = {0};
-              DBusMessageIter dict_iter;
-
-              dbus_message_iter_open_container (&array_iter,
-                                                DBUS_TYPE_DICT_ENTRY,
-                                                NULL,
-                                                &dict_iter);
-              switch (signature[2])
-                {
-                case DBUS_TYPE_STRING:
-                case DBUS_TYPE_OBJECT_PATH:
-                case DBUS_TYPE_SIGNATURE:
-                case DBUS_TYPE_BYTE:
-                case DBUS_TYPE_BOOLEAN:
-                case DBUS_TYPE_INT16:
-                case DBUS_TYPE_UINT16:
-                case DBUS_TYPE_INT32:
-                case DBUS_TYPE_UINT32:
-                  dbus_message_iter_append_basic (&dict_iter, signature[2], &hash_key);
-                  break;
-
-                case DBUS_TYPE_INT64:
-                case DBUS_TYPE_UINT64:
-                case DBUS_TYPE_DOUBLE:
-                  dbus_message_iter_append_basic (&dict_iter, signature[2], hash_key);
-                  break;
-
-                default:
-                  /* the D-Bus spec says the hash_key must be a basic type */
-                  g_assert_not_reached ();
-                  break;
-                }
-
-              //g_debug ("value_signature='%s'", value_signature);
-              switch (value_signature[0])
-                {
-                case DBUS_TYPE_STRING:
-                case DBUS_TYPE_OBJECT_PATH:
-                case DBUS_TYPE_SIGNATURE:
-                case DBUS_TYPE_BYTE:
-                case DBUS_TYPE_BOOLEAN:
-                case DBUS_TYPE_INT16:
-                case DBUS_TYPE_UINT16:
-                case DBUS_TYPE_INT32:
-                case DBUS_TYPE_UINT32:
-                  dbus_message_iter_append_basic (&dict_iter, signature[2], &hash_value);
-                  break;
-
-                case DBUS_TYPE_INT64:
-                case DBUS_TYPE_UINT64:
-                case DBUS_TYPE_DOUBLE:
-                  dbus_message_iter_append_basic (&dict_iter, signature[2], hash_value);
-                  break;
-
-                case DBUS_STRUCT_BEGIN_CHAR:
-                  g_value_init (&val, G_TYPE_DBUS_STRUCTURE);
-                  g_value_take_object (&val, G_DBUS_STRUCTURE (hash_value));
-                  /* recursive dance */
-                  if (!append_value_to_iter (&dict_iter, value_signature, &val, error))
-                    goto out;
-                  break;
-
-                case DBUS_TYPE_ARRAY:
-                  if (value_signature[1] == DBUS_TYPE_BYTE ||
-                      value_signature[1] == DBUS_TYPE_INT16 ||
-                      value_signature[1] == DBUS_TYPE_UINT16 ||
-                      value_signature[1] == DBUS_TYPE_INT32 ||
-                      value_signature[1] == DBUS_TYPE_UINT32 ||
-                      value_signature[1] == DBUS_TYPE_INT64 ||
-                      value_signature[1] == DBUS_TYPE_UINT64 ||
-                      value_signature[1] == DBUS_TYPE_BOOLEAN ||
-                      value_signature[1] == DBUS_TYPE_DOUBLE)
-                    {
-                      g_value_init (&val, G_TYPE_ARRAY);
-                      g_value_take_boxed (&val, hash_value);
-                      /* recurse */
-                      if (!append_value_to_iter (&dict_iter, value_signature, &val, error))
-                        goto out;
-                    }
-                  else if (value_signature[1] == DBUS_TYPE_STRING ||
-                           value_signature[1] == DBUS_TYPE_OBJECT_PATH ||
-                           value_signature[1] == DBUS_TYPE_SIGNATURE)
-                    {
-                      GType boxed_type;
-
-                      if (value_signature[1] == DBUS_TYPE_STRING)
-                        boxed_type = G_TYPE_STRV;
-                      else if (value_signature[1] == DBUS_TYPE_OBJECT_PATH)
-                        boxed_type = G_TYPE_STRV; // TODO:o EGG_DBUS_TYPE_OBJECT_PATH_ARRAY;
-                      else if (value_signature[1] == DBUS_TYPE_SIGNATURE)
-                        boxed_type = G_TYPE_STRV; // TODO:o EGG_DBUS_TYPE_SIGNATURE_ARRAY;
-                      else
-                        g_assert_not_reached ();
-
-                      g_value_init (&val, boxed_type);
-                      g_value_set_static_boxed (&val, hash_value);
-                      /* recurse */
-                      if (!append_value_to_iter (&dict_iter, value_signature, &val, error))
-                        goto out;
-                    }
-                  else if (value_signature[1] == DBUS_STRUCT_BEGIN_CHAR)
-                    {
-                      g_value_init (&val, G_TYPE_PTR_ARRAY);
-                      g_value_take_boxed (&val, hash_value);
-                      /* recurse */
-                      if (!append_value_to_iter (&dict_iter, value_signature, &val, error))
-                        goto out;
-                    }
-                  else if (value_signature[1] == DBUS_DICT_ENTRY_BEGIN_CHAR)
-                    {
-                      g_value_init (&val, G_TYPE_HASH_TABLE);
-                      g_value_take_boxed (&val, hash_value);
-                      /* recurse */
-                      if (!append_value_to_iter (&dict_iter, value_signature, &val, error))
-                        goto out;
-                    }
-                  else if (value_signature[1] == DBUS_TYPE_VARIANT)
-                    {
-                      g_value_init (&val, G_TYPE_PTR_ARRAY);
-                      g_value_take_boxed (&val, hash_value);
-                      /* recurse */
-                      if (!append_value_to_iter (&dict_iter, value_signature, &val, error))
-                        goto out;
-                    }
-                  else if (value_signature[1] == DBUS_TYPE_ARRAY)
-                    {
-                      g_value_init (&val, G_TYPE_PTR_ARRAY);
-                      g_value_take_boxed (&val, hash_value);
-                      /* recurse */
-                      if (!append_value_to_iter (&dict_iter, value_signature, &val, error))
-                        goto out;
-                    }
-                  else
-                    {
-                      g_assert_not_reached ();
-                    }
-                  break;
-
-                case DBUS_TYPE_VARIANT:
-                  g_value_init (&val, G_TYPE_DBUS_VARIANT);
-                  g_value_take_object (&val, hash_value);
-                  /* recurse */
-                  if (!append_value_to_iter (&dict_iter, value_signature, &val, error))
-                    goto out;
-                  break;
-
-                default:
-                  g_assert_not_reached ();
-                  break;
-                }
-
-              dbus_message_iter_close_container (&array_iter, &dict_iter);
-            }
-          dbus_message_iter_close_container (iter, &array_iter);
-
-          g_free (value_signature);
-        }
-      else if (signature[1] == DBUS_TYPE_ARRAY) /* array of an array */
-        {
-          DBusMessageIter array_iter;
-          GPtrArray *p;
-          guint n;
-
-          p = g_value_get_boxed (value);
-          dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, signature + 1, &array_iter);
-          for (n = 0; n < p->len; n++)
-            {
-              GValue val = {0};
-
-              g_value_init (&val, _g_dbus_signature_get_gtype (signature + 1));
-
-              /* this can either be boxed (for GStrv, GArray) or an object (for e.g. structs, variants) */
-              if (g_type_is_a (G_VALUE_TYPE (&val), G_TYPE_BOXED))
-                g_value_take_boxed (&val, p->pdata[n]);
-              else if (g_type_is_a (G_VALUE_TYPE (&val), G_TYPE_OBJECT))
-                g_value_take_object (&val, p->pdata[n]);
-              else
-                g_assert_not_reached ();
-
-              /* recursive dance */
-              if (!append_value_to_iter (&array_iter, signature + 1, &val, error))
-                goto out;
-            }
-
-          dbus_message_iter_close_container (iter, &array_iter);
-        }
-      else if (signature[1] == DBUS_TYPE_VARIANT ) /* array of variants */
-        {
-          DBusMessageIter array_iter;
-          GPtrArray *p;
-          guint n;
-
-          p = g_value_get_boxed (value);
-          dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, signature + 1, &array_iter);
-          for (n = 0; n < p->len; n++)
-            {
-              GValue val = {0};
-
-              g_value_init (&val, G_TYPE_DBUS_VARIANT);
-              g_value_take_object (&val, p->pdata[n]);
-
-              /* recursive dance */
-              if (!append_value_to_iter (&array_iter, signature + 1, &val, error))
-                goto out;
-            }
-
-          dbus_message_iter_close_container (iter, &array_iter);
-        }
-      else
-        {
-          g_warning ("Don't know append an array with elements with with signature %s", signature + 1);
-          g_assert_not_reached ();
-        }
-      break;
-
-    /* ---------------------------------------------------------------------------------------------------- */
-    case DBUS_STRUCT_BEGIN_CHAR:
-      {
-        DBusMessageIter struct_iter;
-        GDBusStructure *structure;
-        guint n;
-        guint num_elems;
-
-        structure = G_DBUS_STRUCTURE (g_value_get_object (value));
-
-        num_elems = g_dbus_structure_get_num_elements (structure);
-
-        dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, &struct_iter);
-        for (n = 0; n < num_elems; n++)
-          {
-            const GValue *val;
-            const gchar *sig_for_elem;
-
-            val = _g_dbus_structure_get_gvalue_for_element (structure, n);
-            sig_for_elem = g_dbus_structure_get_signature_for_element (structure, n);
-            /* recurse */
-            if (!append_value_to_iter (&struct_iter, sig_for_elem, val, error))
-              goto out;
-          }
-        dbus_message_iter_close_container (iter, &struct_iter);
-      }
-      break;
-
-    /* ---------------------------------------------------------------------------------------------------- */
-    case DBUS_TYPE_VARIANT:
-      {
-        GDBusVariant *variant;
-        DBusMessageIter variant_iter;
-        const gchar *variant_signature;
-        GValue val = {0};
-
-        g_value_init (&val, G_TYPE_DBUS_VARIANT);
-        variant = g_value_get_object (value);
-
-        variant_signature = g_dbus_variant_get_variant_signature (variant);
-
-        dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, variant_signature, &variant_iter);
-        /* recurse */
-        if (!append_value_to_iter (&variant_iter,
-                                   variant_signature,
-                                   _g_dbus_variant_get_gvalue (variant),
-                                   error))
-          goto out;
-        dbus_message_iter_close_container (iter, &variant_iter);
-      }
-      break;
-
-    default:
-      g_warning ("Don't know append a value with signature %s", signature);
-      g_assert_not_reached ();
-      break;
-    }
-
-  ret = TRUE;
-
- out:
-  return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
 static gboolean
 extract_values_cb (guint        arg_num,
                    const gchar *signature,
@@ -2294,7 +973,7 @@ extract_values_cb (guint        arg_num,
   //g_debug ("arg %d: %s", arg_num, g_type_name (type));
 
   error = NULL;
-  if (!get_value_from_iter (iter, &value, &error))
+  if (!g_dbus_c_type_mapping_get_value_from_iter (iter, &value, &error))
     {
       g_warning ("Error extracting value for arg %d: %s",
                  arg_num,
@@ -2398,7 +1077,7 @@ append_values_cb (guint        arg_num,
     }
 
   error = NULL;
-  if (!append_value_to_iter (iter, signature, value_to_append, &error))
+  if (!g_dbus_c_type_mapping_append_value_to_iter (iter, signature, value_to_append, &error))
     {
       g_warning ("Error appending value for arg %d: %s",
                  arg_num,
diff --git a/gdbus/gdbusvariant.c b/gdbus/gdbusvariant.c
index 278a63e..b6c20ac 100644
--- a/gdbus/gdbusvariant.c
+++ b/gdbus/gdbusvariant.c
@@ -554,6 +554,23 @@ g_dbus_variant_new_for_structure (GDBusStructure *structure)
   return variant;
 }
 
+/**
+ * g_dbus_variant_new_for_structure:
+ * @variant: A #GDBusVariant.
+ *
+ * Creates a new variant that holds a reference to @variant.
+ *
+ * Returns: A new #GDBusVariant. Free with g_object_unref().
+ **/
+GDBusVariant *
+g_dbus_variant_new_for_variant (GDBusVariant *variant)
+{
+  GDBusVariant *_variant;
+  _variant = g_dbus_variant_new ();
+  g_dbus_variant_set_variant (_variant, variant);
+  return _variant;
+}
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 /**
@@ -927,6 +944,25 @@ g_dbus_variant_set_structure (GDBusVariant   *variant,
   set_signature (variant, g_dbus_structure_get_signature (structure));
 }
 
+/**
+ * g_dbus_variant_set_structure:
+ * @variant: A #GDBusVariant.
+ * @other_variant: A #GDBusVariant.
+ *
+ * Makes @variant hold a reference to @other_variant.
+ **/
+void
+g_dbus_variant_set_variant (GDBusVariant   *variant,
+                            GDBusVariant   *other_variant)
+{
+  g_return_if_fail (G_IS_DBUS_VARIANT (variant));
+  if (variant->priv->signature != NULL)
+    g_value_unset (&variant->priv->value);
+  g_value_init (&variant->priv->value, G_TYPE_DBUS_VARIANT);
+  g_value_set_object (&variant->priv->value, other_variant);
+  set_signature (variant, "v");
+}
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 /**
@@ -1214,6 +1250,21 @@ g_dbus_variant_get_structure (GDBusVariant *variant)
   return g_value_get_object (&variant->priv->value);
 }
 
+/**
+ * g_dbus_variant_get_variant:
+ * @variant: A #GDBusVariant.
+ *
+ * Gets the variant stored in @variant.
+ *
+ * Returns: A #GDBusVariant owned by @variant. Do not free.
+ **/
+GDBusVariant *
+g_dbus_variant_get_variant (GDBusVariant *variant)
+{
+  g_return_val_if_fail (G_IS_DBUS_VARIANT (variant) && g_dbus_variant_is_variant (variant), NULL);
+  return g_value_get_object (&variant->priv->value);
+}
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 /**
@@ -1569,6 +1620,23 @@ g_dbus_variant_is_structure (GDBusVariant *variant)
     variant->priv->signature[0] == '(';
 }
 
+/**
+ * g_dbus_variant_is_variant:
+ * @variant: A #GDBusVariant.
+ *
+ * Checks if @variant holds a variant.
+ *
+ * Returns: %TRUE only if @variant holds a structure.
+ **/
+gboolean
+g_dbus_variant_is_variant (GDBusVariant *variant)
+{
+  g_return_val_if_fail (G_IS_DBUS_VARIANT (variant), FALSE);
+  return
+    variant->priv->signature != NULL &&
+    variant->priv->signature[0] == 'v';
+}
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 #define __G_DBUS_VARIANT_C__
diff --git a/gdbus/gdbusvariant.h b/gdbus/gdbusvariant.h
index 0637d51..ea104b2 100644
--- a/gdbus/gdbusvariant.h
+++ b/gdbus/gdbusvariant.h
@@ -107,6 +107,7 @@ GDBusVariant    *g_dbus_variant_new_for_hash_table        (GHashTable      *hash
                                                            const gchar     *key_signature,
                                                            const gchar     *value_signature);
 GDBusVariant    *g_dbus_variant_new_for_structure         (GDBusStructure  *structure);
+GDBusVariant    *g_dbus_variant_new_for_variant           (GDBusVariant    *variant);
 
 /* getters */
 const gchar     *g_dbus_variant_get_string            (GDBusVariant   *variant);
@@ -128,6 +129,7 @@ GArray          *g_dbus_variant_get_array             (GDBusVariant   *variant);
 GPtrArray       *g_dbus_variant_get_ptr_array         (GDBusVariant   *variant);
 GHashTable      *g_dbus_variant_get_hash_table        (GDBusVariant   *variant);
 GDBusStructure  *g_dbus_variant_get_structure         (GDBusVariant   *variant);
+GDBusVariant    *g_dbus_variant_get_variant           (GDBusVariant   *variant);
 
 /* setters */
 void             g_dbus_variant_set_string            (GDBusVariant   *variant,
@@ -172,6 +174,8 @@ void             g_dbus_variant_set_hash_table        (GDBusVariant   *variant,
                                                        const gchar    *value_signature);
 void             g_dbus_variant_set_structure         (GDBusVariant   *variant,
                                                        GDBusStructure *structure);
+void             g_dbus_variant_set_variant           (GDBusVariant   *variant,
+                                                       GDBusVariant   *other_variant);
 
 /* identification */
 gboolean         g_dbus_variant_is_unset              (GDBusVariant     *variant);
@@ -194,6 +198,7 @@ gboolean         g_dbus_variant_is_array              (GDBusVariant     *variant
 gboolean         g_dbus_variant_is_ptr_array          (GDBusVariant     *variant);
 gboolean         g_dbus_variant_is_hash_table         (GDBusVariant     *variant);
 gboolean         g_dbus_variant_is_structure          (GDBusVariant     *variant);
+gboolean         g_dbus_variant_is_variant            (GDBusVariant     *variant);
 
 G_END_DECLS
 
diff --git a/gdbus/tests/connection.c b/gdbus/tests/connection.c
index 966bfff..1d8ab48 100644
--- a/gdbus/tests/connection.c
+++ b/gdbus/tests/connection.c
@@ -363,15 +363,16 @@ test_connection_signals (void)
   GDBusConnection *c3;
   guint s1;
   guint s2;
+  guint s3;
   gint count_s1;
   gint count_s2;
+  gint count_name_owner_changed;
   DBusMessage *m;
 
   /**
-   * Bring up three separate connections
+   * Bring up first separate connections
    */
   session_bus_up ();
-
   /* if running with dbus-monitor, it claims the name :1.0 - so if we don't run with the monitor
    * emulate this
    */
@@ -388,16 +389,6 @@ test_connection_signals (void)
   g_assert (g_dbus_connection_get_is_open (c1));
   g_assert (g_dbus_connection_get_is_initialized (c1));
   g_assert_cmpstr (g_dbus_connection_get_unique_name (c1), ==, ":1.1");
-  c2 = g_dbus_connection_bus_get_private (G_BUS_TYPE_SESSION);
-  _g_assert_signal_received (c2, "opened");
-  g_assert (g_dbus_connection_get_is_open (c2));
-  g_assert (g_dbus_connection_get_is_initialized (c2));
-  g_assert_cmpstr (g_dbus_connection_get_unique_name (c2), ==, ":1.2");
-  c3 = g_dbus_connection_bus_get_private (G_BUS_TYPE_SESSION);
-  _g_assert_signal_received (c3, "opened");
-  g_assert (g_dbus_connection_get_is_open (c3));
-  g_assert (g_dbus_connection_get_is_initialized (c3));
-  g_assert_cmpstr (g_dbus_connection_get_unique_name (c3), ==, ":1.3");
 
   /**
    * Install two signal handlers for the first connection
@@ -405,39 +396,65 @@ test_connection_signals (void)
    *  - Listen to the signal "Foo" from :1.2 (e.g. c2)
    *  - Listen to the signal "Foo" from anyone (e.g. both c2 and c3)
    *
-   * and the conut how many times this signal handler was invoked.
+   * and then count how many times this signal handler was invoked.
    */
   s1 = g_dbus_connection_dbus_1_signal_subscribe (c1,
                                                   ":1.2",
-                                                  NULL,
+                                                  "org.gtk.GDBus.ExampleInterface",
                                                   "Foo",
-                                                  NULL,
+                                                  "/org/gtk/GDBus/ExampleInterface",
                                                   NULL,
                                                   test_connection_signal_handler,
-                                                  &count_s1);
+                                                  &count_s1,
+                                                  NULL);
   s2 = g_dbus_connection_dbus_1_signal_subscribe (c1,
-                                                  NULL,
-                                                  NULL,
+                                                  NULL, /* match any sender */
+                                                  "org.gtk.GDBus.ExampleInterface",
                                                   "Foo",
+                                                  "/org/gtk/GDBus/ExampleInterface",
                                                   NULL,
+                                                  test_connection_signal_handler,
+                                                  &count_s2,
+                                                  NULL);
+  s3 = g_dbus_connection_dbus_1_signal_subscribe (c1,
+                                                  "org.freedesktop.DBus",  /* sender */
+                                                  "org.freedesktop.DBus",  /* interface */
+                                                  "NameOwnerChanged",      /* member */
+                                                  "/org/freedesktop/DBus", /* path */
                                                   NULL,
                                                   test_connection_signal_handler,
-                                                  &count_s2);
+                                                  &count_name_owner_changed,
+                                                  NULL);
+  g_assert (s1 != 0);
   g_assert (s2 != 0);
+  g_assert (s3 != 0);
 
   count_s1 = 0;
   count_s2 = 0;
+  count_name_owner_changed = 0;
+
+  /**
+   * Bring up two other connections
+   */
+  c2 = g_dbus_connection_bus_get_private (G_BUS_TYPE_SESSION);
+  _g_assert_signal_received (c2, "opened");
+  g_assert (g_dbus_connection_get_is_open (c2));
+  g_assert (g_dbus_connection_get_is_initialized (c2));
+  g_assert_cmpstr (g_dbus_connection_get_unique_name (c2), ==, ":1.2");
+  c3 = g_dbus_connection_bus_get_private (G_BUS_TYPE_SESSION);
+  _g_assert_signal_received (c3, "opened");
+  g_assert (g_dbus_connection_get_is_open (c3));
+  g_assert (g_dbus_connection_get_is_initialized (c3));
+  g_assert_cmpstr (g_dbus_connection_get_unique_name (c3), ==, ":1.3");
 
-  m = dbus_message_new_signal ("/",
+  /* prepare a signal message */
+  m = dbus_message_new_signal ("/org/gtk/GDBus/ExampleInterface",
                                "org.gtk.GDBus.ExampleInterface",
                                "Foo");
 
   /**
    * Make c2 emit "Foo" - we should catch it twice
    */
-  m = dbus_message_new_signal ("/",
-                               "org.gtk.GDBus.ExampleInterface",
-                               "Foo");
   g_dbus_connection_send_dbus_1_message (c2, m);
   while (!(count_s1 == 1 && count_s2 == 1))
     g_main_loop_run (loop);
@@ -454,19 +471,77 @@ test_connection_signals (void)
   g_assert_cmpint (count_s2, ==, 2);
 
   /**
-   * Tool around it the mainloop to avoid race conditions
+   * Tool around in the mainloop to avoid race conditions and also to check the
+   * total amount of NameOwnerChanged signals
    */
   g_timeout_add (500, test_connection_signal_quit_mainloop, NULL);
   g_main_loop_run (loop);
   g_assert_cmpint (count_s1, ==, 1);
   g_assert_cmpint (count_s2, ==, 2);
+  g_assert_cmpint (count_name_owner_changed, ==, 2);
+
+  /**
+   * Now bring down the session bus and wait for all three connections to close.
+   * Then bring the bus back up and wait for all connections to open.
+   *
+   * Then check that _only_ the rules not matching on sender still works. This tests that we only
+   * readd match rules only when the sender is not specified.
+   */
+  session_bus_down ();
+  g_dbus_connection_set_exit_on_close (c1, FALSE);
+  g_dbus_connection_set_exit_on_close (c2, FALSE);
+  g_dbus_connection_set_exit_on_close (c3, FALSE);
+  if (g_dbus_connection_get_is_open (c1))
+    _g_assert_signal_received (c1, "closed");
+  if (g_dbus_connection_get_is_open (c2))
+    _g_assert_signal_received (c2, "closed");
+  if (g_dbus_connection_get_is_open (c3))
+    _g_assert_signal_received (c3, "closed");
+  session_bus_up ();
+  if (!g_dbus_connection_get_is_open (c1))
+    _g_assert_signal_received (c1, "opened");
+  if (!g_dbus_connection_get_is_open (c2))
+    _g_assert_signal_received (c2, "opened");
+  if (!g_dbus_connection_get_is_open (c3))
+    _g_assert_signal_received (c3, "opened");
+  /* Make c2 emit "Foo" - now we should catch it only once */
+  count_s1 = 0;
+  count_s2 = 0;
+  g_dbus_connection_send_dbus_1_message (c2, m);
+  while (!(count_s1 == 0 && count_s2 == 1))
+    g_main_loop_run (loop);
+  g_assert_cmpint (count_s1, ==, 0);
+  g_assert_cmpint (count_s2, ==, 1);
+  /* Make c3 emit "Foo" - now we should catch it only once */
+  g_dbus_connection_send_dbus_1_message (c3, m);
+  while (!(count_s1 == 0 && count_s2 == 2))
+    g_main_loop_run (loop);
+  g_assert_cmpint (count_s1, ==, 0);
+  g_assert_cmpint (count_s2, ==, 2);
+  /* Tool around in the mainloop to avoid race conditions
+   */
+  g_timeout_add (500, test_connection_signal_quit_mainloop, NULL);
+  g_main_loop_run (loop);
+  g_assert_cmpint (count_s1, ==, 0);
+  g_assert_cmpint (count_s2, ==, 2);
+  /**
+   * Now bring down both c2 and c3, sleep for a while, and check that count_name_owner_changed is
+   * at least 4 (depending on inherent races (c1 may reconnect before or after c2 and c3 etc.) it may
+   * be larger than 4)
+   *
+   * This demonstrates that the NameOwnerChanged rule was readded when c1 got back online.
+   */
+  g_object_unref (c2);
+  g_object_unref (c3);
+  g_timeout_add (500, test_connection_signal_quit_mainloop, NULL);
+  g_main_loop_run (loop);
+  g_assert_cmpint (count_name_owner_changed, >=, 4);
 
   dbus_message_unref (m);
   g_dbus_connection_dbus_1_signal_unsubscribe (c1, s1);
   g_dbus_connection_dbus_1_signal_unsubscribe (c1, s2);
+  g_dbus_connection_dbus_1_signal_unsubscribe (c1, s3);
   g_object_unref (c1);
-  g_object_unref (c2);
-  g_object_unref (c3);
   session_bus_down ();
 }
 
diff --git a/gdbus/tests/proxy.c b/gdbus/tests/proxy.c
index 7b12f8b..c0453ab 100644
--- a/gdbus/tests/proxy.c
+++ b/gdbus/tests/proxy.c
@@ -1072,21 +1072,27 @@ static void
 test_proxy_signals_on_signal (GDBusProxy  *proxy,
                               const gchar *signal_name,
                               const gchar *signature,
-                              GValueArray *args,
+                              GPtrArray   *args,
                               gpointer     user_data)
 {
   GString *s = user_data;
+  GDBusVariant *variant2;
 
-  g_assert_cmpstr (signature, ==, "so");
-  g_assert_cmpint (args->n_values, ==, 2);
-  g_assert (G_VALUE_TYPE (&args->values[0]) == G_TYPE_STRING);
-  g_assert (G_VALUE_TYPE (&args->values[1]) == G_TYPE_STRING);
+  g_assert_cmpstr (signature, ==, "sov");
+  g_assert_cmpint (args->len, ==, 3);
+  g_assert (g_dbus_variant_is_string (G_DBUS_VARIANT (args->pdata[0])));
+  g_assert (g_dbus_variant_is_object_path (G_DBUS_VARIANT (args->pdata[1])));
+  g_assert (g_dbus_variant_is_variant (G_DBUS_VARIANT (args->pdata[2])));
 
   g_string_append (s, signal_name);
   g_string_append_c (s, ':');
-  g_string_append (s, g_value_get_string (&args->values[0]));
+  g_string_append (s, g_dbus_variant_get_string (G_DBUS_VARIANT (args->pdata[0])));
+  g_string_append_c (s, ',');
+  g_string_append (s, g_dbus_variant_get_object_path (G_DBUS_VARIANT (args->pdata[1])));
   g_string_append_c (s, ',');
-  g_string_append (s, g_value_get_string (&args->values[1]));
+  variant2 = g_dbus_variant_get_variant (G_DBUS_VARIANT (args->pdata[2]));
+  g_assert (g_dbus_variant_is_string (variant2));
+  g_string_append (s, g_dbus_variant_get_string (variant2));
 }
 
 static void
@@ -1133,9 +1139,8 @@ test_proxy_signals (void)
                     "g-dbus-proxy-signal",
                     G_CALLBACK (test_proxy_signals_on_signal),
                     s);
-  ret = g_dbus_proxy_invoke_method_sync (frob, "EmitSignal", "sso", "",
+  ret = g_dbus_proxy_invoke_method_sync (frob, "EmitSignal", "so", "",
                                          -1, NULL, &error,
-                                         G_TYPE_STRING, "SomeSignal",
                                          G_TYPE_STRING, "Accept the next proposition you hear",
                                          G_TYPE_STRING, "/some/path",
                                          G_TYPE_INVALID,
@@ -1143,7 +1148,7 @@ test_proxy_signals (void)
   g_assert_no_error (error);
   g_assert (ret);
   _g_assert_signal_received (frob, "g-dbus-proxy-signal");
-  g_assert_cmpstr (s->str, ==, "SomeSignal:Accept the next proposition you hear .. in bed!,/some/path/in/bed");
+  g_assert_cmpstr (s->str, ==, "TestSignal:Accept the next proposition you hear .. in bed!,/some/path/in/bed,a variant");
 
   /**
    * Make the service quit, bring it back up and then try again (with the same proxy).
@@ -1162,9 +1167,8 @@ test_proxy_signals (void)
   g_assert_cmpstr (g_dbus_proxy_get_name_owner (frob), !=, NULL);
   /* again */
   g_string_set_size (s, 0);
-  ret = g_dbus_proxy_invoke_method_sync (frob, "EmitSignal", "sso", "",
+  ret = g_dbus_proxy_invoke_method_sync (frob, "EmitSignal", "so", "",
                                          -1, NULL, &error,
-                                         G_TYPE_STRING, "OtherSignal",
                                          G_TYPE_STRING, "Your present plans are going to succeed",
                                          G_TYPE_STRING, "/another/path",
                                          G_TYPE_INVALID,
@@ -1172,7 +1176,7 @@ test_proxy_signals (void)
   g_assert_no_error (error);
   g_assert (ret);
   _g_assert_signal_received (frob, "g-dbus-proxy-signal");
-  g_assert_cmpstr (s->str, ==, "OtherSignal:Your present plans are going to succeed .. in bed!,/another/path/in/bed");
+  g_assert_cmpstr (s->str, ==, "TestSignal:Your present plans are going to succeed .. in bed!,/another/path/in/bed,a variant");
   g_signal_handlers_disconnect_by_func (frob, test_proxy_signals_on_signal, s);
   g_string_free (s, TRUE);
 
diff --git a/gdbus/tests/testserver.py b/gdbus/tests/testserver.py
index 78b66b4..2f447a7 100755
--- a/gdbus/tests/testserver.py
+++ b/gdbus/tests/testserver.py
@@ -179,15 +179,15 @@ class TestService(dbus.service.Object):
         session_bus.send_message(message)
     # ----------------------------------------------------------------------------------------------------
 
+    @dbus.service.signal("com.example.Frob",
+                         signature="sov")
+    def TestSignal(self, str1, objpath1, variant1):
+        pass
+
     @dbus.service.method("com.example.Frob",
-                          in_signature='sso', out_signature='')
-    def EmitSignal(self, signal_name, str1, objpath1):
-        message = dbus.lowlevel.SignalMessage("/com/example/TestObject",
-                                              "com.example.Frob",
-                                              signal_name)
-        message.append(str1 + " .. in bed!")
-        message.append(dbus.ObjectPath (objpath1 + "/in/bed"))
-        session_bus.send_message(message)
+                          in_signature='so', out_signature='')
+    def EmitSignal(self, str1, objpath1):
+        self.TestSignal (str1 + " .. in bed!", objpath1 + "/in/bed", "a variant")
 
     # ----------------------------------------------------------------------------------------------------
 



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