From 4538f9bd8af110a3ab5596077877188bb2444fc7 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Mon, 21 Oct 2013 13:54:57 +0100 Subject: [PATCH 10/11] Add GVariant-based async method replies --- dbus/dbus-glib.h | 2 + dbus/dbus-gobject.c | 89 +++++++++++++++++++++++++++++++++++++++++ test/core/my-object.c | 12 ++++++ test/core/not-quite-gdbus.c | 2 +- test/core/test-service-glib.xml | 8 +++- 5 files changed, 111 insertions(+), 2 deletions(-) diff --git a/dbus/dbus-glib.h b/dbus/dbus-glib.h index dbdff5a..1674244 100644 --- a/dbus/dbus-glib.h +++ b/dbus/dbus-glib.h @@ -348,6 +348,8 @@ const char* dbus_g_proxy_get_interface (DBusGProxy *proxy); typedef struct _DBusGMethodInvocation DBusGMethodInvocation; void dbus_g_method_return (DBusGMethodInvocation *context, ...); +void dbus_g_method_return_variants (DBusGMethodInvocation *context, + GVariant *tuple); void dbus_g_method_return_error (DBusGMethodInvocation *context, const GError *error); diff --git a/dbus/dbus-gobject.c b/dbus/dbus-gobject.c index 9889836..56727e2 100644 --- a/dbus/dbus-gobject.c +++ b/dbus/dbus-gobject.c @@ -3,6 +3,7 @@ * * Copyright (C) 2003, 2004, 2005 Red Hat, Inc. * Copyright (C) 2005 Nokia + * Copyright (C) 2013 Collabora Ltd. * * Licensed under the Academic Free License version 2.1 * @@ -3246,6 +3247,94 @@ out: } /** + * dbus_g_method_return_variants: + * @context: the method context + * @tuple: (allow-none): parameters for the reply, which must match + * the #DBusGObjectInfo. If floating, ownership will be taken. + * %NULL is treated as equivalent to an empty tuple. + * + * Send a return message for a given method invocation, with arguments. + * This function also frees the sending context. + * + * The @tuple parameter encapsulates 0 or more return values: for + * instance, a method that returns nothing would pass () or %NULL, + * a method that returns one uint32 might pass (uint32 4,) + * and a method that returns three strings might pass + * ("a", "b", "c"). + */ +void +dbus_g_method_return_variants (DBusGMethodInvocation *context, + GVariant *tuple) +{ + DBusMessage *reply; + gchar *out_sig = NULL; + GError *error = NULL; + + g_return_if_fail (context != NULL); + + out_sig = method_output_signature_from_object_info (context->object, context->method); + + if (tuple == NULL) + { + /* only valid if the method doesn't return anything */ + g_return_if_fail (out_sig[0] == '\0'); + } + else + { + const GVariantType *type; + const gchar *tuple_sig; + gsize tuple_sig_len; + + g_variant_ref_sink (tuple); + + type = g_variant_get_type (tuple); + tuple_sig_len = g_variant_type_get_string_length (type); + tuple_sig = g_variant_type_peek_string (type); + + g_return_if_fail (g_variant_type_is_tuple (type)); + /* In a high-level language, this would say: + * tuple_sig == "(" + out_sig + ")" */ + g_return_if_fail (tuple_sig[0] == '('); + g_return_if_fail (tuple_sig_len == strlen (out_sig) + 2); + g_return_if_fail (memcmp (out_sig, tuple_sig + 1, tuple_sig_len - 2) == 0); + g_return_if_fail (tuple_sig[tuple_sig_len - 1] == ')'); + } + + /* This field was initialized inside invoke_object_method; we + * carry it over through the async invocation to here. + */ + if (!context->send_reply) + goto out; + + reply = dbus_g_method_get_reply (context); + + if (tuple == NULL || + dbus_g_message_write_variants (reply, tuple, &error)) + { + connection_send_or_die ( + dbus_g_connection_get_connection (context->connection), + reply); + } + else + { + /* programming error: probably something unsupportable in a variant */ + g_critical ("%s", error->message); + g_error_free (error); + } + + dbus_message_unref (reply); + +out: + g_free (out_sig); + dbus_g_connection_unref (context->connection); + dbus_g_message_unref (context->message); + g_free (context); + + if (tuple != NULL) + g_variant_unref (tuple); +} + +/** * dbus_g_method_return_error: * @context: the method context * @error: the error to send diff --git a/test/core/my-object.c b/test/core/my-object.c index 5ebf8f4..8442927 100644 --- a/test/core/my-object.c +++ b/test/core/my-object.c @@ -5,6 +5,9 @@ #include "my-object.h" #include "my-object-marshal.h" +static void my_object_async_increment_gvariant (MyObject *obj, + guint32 x, + DBusGMethodInvocation *context); #include "test-service-glib-glue.h" void @@ -845,6 +848,15 @@ my_object_async_increment (MyObject *obj, gint32 x, DBusGMethodInvocation *conte g_idle_add ((GSourceFunc)do_async_increment, data); } +static void +my_object_async_increment_gvariant (MyObject *obj, + guint32 x, + DBusGMethodInvocation *context) +{ + dbus_g_method_return_variants (context, + g_variant_new_parsed ("(%u,)", x + 1)); +} + typedef struct { GError *error; DBusGMethodInvocation *context; diff --git a/test/core/not-quite-gdbus.c b/test/core/not-quite-gdbus.c index 2f0f3df..e9e1bf3 100644 --- a/test/core/not-quite-gdbus.c +++ b/test/core/not-quite-gdbus.c @@ -155,7 +155,7 @@ test_success (Fixture *f, /* called for its reply */ dbus_g_connection_call_async (f->bus, f->unique_name, "/foo", IFACE, - "Increment", + "AsyncIncrementGVariant", g_variant_new_parsed ("(uint32 256,)"), G_VARIANT_TYPE ("(u)"), G_DBUS_CALL_FLAGS_NONE, diff --git a/test/core/test-service-glib.xml b/test/core/test-service-glib.xml index 8058fe6..ca8f9e9 100644 --- a/test/core/test-service-glib.xml +++ b/test/core/test-service-glib.xml @@ -125,7 +125,13 @@ - + + + + + + + -- 1.8.4.rc3