[glib/gdbus] Add g_dbus_connection_signal_subscribe()
- From: David Zeuthen <davidz src gnome org>
- To: svn-commits-list gnome org
- Subject: [glib/gdbus] Add g_dbus_connection_signal_subscribe()
- Date: Thu, 30 Apr 2009 20:51:48 -0400 (EDT)
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]