[glib/gdbus-codegen] GDBus: Add test-suite for new ObjectManager and gdbus-codegen(1) code
- From: David Zeuthen <davidz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/gdbus-codegen] GDBus: Add test-suite for new ObjectManager and gdbus-codegen(1) code
- Date: Mon, 11 Apr 2011 14:55:59 +0000 (UTC)
commit 9c1941c07fba7626ba1a40a7009615c88a645539
Author: David Zeuthen <davidz redhat com>
Date: Mon Apr 11 10:54:52 2011 -0400
GDBus: Add test-suite for new ObjectManager and gdbus-codegen(1) code
Signed-off-by: David Zeuthen <davidz redhat com>
gio/tests/Makefile.am | 24 +
gio/tests/gdbus-test-codegen.c | 2178 ++++++++++++++++++++++++++++++++++++++++
gio/tests/test-codegen.xml | 341 +++++++
3 files changed, 2543 insertions(+), 0 deletions(-)
---
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 46b0efa..e17858b 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -62,6 +62,7 @@ TEST_PROGS += \
gdbus-exit-on-close \
gdbus-non-socket \
gdbus-bz627724 \
+ gdbus-test-codegen \
appinfo \
contenttype \
file \
@@ -236,6 +237,27 @@ gdbus_addresses_LDADD = $(progs_ldadd)
gdbus_bz627724_SOURCES = gdbus-bz627724.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
gdbus_bz627724_LDADD = $(progs_ldadd)
+gdbus-test-codegen-generated.h gdbus-test-codegen-generated.c : test-codegen.xml
+ $(PYTHON) $(top_srcdir)/gio/gdbus-codegen/codegen_main.py \
+ --c-namespace Foo \
+ --interface-prefix org.project. \
+ --generate-c-code gdbus-test-codegen-generated \
+ --generate-docbook gdbus-test-codegen-generated-doc \
+ --annotate "org.project.Bar" Key1 Value1 \
+ --annotate "org.project.Bar" org.gtk.GDBus.Internal Value2 \
+ --annotate "org.project.Bar.HelloWorld()" Key3 Value3 \
+ --annotate "org.project.Bar::TestSignal" Key4 Value4 \
+ --annotate "org.project.Bar:ay" Key5 Value5 \
+ --annotate "org.project.Bar.TestPrimitiveTypes()[val_int32]" Key6 Value6 \
+ --annotate "org.project.Bar.TestPrimitiveTypes()[ret_uint32]" Key7 Value7 \
+ --annotate "org.project.Bar::TestSignal[array_of_strings]" Key8 Value8 \
+ test-codegen.xml \
+ $(NULL)
+
+gdbus_test_codegen_SOURCES = gdbus-test-codegen.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
+gdbus_test_codegen_SOURCES += gdbus-test-codegen-generated.c gdbus-test-codegen-generated.h
+gdbus_test_codegen_LDADD = $(progs_ldadd)
+
gdbus_connection_SOURCES = gdbus-connection.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
gdbus_connection_LDADD = $(progs_ldadd)
@@ -433,6 +455,8 @@ test.mo: de.po
$(MKDIR_P) de/LC_MESSAGES; \
cp -f test.mo de/LC_MESSAGES
+CLEANFILES = gdbus-test-codegen-generated.[ch] gdbus-test-codegen-generated-doc-*.xml
+
DISTCLEANFILES = \
applications/mimeinfo.cache \
org.gtk.test.enums.xml \
diff --git a/gio/tests/gdbus-test-codegen.c b/gio/tests/gdbus-test-codegen.c
new file mode 100644
index 0000000..b70bd42
--- /dev/null
+++ b/gio/tests/gdbus-test-codegen.c
@@ -0,0 +1,2178 @@
+/* GLib testing framework examples and tests
+ *
+ * Copyright (C) 2008-2011 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 <gio/gio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gdbus-tests.h"
+
+#include "gdbus-test-codegen-generated.h"
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static guint
+count_annotations (GDBusAnnotationInfo **annotations)
+{
+ guint ret;
+ ret = 0;
+ while (annotations != NULL && annotations[ret] != NULL)
+ ret++;
+ return ret;
+}
+
+/* checks that
+ *
+ * - non-internal annotations are written out correctly; and
+ * - injection via --annotation --key --value works
+ */
+static void
+test_annotations (void)
+{
+ GDBusInterfaceInfo *iface;
+ GDBusMethodInfo *method;
+ GDBusSignalInfo *signal;
+ GDBusPropertyInfo *property;
+
+ iface = foo_bar_interface_info ();
+ g_assert (iface != NULL);
+
+ /* see Makefile.am for where these annotations are injected */
+ g_assert_cmpint (count_annotations (iface->annotations), ==, 1);
+ g_assert_cmpstr (g_dbus_annotation_info_lookup (iface->annotations, "Key1"), ==, "Value1");
+
+ method = g_dbus_interface_info_lookup_method (iface, "HelloWorld");
+ g_assert (method != NULL);
+ g_assert_cmpint (count_annotations (method->annotations), ==, 2);
+ g_assert_cmpstr (g_dbus_annotation_info_lookup (method->annotations, "ExistingAnnotation"), ==, "blah");
+ g_assert_cmpstr (g_dbus_annotation_info_lookup (method->annotations, "Key3"), ==, "Value3");
+
+ signal = g_dbus_interface_info_lookup_signal (iface, "TestSignal");
+ g_assert (signal != NULL);
+ g_assert_cmpint (count_annotations (signal->annotations), ==, 1);
+ g_assert_cmpstr (g_dbus_annotation_info_lookup (signal->annotations, "Key4"), ==, "Value4");
+ g_assert_cmpstr (g_dbus_annotation_info_lookup (signal->args[1]->annotations, "Key8"), ==, "Value8");
+
+ property = g_dbus_interface_info_lookup_property (iface, "ay");
+ g_assert (property != NULL);
+ g_assert_cmpint (count_annotations (property->annotations), ==, 1);
+ g_assert_cmpstr (g_dbus_annotation_info_lookup (property->annotations, "Key5"), ==, "Value5");
+
+ method = g_dbus_interface_info_lookup_method (iface, "TestPrimitiveTypes");
+ g_assert (method != NULL);
+ g_assert_cmpstr (g_dbus_annotation_info_lookup (method->in_args[4]->annotations, "Key6"), ==, "Value6");
+ g_assert_cmpstr (g_dbus_annotation_info_lookup (method->out_args[5]->annotations, "Key7"), ==, "Value7");
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+on_handle_hello_world (FooBar *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *greeting,
+ gpointer user_data)
+{
+ gchar *response;
+ response = g_strdup_printf ("Word! You said `%s'. I'm Stub, btw!", greeting);
+ foo_bar_complete_hello_world (object, invocation, response);
+ g_free (response);
+ return TRUE;
+}
+
+static gboolean
+on_handle_test_primitive_types (FooBar *object,
+ GDBusMethodInvocation *invocation,
+ guchar val_byte,
+ gboolean val_boolean,
+ gint16 val_int16,
+ guint16 val_uint16,
+ gint val_int32,
+ guint val_uint32,
+ gint64 val_int64,
+ guint64 val_uint64,
+ gdouble val_double,
+ const gchar *val_string,
+ const gchar *val_objpath,
+ const gchar *val_signature,
+ const gchar *val_bytestring,
+ gpointer user_data)
+{
+ gchar *s1;
+ gchar *s2;
+ gchar *s3;
+ s1 = g_strdup_printf ("Word! You said `%s'. Rock'n'roll!", val_string);
+ s2 = g_strdup_printf ("/modified%s", val_objpath);
+ s3 = g_strdup_printf ("assgit%s", val_signature);
+ foo_bar_complete_test_primitive_types (object,
+ invocation,
+ 10 + val_byte,
+ !val_boolean,
+ 100 + val_int16,
+ 1000 + val_uint16,
+ 10000 + val_int32,
+ 100000 + val_uint32,
+ 1000000 + val_int64,
+ 10000000 + val_uint64,
+ val_double / G_PI,
+ s1,
+ s2,
+ s3,
+ "bytestring!\xff");
+ g_free (s1);
+ g_free (s2);
+ g_free (s3);
+ return TRUE;
+}
+
+static gboolean
+on_handle_test_non_primitive_types (FooBar *object,
+ GDBusMethodInvocation *invocation,
+ GVariant *dict_s_to_s,
+ GVariant *dict_s_to_pairs,
+ GVariant *a_struct,
+ const gchar* const *array_of_strings,
+ GVariant *array_of_objpaths,
+ GVariant *array_of_signatures,
+ const gchar* const *array_of_bytestrings,
+ gpointer user_data)
+{
+ gchar *s;
+ GString *str;
+ str = g_string_new (NULL);
+ s = g_variant_print (dict_s_to_s, TRUE); g_string_append (str, s); g_free (s);
+ s = g_variant_print (dict_s_to_pairs, TRUE); g_string_append (str, s); g_free (s);
+ s = g_variant_print (a_struct, TRUE); g_string_append (str, s); g_free (s);
+ s = g_strjoinv (", ", (gchar **) array_of_strings);
+ g_string_append_printf (str, "array_of_strings: [%s] ", s);
+ g_free (s);
+ s = g_variant_print (array_of_objpaths, TRUE);
+ g_string_append_printf (str, "array_of_objpaths: %s ", s);
+ g_free (s);
+ s = g_variant_print (array_of_objpaths, TRUE);
+ g_string_append_printf (str, "array_of_signatures: %s ", s);
+ g_free (s);
+ s = g_strjoinv (", ", (gchar **) array_of_bytestrings);
+ g_string_append_printf (str, "array_of_bytestrings: [%s] ", s);
+ g_free (s);
+ foo_bar_complete_test_non_primitive_types (object, invocation, str->str);
+ g_string_free (str, TRUE);
+ return TRUE;
+}
+
+static gboolean
+on_handle_request_signal_emission (FooBar *object,
+ GDBusMethodInvocation *invocation,
+ gint which_one,
+ gpointer user_data)
+{
+ if (which_one == 0)
+ {
+ const gchar *a_strv[] = {"foo", "bar", NULL};
+ const gchar *a_bytestring_array[] = {"foo\xff", "bar\xff", NULL};
+ GVariant *a_variant = g_variant_new_parsed ("{'first': (42, 42), 'second': (43, 43)}");
+ foo_bar_emit_test_signal (object, 43, a_strv, a_bytestring_array, a_variant); /* consumes a_variant */
+ foo_bar_complete_request_signal_emission (object, invocation);
+ }
+ return TRUE;
+}
+
+static gboolean
+on_handle_request_multi_property_mods (FooBar *object,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ foo_bar_set_y (object, foo_bar_get_y (object) + 1);
+ foo_bar_set_i (object, foo_bar_get_i (object) + 1);
+ foo_bar_set_y (object, foo_bar_get_y (object) + 1);
+ foo_bar_set_i (object, foo_bar_get_i (object) + 1);
+ g_dbus_interface_stub_flush (G_DBUS_INTERFACE_STUB (object));
+ foo_bar_set_y (object, foo_bar_get_y (object) + 1);
+ foo_bar_set_i (object, foo_bar_get_i (object) + 1);
+ foo_bar_complete_request_multi_property_mods (object, invocation);
+ return TRUE;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+on_handle_force_method (FooBat *object,
+ GDBusMethodInvocation *invocation,
+ GVariant *force_in_i,
+ GVariant *force_in_s,
+ GVariant *force_in_ay,
+ GVariant *force_in_struct,
+ gpointer user_data)
+{
+ GVariant *ret_i;
+ GVariant *ret_s;
+ GVariant *ret_ay;
+ GVariant *ret_struct;
+ gint32 val;
+ gchar *s;
+
+ ret_i = g_variant_new_int32 (g_variant_get_int32 (force_in_i) + 10);
+ s = g_strdup_printf ("%s_foo", g_variant_get_string (force_in_s, NULL));
+ ret_s = g_variant_new_string (s);
+ g_free (s);
+ s = g_strdup_printf ("%s_foo\xff", g_variant_get_bytestring (force_in_ay));
+ ret_ay = g_variant_new_bytestring (s);
+ g_free (s);
+
+ g_variant_get (force_in_struct, "(i)", &val);
+ ret_struct = g_variant_new ("(i)", val + 10);
+
+ g_variant_ref_sink (ret_i);
+ g_variant_ref_sink (ret_s);
+ g_variant_ref_sink (ret_ay);
+ g_variant_ref_sink (ret_struct);
+
+ foo_bat_emit_force_signal (object,
+ ret_i,
+ ret_s,
+ ret_ay,
+ ret_struct);
+
+ foo_bat_complete_force_method (object,
+ invocation,
+ ret_i,
+ ret_s,
+ ret_ay,
+ ret_struct);
+
+ g_variant_unref (ret_i);
+ g_variant_unref (ret_s);
+ g_variant_unref (ret_ay);
+ g_variant_unref (ret_struct);
+
+ return TRUE;
+}
+
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+my_g_authorize_method_handler (GDBusInterfaceStub *interface,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ const gchar *method_name;
+ gboolean authorized;
+
+ authorized = FALSE;
+
+ method_name = g_dbus_method_invocation_get_method_name (invocation);
+ if (g_strcmp0 (method_name, "CheckNotAuthorized") == 0)
+ {
+ authorized = FALSE;
+ }
+ else if (g_strcmp0 (method_name, "CheckAuthorized") == 0)
+ {
+ authorized = TRUE;
+ }
+ else if (g_strcmp0 (method_name, "CheckNotAuthorizedFromObject") == 0)
+ {
+ authorized = TRUE;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+
+ if (!authorized)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_IO_ERROR,
+ G_IO_ERROR_PERMISSION_DENIED,
+ "not authorized...");
+ }
+ return authorized;
+}
+
+static gboolean
+my_object_authorize_method_handler (GDBusObjectStub *object,
+ GDBusInterfaceStub *interface,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ const gchar *method_name;
+ gboolean authorized;
+
+ authorized = FALSE;
+
+ method_name = g_dbus_method_invocation_get_method_name (invocation);
+ if (g_strcmp0 (method_name, "CheckNotAuthorized") == 0)
+ {
+ authorized = TRUE;
+ }
+ else if (g_strcmp0 (method_name, "CheckAuthorized") == 0)
+ {
+ authorized = TRUE;
+ }
+ else if (g_strcmp0 (method_name, "CheckNotAuthorizedFromObject") == 0)
+ {
+ authorized = FALSE;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+
+ if (!authorized)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_IO_ERROR,
+ G_IO_ERROR_PENDING,
+ "not authorized (from object)...");
+ }
+ return authorized;
+}
+
+static gboolean
+on_handle_check_not_authorized (FooAuthorize *object,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ foo_authorize_complete_check_not_authorized (object, invocation);
+ return TRUE;
+}
+
+static gboolean
+on_handle_check_authorized (FooAuthorize *object,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ foo_authorize_complete_check_authorized (object, invocation);
+ return TRUE;
+}
+
+static gboolean
+on_handle_check_not_authorized_from_object (FooAuthorize *object,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ foo_authorize_complete_check_not_authorized_from_object (object, invocation);
+ return TRUE;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+on_handle_get_self (FooMethodThreads *object,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ gchar *s;
+ s = g_strdup_printf ("%p", g_thread_self ());
+ foo_method_threads_complete_get_self (object, invocation, s);
+ g_free (s);
+ return TRUE;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GThread *method_handler_thread = NULL;
+
+static FooBar *exported_bar_object = NULL;
+static FooBat *exported_bat_object = NULL;
+static FooAuthorize *exported_authorize_object = NULL;
+static GDBusObjectStub *authorize_enclosing_object = NULL;
+static FooMethodThreads *exported_thread_object_1 = NULL;
+static FooMethodThreads *exported_thread_object_2 = NULL;
+
+static void
+on_bus_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ GError *error;
+
+ /* Test that we can export an object using the generated
+ * FooBarStub subclass. Notes:
+ *
+ * 1. We handle methods by simply connecting to the appropriate
+ * GObject signal.
+ *
+ * 2. Property storage is taken care of by the class; we can
+ * use g_object_get()/g_object_set() (and the generated
+ * C bindings at will)
+ */
+ error = NULL;
+ exported_bar_object = foo_bar_stub_new ();
+ foo_bar_set_ay (exported_bar_object, "ABCabc");
+ foo_bar_set_y (exported_bar_object, 42);
+ foo_bar_set_d (exported_bar_object, 43.0);
+ foo_bar_set_finally_normal_name (exported_bar_object, "There aint no place like home");
+ foo_bar_set_writeonly_property (exported_bar_object, "Mr. Burns");
+
+ /* The following works because it's on the Stub object - it will
+ * fail (at run-time) on a Proxy (see on_proxy_appeared() below)
+ */
+ foo_bar_set_readonly_property (exported_bar_object, "blah");
+ g_assert_cmpstr (foo_bar_get_writeonly_property (exported_bar_object), ==, "Mr. Burns");
+
+ g_dbus_interface_stub_export (G_DBUS_INTERFACE_STUB (exported_bar_object),
+ connection,
+ "/bar",
+ &error);
+ g_assert_no_error (error);
+ g_signal_connect (exported_bar_object,
+ "handle-hello-world",
+ G_CALLBACK (on_handle_hello_world),
+ NULL);
+ g_signal_connect (exported_bar_object,
+ "handle-test-primitive-types",
+ G_CALLBACK (on_handle_test_primitive_types),
+ NULL);
+ g_signal_connect (exported_bar_object,
+ "handle-test-non-primitive-types",
+ G_CALLBACK (on_handle_test_non_primitive_types),
+ NULL);
+ g_signal_connect (exported_bar_object,
+ "handle-request-signal-emission",
+ G_CALLBACK (on_handle_request_signal_emission),
+ NULL);
+ g_signal_connect (exported_bar_object,
+ "handle-request-multi-property-mods",
+ G_CALLBACK (on_handle_request_multi_property_mods),
+ NULL);
+
+ exported_bat_object = foo_bat_stub_new ();
+ g_dbus_interface_stub_export (G_DBUS_INTERFACE_STUB (exported_bat_object),
+ connection,
+ "/bat",
+ &error);
+ g_assert_no_error (error);
+ g_signal_connect (exported_bat_object,
+ "handle-force-method",
+ G_CALLBACK (on_handle_force_method),
+ NULL);
+ g_object_set (exported_bat_object,
+ "force-i", g_variant_new_int32 (43),
+ "force-s", g_variant_new_string ("prop string"),
+ "force-ay", g_variant_new_bytestring ("prop bytestring\xff"),
+ "force-struct", g_variant_new ("(i)", 4300),
+ NULL);
+
+ authorize_enclosing_object = g_dbus_object_stub_new ("/authorize");
+ g_signal_connect (authorize_enclosing_object,
+ "authorize-method",
+ G_CALLBACK (my_object_authorize_method_handler),
+ NULL);
+ exported_authorize_object = foo_authorize_stub_new ();
+ g_dbus_object_stub_add_interface (authorize_enclosing_object,
+ G_DBUS_INTERFACE_STUB (exported_authorize_object));
+ g_dbus_interface_stub_export (G_DBUS_INTERFACE_STUB (exported_authorize_object),
+ connection,
+ "/authorize",
+ &error);
+ g_assert_no_error (error);
+ g_signal_connect (exported_authorize_object,
+ "g-authorize-method",
+ G_CALLBACK (my_g_authorize_method_handler),
+ NULL);
+ g_signal_connect (exported_authorize_object,
+ "handle-check-not-authorized",
+ G_CALLBACK (on_handle_check_not_authorized),
+ NULL);
+ g_signal_connect (exported_authorize_object,
+ "handle-check-authorized",
+ G_CALLBACK (on_handle_check_authorized),
+ NULL);
+ g_signal_connect (exported_authorize_object,
+ "handle-check-not-authorized-from-object",
+ G_CALLBACK (on_handle_check_not_authorized_from_object),
+ NULL);
+
+
+ /* only object 1 has the G_DBUS_INTERFACE_STUB_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD flag set */
+ exported_thread_object_1 = foo_method_threads_stub_new ();
+ g_dbus_interface_stub_set_flags (G_DBUS_INTERFACE_STUB (exported_thread_object_1),
+ G_DBUS_INTERFACE_STUB_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
+ g_dbus_interface_stub_export (G_DBUS_INTERFACE_STUB (exported_thread_object_1),
+ connection,
+ "/method_threads_1",
+ &error);
+ g_assert_no_error (error);
+ g_signal_connect (exported_thread_object_1,
+ "handle-get-self",
+ G_CALLBACK (on_handle_get_self),
+ NULL);
+
+ exported_thread_object_2 = foo_method_threads_stub_new ();
+ g_dbus_interface_stub_export (G_DBUS_INTERFACE_STUB (exported_thread_object_2),
+ connection,
+ "/method_threads_2",
+ &error);
+ g_assert_no_error (error);
+ g_signal_connect (exported_thread_object_2,
+ "handle-get-self",
+ G_CALLBACK (on_handle_get_self),
+ NULL);
+
+ method_handler_thread = g_thread_self ();
+}
+
+static gpointer check_proxies_in_thread (gpointer user_data);
+
+static void
+on_name_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ GMainLoop *loop = user_data;
+
+ g_thread_create (check_proxies_in_thread,
+ loop,
+ TRUE,
+ NULL);
+}
+
+static void
+on_name_lost (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ g_assert_not_reached ();
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+ GMainLoop *thread_loop;
+ gint initial_y;
+ gint initial_i;
+ guint num_g_properties_changed;
+ gboolean received_test_signal;
+ guint num_notify_u;
+ guint num_notify_n;
+} ClientData;
+
+static void
+on_notify_u (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ ClientData *data = user_data;
+ g_assert_cmpstr (pspec->name, ==, "u");
+ data->num_notify_u += 1;
+}
+
+static void
+on_notify_n (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ ClientData *data = user_data;
+ g_assert_cmpstr (pspec->name, ==, "n");
+ data->num_notify_n += 1;
+}
+
+static void
+on_g_properties_changed (GDBusProxy *_proxy,
+ GVariant *changed_properties,
+ const gchar* const *invalidated_properties,
+ gpointer user_data)
+{
+ ClientData *data = user_data;
+ FooBar *proxy = FOO_BAR (_proxy);
+
+ g_assert_cmpint (g_variant_n_children (changed_properties), ==, 2);
+
+ if (data->num_g_properties_changed == 0)
+ {
+ g_assert_cmpint (data->initial_y, ==, foo_bar_get_y (proxy) - 2);
+ g_assert_cmpint (data->initial_i, ==, foo_bar_get_i (proxy) - 2);
+ }
+ else if (data->num_g_properties_changed == 1)
+ {
+ g_assert_cmpint (data->initial_y, ==, foo_bar_get_y (proxy) - 3);
+ g_assert_cmpint (data->initial_i, ==, foo_bar_get_i (proxy) - 3);
+ }
+ else
+ g_assert_not_reached ();
+
+ data->num_g_properties_changed++;
+
+ if (data->num_g_properties_changed == 2)
+ g_main_loop_quit (data->thread_loop);
+}
+
+static void
+on_test_signal (FooBar *proxy,
+ gint val_int32,
+ const gchar* const *array_of_strings,
+ const gchar* const *array_of_bytestrings,
+ GVariant *dict_s_to_pairs,
+ gpointer user_data)
+{
+ ClientData *data = user_data;
+
+ g_assert_cmpint (val_int32, ==, 43);
+ g_assert_cmpstr (array_of_strings[0], ==, "foo");
+ g_assert_cmpstr (array_of_strings[1], ==, "bar");
+ g_assert (array_of_strings[2] == NULL);
+ g_assert_cmpstr (array_of_bytestrings[0], ==, "foo\xff");
+ g_assert_cmpstr (array_of_bytestrings[1], ==, "bar\xff");
+ g_assert (array_of_bytestrings[2] == NULL);
+
+ data->received_test_signal = TRUE;
+ g_main_loop_quit (data->thread_loop);
+}
+
+static void
+check_bar_proxy (FooBar *proxy,
+ GMainLoop *thread_loop)
+{
+ guchar ret_val_byte;
+ gboolean ret_val_boolean;
+ gint16 ret_val_int16;
+ guint16 ret_val_uint16;
+ gint ret_val_int32;
+ guint ret_val_uint32;
+ gint64 ret_val_int64;
+ guint64 ret_val_uint64;
+ gdouble ret_val_double;
+ gchar *ret_val_string;
+ gchar *ret_val_objpath;
+ gchar *ret_val_signature;
+ gchar *ret_val_bytestring;
+ gboolean ret;
+ GError *error;
+ ClientData *data;
+ guchar val_y;
+ gboolean val_b;
+ gint16 val_n;
+ guint16 val_q;
+ gint val_i;
+ guint val_u;
+ gint64 val_x;
+ guint64 val_t;
+ gdouble val_d;
+ gchar *val_s;
+ gchar *val_o;
+ gchar *val_g;
+ gchar *val_ay;
+ gchar **val_as;
+ GVariant *val_ao;
+ GVariant *val_ag;
+ gint32 val_unset_i;
+ gdouble val_unset_d;
+ gchar *val_unset_s;
+ gchar *val_unset_o;
+ gchar *val_unset_g;
+ gchar *val_unset_ay;
+ gchar **val_unset_as;
+ GVariant *val_unset_ao;
+ GVariant *val_unset_ag;
+ GVariant *val_unset_struct;
+ gchar *val_finally_normal_name;
+ GVariant *v;
+ gchar *s;
+
+ data = g_new0 (ClientData, 1);
+ data->thread_loop = thread_loop;
+
+ v = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), "y");
+ g_assert (v != NULL);
+ g_variant_unref (v);
+
+ /* set empty values to non-empty */
+ val_unset_i = 42;
+ val_unset_d = 42.0;
+ val_unset_s = "42";
+ val_unset_o = "42";
+ val_unset_g = "42";
+ val_unset_ay = NULL;
+ val_unset_as = NULL;
+ val_unset_ao = NULL;
+ val_unset_ag = NULL;
+ val_unset_struct = NULL;
+ /* check properties */
+ g_object_get (proxy,
+ "y", &val_y,
+ "b", &val_b,
+ "n", &val_n,
+ "q", &val_q,
+ "i", &val_i,
+ "u", &val_u,
+ "x", &val_x,
+ "t", &val_t,
+ "d", &val_d,
+ "s", &val_s,
+ "o", &val_o,
+ "g", &val_g,
+ "ay", &val_ay,
+ "as", &val_as,
+ "ao", &val_ao,
+ "ag", &val_ag,
+ "unset_i", &val_unset_i,
+ "unset_d", &val_unset_d,
+ "unset_s", &val_unset_s,
+ "unset_o", &val_unset_o,
+ "unset_g", &val_unset_g,
+ "unset_ay", &val_unset_ay,
+ "unset_as", &val_unset_as,
+ "unset_ao", &val_unset_ao,
+ "unset_ag", &val_unset_ag,
+ "unset_struct", &val_unset_struct,
+ "finally-normal-name", &val_finally_normal_name,
+ NULL);
+ g_assert_cmpint (val_y, ==, 42);
+ g_assert_cmpstr (val_finally_normal_name, ==, "There aint no place like home");
+ g_free (val_s);
+ g_free (val_o);
+ g_free (val_g);
+ g_assert_cmpstr (val_ay, ==, "ABCabc");
+ g_free (val_ay);
+ g_strfreev (val_as);
+ g_variant_unref (val_ao);
+ g_variant_unref (val_ag);
+ g_free (val_finally_normal_name);
+ /* check empty values */
+ g_assert_cmpint (val_unset_i, ==, 0);
+ g_assert_cmpfloat (val_unset_d, ==, 0.0);
+ g_assert_cmpstr (val_unset_s, ==, "");
+ g_assert_cmpstr (val_unset_o, ==, "/");
+ g_assert_cmpstr (val_unset_g, ==, "");
+ g_free (val_unset_s);
+ g_free (val_unset_o);
+ g_free (val_unset_g);
+ g_assert_cmpstr (val_unset_ay, ==, "");
+ g_assert (val_unset_as[0] == NULL);
+ g_assert (g_variant_is_of_type (val_unset_ao, G_VARIANT_TYPE ("ao")));
+ g_assert (g_variant_is_of_type (val_unset_ag, G_VARIANT_TYPE ("ag")));
+ g_assert (g_variant_is_of_type (val_unset_struct, G_VARIANT_TYPE ("(idsogayasaoag)")));
+ s = g_variant_print (val_unset_struct, TRUE);
+ g_assert_cmpstr (s, ==, "(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])");
+ g_free (s);
+ g_free (val_unset_ay);
+ g_strfreev (val_unset_as);
+ g_variant_unref (val_unset_ao);
+ g_variant_unref (val_unset_ag);
+ g_variant_unref (val_unset_struct);
+
+ /* Try setting a property. This causes the generated glue to invoke
+ * the org.fd.DBus.Properties.Set() method asynchronously. So we
+ * have to wait for properties-changed...
+ */
+ foo_bar_set_finally_normal_name (proxy, "foo!");
+ _g_assert_property_notify (proxy, "finally-normal-name");
+ g_assert_cmpstr (foo_bar_get_finally_normal_name (proxy), ==, "foo!");
+
+ /* Try setting properties that requires memory management. This
+ * is to exercise the paths that frees the references.
+ */
+ const gchar *array_of_strings[3] = {"one", "two", NULL};
+ const gchar *array_of_bytestrings[3] = {"one\xff", "two\xff", NULL};
+ g_object_set (proxy,
+ "s", "a string",
+ "o", "/a/path",
+ "g", "asig",
+ "ay", g_variant_new_parsed ("[byte 0x65, 0x67]"),
+ "as", array_of_strings,
+ "ao", g_variant_new_parsed ("[ o '/one', '/one/two']"),
+ "ag", g_variant_new_parsed ("[ g 'ass', 'git']"),
+ NULL);
+
+ error = NULL;
+ ret = foo_bar_call_test_primitive_types_sync (proxy,
+ 10,
+ TRUE,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ "a string",
+ "/a/path",
+ "asig",
+ "bytestring\xff",
+ &ret_val_byte,
+ &ret_val_boolean,
+ &ret_val_int16,
+ &ret_val_uint16,
+ &ret_val_int32,
+ &ret_val_uint32,
+ &ret_val_int64,
+ &ret_val_uint64,
+ &ret_val_double,
+ &ret_val_string,
+ &ret_val_objpath,
+ &ret_val_signature,
+ &ret_val_bytestring,
+ NULL, /* GCancellable */
+ &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ error = NULL;
+ ret = foo_bar_call_test_non_primitive_types_sync (proxy,
+ g_variant_new_parsed ("{'one': 'red',"
+ " 'two': 'blue'}"),
+ g_variant_new_parsed ("{'first': (42, 42), "
+ "'second': (43, 43)}"),
+ g_variant_new_parsed ("(42, 'foo', 'bar')"),
+ array_of_strings,
+ g_variant_new_parsed ("[ o '/one', '/one/two']"),
+ g_variant_new_parsed ("[ g 'ass', 'git']"),
+ array_of_bytestrings,
+ &s,
+ NULL, /* GCancellable */
+ &error);
+
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ /* Check that org.freedesktop.DBus.Error.UnknownMethod is returned on
+ * unimplemented methods.
+ */
+ error = NULL;
+ ret = foo_bar_call_unimplemented_method_sync (proxy, NULL /* GCancellable */, &error);
+ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
+ g_error_free (error);
+ error = NULL;
+ g_assert (!ret);
+
+ g_signal_connect (proxy,
+ "test-signal",
+ G_CALLBACK (on_test_signal),
+ data);
+ error = NULL;
+ ret = foo_bar_call_request_signal_emission_sync (proxy, 0, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ g_assert (!data->received_test_signal);
+ g_main_loop_run (thread_loop);
+ g_assert (data->received_test_signal);
+
+ /* Try setting a property. This causes the generated glue to invoke
+ * the org.fd.DBus.Properties.Set() method asynchronously. So we
+ * have to wait for properties-changed...
+ */
+ foo_bar_set_finally_normal_name (proxy, "hey back!");
+ _g_assert_property_notify (proxy, "finally-normal-name");
+ g_assert_cmpstr (foo_bar_get_finally_normal_name (proxy), ==, "hey back!");
+
+ /* Check that grouping changes in idle works.
+ *
+ * See on_handle_request_multi_property_mods(). The server should
+ * emit exactly two PropertiesChanged signals each containing two
+ * properties.
+ *
+ * On the first reception, y and i should both be increased by
+ * two. On the the second reception, only by one. The signal handler
+ * checks this.
+ *
+ * This also checks that _drain_notify() works.
+ */
+ data->initial_y = foo_bar_get_y (proxy);
+ data->initial_i = foo_bar_get_i (proxy);
+ g_signal_connect (proxy,
+ "g-properties-changed",
+ G_CALLBACK (on_g_properties_changed),
+ data);
+ error = NULL;
+ ret = foo_bar_call_request_multi_property_mods_sync (proxy, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_main_loop_run (thread_loop);
+ g_assert_cmpint (data->num_g_properties_changed, ==, 2);
+ g_signal_handlers_disconnect_by_func (proxy,
+ G_CALLBACK (on_g_properties_changed),
+ data);
+
+ /* Check that we don't emit PropertiesChanged() if the property
+ * didn't change... we actually get two notifies.. one for the
+ * local set (without a value change) and one when receiving
+ * the PropertiesChanged() signal generated from the remote end.
+ */
+ g_assert_cmpint (data->num_notify_u, ==, 0);
+ g_signal_connect (proxy,
+ "notify::u",
+ G_CALLBACK (on_notify_u),
+ data);
+ foo_bar_set_u (proxy, 1042);
+ g_assert_cmpint (data->num_notify_u, ==, 1);
+ g_assert_cmpint (foo_bar_get_u (proxy), ==, 0);
+ _g_assert_property_notify (proxy, "u");
+ g_assert_cmpint (foo_bar_get_u (proxy), ==, 1042);
+ g_assert_cmpint (data->num_notify_u, ==, 2);
+
+ /* Now change u again to the same value.. this will cause a
+ * local notify:: notify and the usual Properties.Set() call
+ *
+ * (Btw, why also the Set() call if the value in the cache is
+ * the same? Because someone else might have changed it
+ * in the mean time and we're just waiting to receive the
+ * PropertiesChanged() signal...)
+ *
+ * More tricky - how do we check for the *absence* of the
+ * notification that u changed? Simple: we change another
+ * property and wait for that PropertiesChanged() message
+ * to arrive.
+ */
+ foo_bar_set_u (proxy, 1042);
+ g_assert_cmpint (data->num_notify_u, ==, 3);
+
+ g_assert_cmpint (data->num_notify_n, ==, 0);
+ g_signal_connect (proxy,
+ "notify::n",
+ G_CALLBACK (on_notify_n),
+ data);
+ foo_bar_set_n (proxy, 10042);
+ g_assert_cmpint (data->num_notify_n, ==, 1);
+ g_assert_cmpint (foo_bar_get_n (proxy), ==, 0);
+ _g_assert_property_notify (proxy, "n");
+ g_assert_cmpint (foo_bar_get_n (proxy), ==, 10042);
+ g_assert_cmpint (data->num_notify_n, ==, 2);
+
+ /* Checks that u didn't change at all */
+ g_assert_cmpint (data->num_notify_u, ==, 3);
+
+ /* cleanup */
+ g_free (data);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_force_signal (FooBat *proxy,
+ GVariant *force_i,
+ GVariant *force_s,
+ GVariant *force_ay,
+ GVariant *force_struct,
+ gpointer user_data)
+{
+ gboolean *signal_received = user_data;
+ gint val;
+
+ g_assert (!(*signal_received));
+
+ g_assert_cmpint (g_variant_get_int32 (force_i), ==, 42 + 10);
+ g_assert_cmpstr (g_variant_get_string (force_s, NULL), ==, "a string_foo");
+ g_assert_cmpstr (g_variant_get_bytestring (force_ay), ==, "a bytestring\xff_foo\xff");
+ g_variant_get (force_struct, "(i)", &val);
+ g_assert_cmpint (val, ==, 4200 + 10);
+
+ *signal_received = TRUE;
+}
+
+static void
+check_bat_proxy (FooBat *proxy,
+ GMainLoop *thread_loop)
+{
+ GError *error;
+ GVariant *ret_i;
+ GVariant *ret_s;
+ GVariant *ret_ay;
+ GVariant *ret_struct;
+ gint val;
+ gboolean force_signal_received;
+
+ /* --------------------------------------------------- */
+ /* Check type-mapping where we force use of a GVariant */
+ /* --------------------------------------------------- */
+
+ /* check properties */
+ g_object_get (proxy,
+ "force-i", &ret_i,
+ "force-s", &ret_s,
+ "force-ay", &ret_ay,
+ "force-struct", &ret_struct,
+ NULL);
+ g_assert_cmpint (g_variant_get_int32 (ret_i), ==, 43);
+ g_assert_cmpstr (g_variant_get_string (ret_s, NULL), ==, "prop string");
+ g_assert_cmpstr (g_variant_get_bytestring (ret_ay), ==, "prop bytestring\xff");
+ g_variant_get (ret_struct, "(i)", &val);
+ g_assert_cmpint (val, ==, 4300);
+ g_variant_unref (ret_i);
+ g_variant_unref (ret_s);
+ g_variant_unref (ret_ay);
+ g_variant_unref (ret_struct);
+
+ /* check method and signal */
+ force_signal_received = FALSE;
+ g_signal_connect (proxy,
+ "force-signal",
+ G_CALLBACK (on_force_signal),
+ &force_signal_received);
+
+ error = NULL;
+ foo_bat_call_force_method_sync (proxy,
+ g_variant_new_int32 (42),
+ g_variant_new_string ("a string"),
+ g_variant_new_bytestring ("a bytestring\xff"),
+ g_variant_new ("(i)", 4200),
+ &ret_i,
+ &ret_s,
+ &ret_ay,
+ &ret_struct,
+ NULL, /* GCancellable* */
+ &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (g_variant_get_int32 (ret_i), ==, 42 + 10);
+ g_assert_cmpstr (g_variant_get_string (ret_s, NULL), ==, "a string_foo");
+ g_assert_cmpstr (g_variant_get_bytestring (ret_ay), ==, "a bytestring\xff_foo\xff");
+ g_variant_get (ret_struct, "(i)", &val);
+ g_assert_cmpint (val, ==, 4200 + 10);
+ g_variant_unref (ret_i);
+ g_variant_unref (ret_s);
+ g_variant_unref (ret_ay);
+ g_variant_unref (ret_struct);
+ _g_assert_signal_received (proxy, "force-signal");
+ g_assert (force_signal_received);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+check_authorize_proxy (FooAuthorize *proxy,
+ GMainLoop *thread_loop)
+{
+ GError *error;
+ gboolean ret;
+
+ /* Check that g-authorize-method works as intended */
+
+ error = NULL;
+ ret = foo_authorize_call_check_not_authorized_sync (proxy, NULL, &error);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
+ g_error_free (error);
+ g_assert (!ret);
+
+ error = NULL;
+ ret = foo_authorize_call_check_authorized_sync (proxy, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ error = NULL;
+ ret = foo_authorize_call_check_not_authorized_from_object_sync (proxy, NULL, &error);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
+ g_error_free (error);
+ g_assert (!ret);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GThread *
+get_self_via_proxy (FooMethodThreads *proxy_1)
+{
+ GError *error;
+ gchar *self_str;
+ gboolean ret;
+ gpointer self;
+
+ error = NULL;
+ ret = foo_method_threads_call_get_self_sync (proxy_1, &self_str, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ g_assert_cmpint (sscanf (self_str, "%p", &self), ==, 1);
+
+ g_free (self_str);
+
+ return self;
+}
+
+static void
+check_thread_proxies (FooMethodThreads *proxy_1,
+ FooMethodThreads *proxy_2,
+ GMainLoop *thread_loop)
+{
+ /* proxy_1 is indeed using threads so should never get the handler thread */
+ g_assert (get_self_via_proxy (proxy_1) != method_handler_thread);
+
+ /* proxy_2 is not using threads so should get the handler thread */
+ g_assert (get_self_via_proxy (proxy_2) == method_handler_thread);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gpointer
+check_proxies_in_thread (gpointer user_data)
+{
+ GMainLoop *loop = user_data;
+ GMainContext *thread_context;
+ GMainLoop *thread_loop;
+ GError *error;
+ FooBar *bar_proxy;
+ FooBat *bat_proxy;
+ FooAuthorize *authorize_proxy;
+ FooMethodThreads *thread_proxy_1;
+ FooMethodThreads *thread_proxy_2;
+
+ thread_context = g_main_context_new ();
+ thread_loop = g_main_loop_new (thread_context, FALSE);
+ g_main_context_push_thread_default (thread_context);
+
+ /* Check the object */
+ error = NULL;
+ bar_proxy = foo_bar_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "org.gtk.GDBus.BindingsTool.Test",
+ "/bar",
+ NULL, /* GCancellable* */
+ &error);
+ check_bar_proxy (bar_proxy, thread_loop);
+ g_assert_no_error (error);
+ g_object_unref (bar_proxy);
+
+ error = NULL;
+ bat_proxy = foo_bat_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "org.gtk.GDBus.BindingsTool.Test",
+ "/bat",
+ NULL, /* GCancellable* */
+ &error);
+ check_bat_proxy (bat_proxy, thread_loop);
+ g_assert_no_error (error);
+ g_object_unref (bat_proxy);
+
+ error = NULL;
+ authorize_proxy = foo_authorize_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "org.gtk.GDBus.BindingsTool.Test",
+ "/authorize",
+ NULL, /* GCancellable* */
+ &error);
+ check_authorize_proxy (authorize_proxy, thread_loop);
+ g_assert_no_error (error);
+ g_object_unref (authorize_proxy);
+
+ error = NULL;
+ thread_proxy_1 = foo_method_threads_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "org.gtk.GDBus.BindingsTool.Test",
+ "/method_threads_1",
+ NULL, /* GCancellable* */
+ &error);
+ g_assert_no_error (error);
+ thread_proxy_2 = foo_method_threads_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "org.gtk.GDBus.BindingsTool.Test",
+ "/method_threads_2",
+ NULL, /* GCancellable* */
+ &error);
+ g_assert_no_error (error);
+ check_thread_proxies (thread_proxy_1, thread_proxy_2, thread_loop);
+ g_object_unref (thread_proxy_1);
+ g_object_unref (thread_proxy_2);
+
+ g_main_loop_unref (thread_loop);
+ g_main_context_unref (thread_context);
+
+ /* this breaks out of the loop in main() (below) */
+ g_main_loop_quit (loop);
+ return NULL;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+ gchar *xml;
+ GMainLoop *loop;
+} IntrospectData;
+
+static void
+introspect_cb (GDBusConnection *connection,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ IntrospectData *data = user_data;
+ GVariant *result;
+ GError *error;
+
+ error = NULL;
+ result = g_dbus_connection_call_finish (connection,
+ res,
+ &error);
+ g_assert_no_error (error);
+ g_assert (result != NULL);
+ g_variant_get (result, "(s)", &data->xml);
+ g_variant_unref (result);
+
+ g_main_loop_quit (data->loop);
+}
+
+static GDBusNodeInfo *
+introspect (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *object_path,
+ GMainLoop *loop)
+{
+ GError *error;
+ GDBusNodeInfo *node_info;
+ IntrospectData *data;
+
+ data = g_new0 (IntrospectData, 1);
+ data->xml = NULL;
+ data->loop = loop;
+
+ /* do this async to avoid deadlocks */
+ g_dbus_connection_call (connection,
+ name,
+ object_path,
+ "org.freedesktop.DBus.Introspectable",
+ "Introspect",
+ NULL, /* params */
+ G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ (GAsyncReadyCallback) introspect_cb,
+ data);
+ g_main_loop_run (loop);
+ g_assert (data->xml != NULL);
+
+ error = NULL;
+ node_info = g_dbus_node_info_new_for_xml (data->xml, &error);
+ g_assert_no_error (error);
+ g_assert (node_info != NULL);
+ g_free (data->xml);
+ g_free (data);
+
+ return node_info;
+}
+
+static guint
+count_interfaces (GDBusNodeInfo *info)
+{
+ guint n;
+ for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
+ ;
+ return n;
+}
+
+static guint
+count_nodes (GDBusNodeInfo *info)
+{
+ guint n;
+ for (n = 0; info->nodes != NULL && info->nodes[n] != NULL; n++)
+ ;
+ return n;
+}
+
+static guint
+has_interface (GDBusNodeInfo *info,
+ const gchar *name)
+{
+ guint n;
+ for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
+ {
+ if (g_strcmp0 (info->interfaces[n]->name, name) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct {
+ GMainLoop *loop;
+ GVariant *result;
+} OMGetManagedObjectsData;
+
+static void
+om_get_all_cb (GDBusConnection *connection,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ OMGetManagedObjectsData *data = user_data;
+ GError *error;
+
+ error = NULL;
+ data->result = g_dbus_connection_call_finish (connection,
+ res,
+ &error);
+ g_assert_no_error (error);
+ g_assert (data->result != NULL);
+ g_main_loop_quit (data->loop);
+}
+
+static void
+om_check_get_all (GDBusConnection *c,
+ GMainLoop *loop,
+ const gchar *str)
+{
+ OMGetManagedObjectsData data;
+ gchar *s;
+
+ data.loop = loop;
+ data.result = NULL;
+
+ /* do this async to avoid deadlocks */
+ g_dbus_connection_call (c,
+ g_dbus_connection_get_unique_name (c),
+ "/managed",
+ "org.freedesktop.DBus.ObjectManager",
+ "GetManagedObjects",
+ NULL, /* params */
+ G_VARIANT_TYPE ("(a{oa{sa{sv}}})"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ (GAsyncReadyCallback) om_get_all_cb,
+ &data);
+ g_main_loop_run (loop);
+ g_assert (data.result != NULL);
+ s = g_variant_print (data.result, TRUE);
+ g_assert_cmpstr (s, ==, str);
+ g_free (s);
+ g_variant_unref (data.result);
+}
+
+typedef struct
+{
+ GMainLoop *loop;
+ guint state;
+
+ guint num_object_proxy_added_signals;
+ guint num_object_proxy_removed_signals;
+ guint num_interface_added_signals;
+ guint num_interface_removed_signals;
+} OMData;
+
+static gint
+my_pstrcmp (const gchar **a, const gchar **b)
+{
+ return g_strcmp0 (*a, *b);
+}
+
+static void
+om_check_interfaces_added (const gchar *signal_name,
+ GVariant *parameters,
+ const gchar *object_path,
+ const gchar *first_interface_name,
+ ...)
+{
+ const gchar *path;
+ GVariant *array;
+ guint n;
+ GPtrArray *interfaces;
+ GPtrArray *interfaces_in_message;
+ va_list var_args;
+ const gchar *str;
+
+ interfaces = g_ptr_array_new ();
+ g_ptr_array_add (interfaces, (gpointer) first_interface_name);
+ va_start (var_args, first_interface_name);
+ do
+ {
+ str = va_arg (var_args, const gchar *);
+ if (str == NULL)
+ break;
+ g_ptr_array_add (interfaces, (gpointer) str);
+ }
+ while (TRUE);
+ va_end (var_args);
+
+ g_variant_get (parameters, "(&o*)", &path, &array);
+ g_assert_cmpstr (signal_name, ==, "InterfacesAdded");
+ g_assert_cmpstr (path, ==, object_path);
+ g_assert_cmpint (g_variant_n_children (array), ==, interfaces->len);
+ interfaces_in_message = g_ptr_array_new ();
+ for (n = 0; n < interfaces->len; n++)
+ {
+ const gchar *iface_name;
+ g_variant_get_child (array, n, "{&sa{sv}}", &iface_name, NULL);
+ g_ptr_array_add (interfaces_in_message, (gpointer) iface_name);
+ }
+ g_assert_cmpint (interfaces_in_message->len, ==, interfaces->len);
+ g_ptr_array_sort (interfaces, (GCompareFunc) my_pstrcmp);
+ g_ptr_array_sort (interfaces_in_message, (GCompareFunc) my_pstrcmp);
+ for (n = 0; n < interfaces->len; n++)
+ g_assert_cmpstr (interfaces->pdata[n], ==, interfaces_in_message->pdata[n]);
+ g_ptr_array_unref (interfaces_in_message);
+ g_ptr_array_unref (interfaces);
+ g_variant_unref (array);
+}
+
+static void
+om_check_interfaces_removed (const gchar *signal_name,
+ GVariant *parameters,
+ const gchar *object_path,
+ const gchar *first_interface_name,
+ ...)
+{
+ const gchar *path;
+ GVariant *array;
+ guint n;
+ GPtrArray *interfaces;
+ GPtrArray *interfaces_in_message;
+ va_list var_args;
+ const gchar *str;
+
+ interfaces = g_ptr_array_new ();
+ g_ptr_array_add (interfaces, (gpointer) first_interface_name);
+ va_start (var_args, first_interface_name);
+ do
+ {
+ str = va_arg (var_args, const gchar *);
+ if (str == NULL)
+ break;
+ g_ptr_array_add (interfaces, (gpointer) str);
+ }
+ while (TRUE);
+ va_end (var_args);
+
+ g_variant_get (parameters, "(&o*)", &path, &array);
+ g_assert_cmpstr (signal_name, ==, "InterfacesRemoved");
+ g_assert_cmpstr (path, ==, object_path);
+ g_assert_cmpint (g_variant_n_children (array), ==, interfaces->len);
+ interfaces_in_message = g_ptr_array_new ();
+ for (n = 0; n < interfaces->len; n++)
+ {
+ const gchar *iface_name;
+ g_variant_get_child (array, n, "&s", &iface_name, NULL);
+ g_ptr_array_add (interfaces_in_message, (gpointer) iface_name);
+ }
+ g_assert_cmpint (interfaces_in_message->len, ==, interfaces->len);
+ g_ptr_array_sort (interfaces, (GCompareFunc) my_pstrcmp);
+ g_ptr_array_sort (interfaces_in_message, (GCompareFunc) my_pstrcmp);
+ for (n = 0; n < interfaces->len; n++)
+ g_assert_cmpstr (interfaces->pdata[n], ==, interfaces_in_message->pdata[n]);
+ g_ptr_array_unref (interfaces_in_message);
+ g_ptr_array_unref (interfaces);
+ g_variant_unref (array);
+}
+
+static void
+om_on_signal (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ OMData *om_data = user_data;
+
+ //g_debug ("foo: %s", g_variant_print (parameters, TRUE));
+
+ switch (om_data->state)
+ {
+ default:
+ case 0:
+ g_print ("failing and om_data->state=%d on signal %s, params=%s\n",
+ om_data->state,
+ signal_name,
+ g_variant_print (parameters, TRUE));
+ g_assert_not_reached ();
+ break;
+
+ case 1:
+ om_check_interfaces_added (signal_name, parameters, "/managed/first",
+ "org.project.Bar", NULL);
+ om_data->state = 2;
+ g_main_loop_quit (om_data->loop);
+ break;
+
+ case 3:
+ om_check_interfaces_removed (signal_name, parameters, "/managed/first",
+ "org.project.Bar", NULL);
+ om_data->state = 5;
+ /* keep running the loop */
+ break;
+
+ case 5:
+ om_check_interfaces_added (signal_name, parameters, "/managed/first",
+ "org.project.Bar", NULL);
+ om_data->state = 6;
+ g_main_loop_quit (om_data->loop);
+ break;
+
+ case 7:
+ om_check_interfaces_removed (signal_name, parameters, "/managed/first",
+ "org.project.Bar", NULL);
+ om_data->state = 9;
+ /* keep running the loop */
+ break;
+
+ case 9:
+ om_check_interfaces_added (signal_name, parameters, "/managed/first",
+ "org.project.Bar", NULL);
+ om_data->state = 10;
+ g_main_loop_quit (om_data->loop);
+ break;
+
+ case 11:
+ om_check_interfaces_added (signal_name, parameters, "/managed/first",
+ "org.project.Bat", NULL);
+ om_data->state = 12;
+ g_main_loop_quit (om_data->loop);
+ break;
+
+ case 13:
+ om_check_interfaces_removed (signal_name, parameters, "/managed/first",
+ "org.project.Bar", NULL);
+ om_data->state = 14;
+ g_main_loop_quit (om_data->loop);
+ break;
+
+ case 15:
+ om_check_interfaces_removed (signal_name, parameters, "/managed/first",
+ "org.project.Bat", NULL);
+ om_data->state = 16;
+ g_main_loop_quit (om_data->loop);
+ break;
+
+ case 17:
+ om_check_interfaces_added (signal_name, parameters, "/managed/first",
+ "com.acme.Coyote", NULL);
+ om_data->state = 18;
+ g_main_loop_quit (om_data->loop);
+ break;
+
+ case 101:
+ om_check_interfaces_added (signal_name, parameters, "/managed/second",
+ "org.project.Bat", "org.project.Bar", NULL);
+ om_data->state = 102;
+ g_main_loop_quit (om_data->loop);
+ break;
+
+ case 103:
+ om_check_interfaces_removed (signal_name, parameters, "/managed/second",
+ "org.project.Bat", "org.project.Bar", NULL);
+ om_data->state = 104;
+ g_main_loop_quit (om_data->loop);
+ break;
+ }
+}
+
+static GAsyncResult *om_res = NULL;
+
+static void
+om_pm_start_cb (GDBusObjectManagerClient *manager,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GMainLoop *loop = user_data;
+ om_res = g_object_ref (res);
+ g_main_loop_quit (loop);
+}
+
+static GType
+get_proxy_type (GDBusObjectManagerClient *manager,
+ const gchar *object_path,
+ const gchar *interface_name,
+ gpointer user_data)
+{
+ GType type;
+
+ g_assert_cmpint (GPOINTER_TO_UINT (user_data), ==, 42);
+
+ type = G_TYPE_DBUS_PROXY;
+ /* only map Bar and Bat, not other interface types */
+ if (g_strcmp0 (interface_name, "org.project.Bar") == 0)
+ type = FOO_TYPE_BAR_PROXY;
+ else if (g_strcmp0 (interface_name, "org.project.Bat") == 0)
+ type = FOO_TYPE_BAT_PROXY;
+
+ return type;
+}
+
+static void
+on_interface_added (GDBusObject *object,
+ GDBusInterface *interface,
+ gpointer user_data)
+{
+ OMData *om_data = user_data;
+ om_data->num_interface_added_signals += 1;
+}
+
+static void
+on_interface_removed (GDBusObject *object,
+ GDBusInterface *interface,
+ gpointer user_data)
+{
+ OMData *om_data = user_data;
+ om_data->num_interface_removed_signals += 1;
+}
+
+static void
+on_object_proxy_added (GDBusObjectManagerClient *manager,
+ GDBusObjectProxy *object_proxy,
+ gpointer user_data)
+{
+ OMData *om_data = user_data;
+ om_data->num_object_proxy_added_signals += 1;
+ g_signal_connect (object_proxy,
+ "interface-added",
+ G_CALLBACK (on_interface_added),
+ om_data);
+ g_signal_connect (object_proxy,
+ "interface-removed",
+ G_CALLBACK (on_interface_removed),
+ om_data);
+}
+
+static void
+on_object_proxy_removed (GDBusObjectManagerClient *manager,
+ GDBusObjectProxy *object_proxy,
+ gpointer user_data)
+{
+ OMData *om_data = user_data;
+ om_data->num_object_proxy_removed_signals += 1;
+ g_assert_cmpint (g_signal_handlers_disconnect_by_func (object_proxy,
+ G_CALLBACK (on_interface_added),
+ om_data), ==, 1);
+ g_assert_cmpint (g_signal_handlers_disconnect_by_func (object_proxy,
+ G_CALLBACK (on_interface_removed),
+ om_data), ==, 1);
+}
+
+static void
+om_check_property_and_signal_emission (GMainLoop *loop,
+ FooBar *stub,
+ FooBar *proxy)
+{
+ /* First PropertiesChanged */
+ g_assert_cmpint (foo_bar_get_i (stub), ==, 0);
+ g_assert_cmpint (foo_bar_get_i (proxy), ==, 0);
+ foo_bar_set_i (stub, 1);
+ _g_assert_property_notify (proxy, "i");
+ g_assert_cmpint (foo_bar_get_i (stub), ==, 1);
+ g_assert_cmpint (foo_bar_get_i (proxy), ==, 1);
+
+ /* Then just a regular signal */
+ foo_bar_emit_another_signal (stub, "word");
+ _g_assert_signal_received (proxy, "another-signal");
+}
+
+static void
+check_object_manager (void)
+{
+ GDBusObjectStub *o;
+ GDBusObjectStub *o2;
+ GDBusInterfaceStub *i;
+ GDBusInterfaceStub *i2;
+ GDBusConnection *c;
+ GDBusObjectManagerServer *manager;
+ GDBusNodeInfo *info;
+ GError *error;
+ GMainLoop *loop;
+ OMData *om_data;
+ guint om_signal_id;
+ GDBusObjectManager *pm;
+ GList *object_proxies;
+ GList *proxies;
+ GDBusObject *op;
+ GDBusProxy *p;
+ FooBar *bar_stub;
+ FooBar *bar_p;
+ FooBar *bar_p2;
+ FooComAcmeCoyote *coyote_p;
+ guint old_ref_count;
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ om_data = g_new0 (OMData, 1);
+ om_data->loop = loop;
+ om_data->state = 0;
+
+ error = NULL;
+ c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (c != NULL);
+
+ om_signal_id = g_dbus_connection_signal_subscribe (c,
+ NULL, /* sender */
+ "org.freedesktop.DBus.ObjectManager",
+ NULL, /* member */
+ NULL, /* object_path */
+ NULL, /* arg0 */
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ om_on_signal,
+ om_data,
+ NULL); /* user_data_free_func */
+
+ /* Our GDBusObjectManagerClient tests are simple - we basically just count the
+ * number of times the various signals have been emitted (we don't check
+ * that the right objects/interfaces are passed though - that's checked
+ * in the lower-level tests in om_on_signal()...)
+ *
+ * Note that these tests rely on the D-Bus signal handlers used by
+ * GDBusObjectManagerClient firing before om_on_signal().
+ */
+ error = NULL;
+ pm = g_dbus_object_manager_client_new_sync (c,
+ G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+ g_dbus_connection_get_unique_name (c),
+ "/managed",
+ get_proxy_type,
+ GUINT_TO_POINTER (42),
+ NULL, /* GCancellable */
+ &error);
+ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
+ g_error_free (error);
+ g_assert (pm == NULL);
+
+ manager = g_dbus_object_manager_server_new (c, "/managed");
+
+ /* Check that the manager object is visible */
+ info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed", loop);
+ g_assert_cmpint (count_interfaces (info), ==, 4); /* ObjectManager + Properties,Introspectable,Peer */
+ g_assert (has_interface (info, "org.freedesktop.DBus.ObjectManager"));
+ g_assert_cmpint (count_nodes (info), ==, 0);
+ g_dbus_node_info_unref (info);
+
+ /* Check GetManagedObjects() - should be empty since we have no objects */
+ om_check_get_all (c, loop,
+ "(@a{oa{sa{sv}}} {},)");
+
+ /* Now try to create the the proxy manager again - this time it should work */
+ error = NULL;
+ g_dbus_object_manager_client_new (c,
+ G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+ g_dbus_connection_get_unique_name (c),
+ "/managed",
+ get_proxy_type,
+ GUINT_TO_POINTER (42),
+ NULL, /* GCancellable */
+ (GAsyncReadyCallback) om_pm_start_cb,
+ loop);
+ g_main_loop_run (loop);
+ error = NULL;
+ pm = g_dbus_object_manager_client_new_finish (om_res, &error);
+ g_object_unref (om_res);
+ g_assert_no_error (error);
+ g_assert (pm != NULL);
+ g_signal_connect (pm,
+ "object-added",
+ G_CALLBACK (on_object_proxy_added),
+ om_data);
+ g_signal_connect (pm,
+ "object-removed",
+ G_CALLBACK (on_object_proxy_removed),
+ om_data);
+ /* ... check there are no object proxies yet */
+ object_proxies = g_dbus_object_manager_get_objects (pm);
+ g_assert (object_proxies == NULL);
+
+ /* First, export an object with a single interface (also check that
+ * g_dbus_interface_get_object() works and that the object isn't reffed)
+ */
+ o = g_dbus_object_stub_new ("/managed/first");
+ i = G_DBUS_INTERFACE_STUB (foo_bar_stub_new ());
+ g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == NULL);
+ g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
+ g_dbus_object_stub_add_interface (o, i);
+ g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
+ g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == G_DBUS_OBJECT (o));
+ g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
+ g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
+ g_dbus_object_stub_remove_interface (o, i);
+ g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == NULL);
+ g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
+ g_dbus_object_stub_add_interface (o, i);
+ g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == G_DBUS_OBJECT (o));
+ g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
+ g_dbus_object_manager_server_export (manager, o);
+
+ /* ... check we get the InterfacesAdded signal */
+ om_data->state = 1;
+ g_main_loop_run (om_data->loop);
+ g_assert_cmpint (om_data->state, ==, 2);
+ g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 1);
+ g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 0);
+ g_assert_cmpint (om_data->num_interface_added_signals, ==, 0);
+ g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
+ /* ... check there's one non-standard interfaces */
+ info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
+ g_assert_cmpint (count_interfaces (info), ==, 4); /* Bar + Properties,Introspectable,Peer */
+ g_assert (has_interface (info, "org.project.Bar"));
+ g_dbus_node_info_unref (info);
+
+ /* Now, check adding the same interface replaces the existing one */
+ g_dbus_object_stub_add_interface (o, i);
+ /* ... check we get the InterfacesRemoved */
+ om_data->state = 3;
+ g_main_loop_run (om_data->loop);
+ /* ... and then check we get the InterfacesAdded */
+ g_assert_cmpint (om_data->state, ==, 6);
+ g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 2);
+ g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 1);
+ g_assert_cmpint (om_data->num_interface_added_signals, ==, 0);
+ g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
+ /* ... check introspection data */
+ info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
+ g_assert_cmpint (count_interfaces (info), ==, 4); /* Bar + Properties,Introspectable,Peer */
+ g_assert (has_interface (info, "org.project.Bar"));
+ g_dbus_node_info_unref (info);
+ g_object_unref (i);
+
+ /* check adding an interface of same type (but not same object) replaces the existing one */
+ i = G_DBUS_INTERFACE_STUB (foo_bar_stub_new ());
+ g_dbus_object_stub_add_interface (o, i);
+ /* ... check we get the InterfacesRemoved and then InterfacesAdded */
+ om_data->state = 7;
+ g_main_loop_run (om_data->loop);
+ g_assert_cmpint (om_data->state, ==, 10);
+ g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
+ g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 2);
+ g_assert_cmpint (om_data->num_interface_added_signals, ==, 0);
+ g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
+ /* ... check introspection data */
+ info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
+ g_assert_cmpint (count_interfaces (info), ==, 4); /* Bar + Properties,Introspectable,Peer */
+ g_assert (has_interface (info, "org.project.Bar"));
+ g_dbus_node_info_unref (info);
+ g_object_unref (i);
+
+ /* check adding an interface of another type doesn't replace the existing one */
+ i = G_DBUS_INTERFACE_STUB (foo_bat_stub_new ());
+ g_dbus_object_stub_add_interface (o, i);
+ g_object_unref (i);
+ /* ... check we get the InterfacesAdded */
+ om_data->state = 11;
+ g_main_loop_run (om_data->loop);
+ g_assert_cmpint (om_data->state, ==, 12);
+ g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
+ g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 2);
+ g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
+ g_assert_cmpint (om_data->num_interface_removed_signals, ==, 0);
+ /* ... check introspection data */
+ info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
+ g_assert_cmpint (count_interfaces (info), ==, 5); /* Bar,Bat + Properties,Introspectable,Peer */
+ g_assert (has_interface (info, "org.project.Bar"));
+ g_assert (has_interface (info, "org.project.Bat"));
+ g_dbus_node_info_unref (info);
+
+ /* check we can remove an interface */
+ g_dbus_object_stub_remove_interface_by_name (o, "org.project.Bar");
+ /* ... check we get the InterfacesRemoved */
+ om_data->state = 13;
+ g_main_loop_run (om_data->loop);
+ g_assert_cmpint (om_data->state, ==, 14);
+ g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
+ g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 2);
+ g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
+ g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
+ /* ... check introspection data */
+ info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
+ g_assert_cmpint (count_interfaces (info), ==, 4); /* Bat + Properties,Introspectable,Peer */
+ g_assert (has_interface (info, "org.project.Bat"));
+ g_dbus_node_info_unref (info);
+ /* also and that the call only has effect if the interface actually exists
+ *
+ * (Note: if a signal was emitted we'd assert in the signal handler
+ * because we're in state 14)
+ */
+ g_dbus_object_stub_remove_interface_by_name (o, "org.project.Bar");
+ /* ... check introspection data */
+ info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
+ g_assert_cmpint (count_interfaces (info), ==, 4); /* Bat + Properties,Introspectable,Peer */
+ g_assert (has_interface (info, "org.project.Bat"));
+ g_dbus_node_info_unref (info);
+
+ /* remove the last interface */
+ g_dbus_object_stub_remove_interface_by_name (o, "org.project.Bat");
+ /* ... check we get the InterfacesRemoved */
+ om_data->state = 15;
+ g_main_loop_run (om_data->loop);
+ g_assert_cmpint (om_data->state, ==, 16);
+ g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 3);
+ g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 3);
+ g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
+ g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
+ /* ... check introspection data */
+ info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
+ g_assert_cmpint (count_interfaces (info), ==, 0); /* nothing */
+ g_dbus_node_info_unref (info);
+
+ /* and add an interface again */
+ i = G_DBUS_INTERFACE_STUB (foo_com_acme_coyote_stub_new ());
+ g_dbus_object_stub_add_interface (o, i);
+ g_object_unref (i);
+ /* ... check we get the InterfacesAdded */
+ om_data->state = 17;
+ g_main_loop_run (om_data->loop);
+ g_assert_cmpint (om_data->state, ==, 18);
+ g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 4);
+ g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 3);
+ g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
+ g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
+ /* ... check introspection data */
+ info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
+ g_assert_cmpint (count_interfaces (info), ==, 4); /* com.acme.Coyote + Properties,Introspectable,Peer */
+ g_assert (has_interface (info, "com.acme.Coyote"));
+ g_dbus_node_info_unref (info);
+
+ /* Check GetManagedObjects() - should be just the Coyote */
+ om_check_get_all (c, loop,
+ "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}},)");
+
+ /* -------------------------------------------------- */
+
+ /* create a new object with two interfaces */
+ o2 = g_dbus_object_stub_new ("/managed/second");
+ i = G_DBUS_INTERFACE_STUB (foo_bar_stub_new ());
+ bar_stub = FOO_BAR (i); /* save for later test */
+ g_dbus_object_stub_add_interface (o2, i);
+ g_object_unref (i);
+ i = G_DBUS_INTERFACE_STUB (foo_bat_stub_new ());
+ g_dbus_object_stub_add_interface (o2, i);
+ g_object_unref (i);
+ /* ... add it */
+ g_dbus_object_manager_server_export (manager, o2);
+ /* ... check we get the InterfacesAdded with _two_ interfaces */
+ om_data->state = 101;
+ g_main_loop_run (om_data->loop);
+ g_assert_cmpint (om_data->state, ==, 102);
+ g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 5);
+ g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 3);
+ g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
+ g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
+
+ /* -------------------------------------------------- */
+
+ /* Now that we have a couple of objects with interfaces, check
+ * that ObjectManager.GetManagedObjects() works
+ */
+ om_check_get_all (c, loop,
+ "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': <byte 0x00>, 'b': <false>, 'n': <int16 0>, 'q': <uint16 0>, 'i': <0>, 'u': <uint32 0>, 'x': <int64 0>, 't': <uint64 0>, 'd': <0.0>, 's': <''>, 'o': <objectpath '/'>, 'g': <signature ''>, 'ay': <b''>, 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': <objectpath '/'>, 'unset_g': <signature ''>, 'unset_ay': <b''>, 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)");
+
+ /* check that the _GET_ and _PEEK_ macros work on the server side */
+ i = FOO_PEEK_BAR (o);
+ g_assert (i == NULL);
+ i = FOO_PEEK_COM_ACME_COYOTE (o);
+ g_assert (i != NULL);
+ g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (i), G_TYPE_DBUS_INTERFACE_STUB));
+ g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (i), FOO_TYPE_COM_ACME_COYOTE));
+ g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (i), FOO_TYPE_COM_ACME_COYOTE_STUB));
+ /* ... and that PEEK doesn't increase the ref_count but GET does */
+ g_assert_cmpint (G_OBJECT (i)->ref_count, ==, 2);
+ i2 = FOO_PEEK_COM_ACME_COYOTE (o);
+ g_assert (i == i2);
+ g_assert_cmpint (G_OBJECT (i)->ref_count, ==, 2);
+ i2 = FOO_GET_COM_ACME_COYOTE (o);
+ g_assert (i == i2);
+ g_assert_cmpint (G_OBJECT (i)->ref_count, ==, 3);
+ g_object_unref (i);
+
+ /* Also check that the ObjectManagerClient returns these objects - and
+ * that they are of the right GType cf. what we requested via
+ * our ::get-proxy-type signal handler
+ */
+ object_proxies = g_dbus_object_manager_get_objects (pm);
+ g_assert (g_list_length (object_proxies) == 2);
+ g_list_foreach (object_proxies, (GFunc) g_object_unref, NULL);
+ g_list_free (object_proxies);
+ op = g_dbus_object_manager_get_object (pm, "/managed/first");
+ g_assert (op != NULL);
+ g_assert_cmpstr (g_dbus_object_get_object_path (op), ==, "/managed/first");
+ proxies = g_dbus_object_get_interfaces (op);
+ g_assert (g_list_length (proxies) == 1);
+ g_list_foreach (proxies, (GFunc) g_object_unref, NULL);
+ g_list_free (proxies);
+ p = G_DBUS_PROXY (g_dbus_object_get_interface (op, "com.acme.Coyote"));
+ g_assert (p != NULL);
+ g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, G_TYPE_DBUS_PROXY);
+ g_assert (!g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_TYPE_COM_ACME_COYOTE));
+ g_object_unref (p);
+ p = (GDBusProxy *) g_dbus_object_get_interface (op, "org.project.NonExisting");
+ g_assert (p == NULL);
+ g_object_unref (op);
+ /* -- */
+ op = g_dbus_object_manager_get_object (pm, "/managed/second");
+ g_assert (op != NULL);
+ g_assert_cmpstr (g_dbus_object_get_object_path (op), ==, "/managed/second");
+ proxies = g_dbus_object_get_interfaces (op);
+ g_assert (g_list_length (proxies) == 2);
+ g_list_foreach (proxies, (GFunc) g_object_unref, NULL);
+ g_list_free (proxies);
+ p = G_DBUS_PROXY (g_dbus_object_get_interface (op, "org.project.Bat"));
+ g_assert (p != NULL);
+ g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_TYPE_BAT_PROXY);
+ g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_TYPE_BAT));
+ g_object_unref (p);
+ p = G_DBUS_PROXY (g_dbus_object_get_interface (op, "org.project.Bar"));
+ g_assert (p != NULL);
+ g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_TYPE_BAR_PROXY);
+ g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_TYPE_BAR));
+ /* ... now that we have a Bar instance around, also check that we get signals
+ * and property changes...
+ */
+ om_check_property_and_signal_emission (loop, bar_stub, FOO_BAR (p));
+ g_object_unref (p);
+ p = (GDBusProxy *) g_dbus_object_get_interface (op, "org.project.NonExisting");
+ g_assert (p == NULL);
+ g_object_unref (op);
+
+ /* -------------------------------------------------- */
+
+ /* check that the _GET_ and _PEEK_ macros work on the proxy side */
+ op = g_dbus_object_manager_get_object (pm, "/managed/second");
+ bar_p = FOO_GET_BAR (op);
+ old_ref_count = G_OBJECT (op)->ref_count;
+ g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (bar_p)) == op);
+ g_assert_cmpint (old_ref_count, ==, G_OBJECT (op)->ref_count);
+ g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (bar_p), FOO_TYPE_BAR));
+ g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (bar_p), G_TYPE_DBUS_PROXY));
+ g_assert_cmpint (G_OBJECT (bar_p)->ref_count, ==, 2);
+ g_object_unref (bar_p);
+ bar_p2 = FOO_PEEK_BAR (op);
+ g_assert (bar_p2 == bar_p);
+ g_assert_cmpint (G_OBJECT (bar_p)->ref_count, ==, 1);
+ coyote_p = FOO_GET_COM_ACME_COYOTE (op);
+ g_assert (coyote_p == NULL);
+ coyote_p = FOO_PEEK_COM_ACME_COYOTE (op);
+ g_assert (coyote_p == NULL);
+ g_object_unref (op);
+
+ /* Also, check that we warn on stderr in case the get_proxy_type() function is
+ * wrong etc.
+ */
+ op = g_dbus_object_manager_get_object (pm, "/managed/first");
+ bar_p = FOO_GET_BAR (op);
+ g_assert (bar_p == NULL);
+ if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
+ {
+ coyote_p = FOO_GET_COM_ACME_COYOTE (op);
+ }
+ g_test_trap_assert_stderr ("*runtime check failed: (G_TYPE_CHECK_INSTANCE_TYPE (ret, type))*");
+ g_object_unref (op);
+
+ /* -------------------------------------------------- */
+
+ /* Now remove the second object added above */
+ g_dbus_object_manager_server_unexport (manager, "/managed/second");
+ /* ... check we get InterfacesRemoved with both interfaces */
+ om_data->state = 103;
+ g_main_loop_run (om_data->loop);
+ g_assert_cmpint (om_data->state, ==, 104);
+ g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 5);
+ g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 4);
+ g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
+ g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
+ /* ... check introspection data (there should be nothing) */
+ info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/second", loop);
+ g_assert_cmpint (count_nodes (info), ==, 0);
+ g_assert_cmpint (count_interfaces (info), ==, 0);
+ g_dbus_node_info_unref (info);
+
+ /* Check GetManagedObjects() again */
+ om_check_get_all (c, loop,
+ "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}},)");
+
+ //g_main_loop_run (loop); /* TODO: tmp */
+
+ g_main_loop_unref (loop);
+
+ g_dbus_connection_signal_unsubscribe (c, om_signal_id);
+ g_object_unref (o2);
+ g_object_unref (o);
+ g_object_unref (manager);
+ g_assert_cmpint (g_signal_handlers_disconnect_by_func (pm,
+ G_CALLBACK (on_object_proxy_added),
+ om_data), ==, 1);
+ g_assert_cmpint (g_signal_handlers_disconnect_by_func (pm,
+ G_CALLBACK (on_object_proxy_removed),
+ om_data), ==, 1);
+ g_object_unref (pm);
+ g_object_unref (c);
+
+ g_free (om_data);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+test_object_manager (void)
+{
+ GMainLoop *loop;
+ guint id;
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ id = g_bus_own_name (G_BUS_TYPE_SESSION,
+ "org.gtk.GDBus.BindingsTool.Test",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus_acquired,
+ on_name_acquired,
+ on_name_lost,
+ loop,
+ NULL);
+
+ g_main_loop_run (loop);
+
+ check_object_manager ();
+
+ /* uncomment to keep the service around (to e.g. introspect it) */
+ /* g_main_loop_run (loop); */
+
+ g_bus_unown_name (id);
+ g_main_loop_unref (loop);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+/* This checks that forcing names via org.gtk.GDBus.Name works (see test-codegen.xml) */
+
+extern gpointer name_forcing_1;
+extern gpointer name_forcing_2;
+extern gpointer name_forcing_3;
+extern gpointer name_forcing_4;
+gpointer name_forcing_1 = foo_rocket123_get_gtype;
+gpointer name_forcing_2 = foo_rocket123_call_ignite_xyz;
+gpointer name_forcing_3 = foo_rocket123_emit_exploded_xyz;
+gpointer name_forcing_4 = foo_rocket123_get_speed_xyz;
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+int
+main (int argc,
+ char *argv[])
+{
+ gint ret;
+
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ /* all the tests use a session bus with a well-known address that we can bring up and down
+ * using session_bus_up() and session_bus_down().
+ */
+ g_unsetenv ("DISPLAY");
+ g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
+
+ session_bus_up ();
+
+ /* TODO: wait a bit for the bus to come up.. ideally session_bus_up() won't return
+ * until one can connect to the bus but that's not how things work right now
+ */
+ usleep (500 * 1000);
+
+ g_test_add_func ("/gdbus/codegen/annotations", test_annotations);
+ g_test_add_func ("/gdbus/codegen/object-manager", test_object_manager);
+
+ ret = g_test_run();
+
+ /* tear down bus */
+ session_bus_down ();
+
+ return ret;
+}
diff --git a/gio/tests/test-codegen.xml b/gio/tests/test-codegen.xml
new file mode 100644
index 0000000..328d888
--- /dev/null
+++ b/gio/tests/test-codegen.xml
@@ -0,0 +1,341 @@
+<node>
+ <!-- Fully Loaded Interface -->
+ <interface name="org.project.Bar">
+ <annotation name="org.gtk.GDBus.DocString" value="The org.project.Bar interface is very complicated."/>
+ <annotation name="org.gtk.GDBus.DocString.Short" value="Brief interface doc string"/>
+
+ <method name="HelloWorld">
+ <annotation name="org.gtk.GDBus.DocString" value="Method <emphasis>documentation</emphasis> blablablabla."/>
+ <annotation name="ExistingAnnotation" value="blah"/>
+ <annotation name="org.gtk.GDBus.ExistingInternalAnnotation" value="booh"/>
+ <arg name="greeting" direction="in" type="s">
+ <annotation name="org.gtk.GDBus.DocString" value="in param doc"/>
+ </arg>
+ <arg name="response" direction="out" type="s">
+ <annotation name="org.gtk.GDBus.DocString" value="out param doc"/>
+ </arg>
+ </method>
+
+ <method name="TestPrimitiveTypes">
+ <arg direction="in" type="y" name="val_byte" />
+ <arg direction="in" type="b" name="val_boolean" />
+ <arg direction="in" type="n" name="val_int16" />
+ <arg direction="in" type="q" name="val_uint16" />
+ <arg direction="in" type="i" name="val_int32" />
+ <arg direction="in" type="u" name="val_uint32" />
+ <arg direction="in" type="x" name="val_int64" />
+ <arg direction="in" type="t" name="val_uint64" />
+ <arg direction="in" type="d" name="val_double" />
+ <arg direction="in" type="s" name="val_string" />
+ <arg direction="in" type="o" name="val_objpath" />
+ <arg direction="in" type="g" name="val_signature" />
+ <arg direction="in" type="ay" name="val_bytestring" />
+ <arg direction="out" type="y" name="ret_byte" />
+ <arg direction="out" type="b" name="ret_boolean" />
+ <arg direction="out" type="n" name="ret_int16" />
+ <arg direction="out" type="q" name="ret_uint16" />
+ <arg direction="out" type="i" name="ret_int32" />
+ <arg direction="out" type="u" name="ret_uint32" />
+ <arg direction="out" type="x" name="ret_int64" />
+ <arg direction="out" type="t" name="ret_uint64" />
+ <arg direction="out" type="d" name="ret_double" />
+ <arg direction="out" type="s" name="ret_string" />
+ <arg direction="out" type="o" name="ret_objpath" />
+ <arg direction="out" type="g" name="ret_signature" />
+ <arg direction="out" type="ay" name="ret_bytestring" />
+ </method>
+
+ <method name="TestNonPrimitiveTypes">
+ <arg direction="in" type="a{ss}" name="dict_s_to_s" />
+ <arg direction="in" type="a{s(ii)}" name="dict_s_to_pairs" />
+ <arg direction="in" type="(iss)" name="a_struct" />
+ <arg direction="in" type="as" name="array_of_strings" />
+ <arg direction="in" type="ao" name="array_of_objpaths" />
+ <arg direction="in" type="ag" name="array_of_signatures" />
+ <arg direction="in" type="aay" name="array_of_bytestrings" />
+ <arg direction="out" type="ay" name="result" />
+ </method>
+
+ <method name="RequestSignalEmission">
+ <arg direction="in" type="i" name="which_one" />
+ </method>
+
+ <method name="RequestMultiPropertyMods"/>
+
+ <method name="UnimplementedMethod"/>
+
+ <signal name="TestSignal">
+ <annotation name="org.gtk.GDBus.DocString" value="Signal documentation."/>
+ <arg type="i" name="val_int32">
+ <annotation name="org.gtk.GDBus.DocString" value="Signal param docs"/>
+ </arg>
+ <arg type="as" name="array_of_strings" />
+ <arg type="aay" name="array_of_bytestrings" />
+ <arg type="a{s(ii)}" name="dict_s_to_pairs" />
+ </signal>
+
+ <signal name="AnotherSignal">
+ <arg type="s" name="word" />
+ </signal>
+
+ <property name="y" type="y" access="readwrite">
+ <annotation name="org.gtk.GDBus.DocString" value="<para>Property docs, yah...</para><para>Second paragraph.</para>"/>
+ </property>
+ <property name="b" type="b" access="readwrite"/>
+ <property name="n" type="n" access="readwrite"/>
+ <property name="q" type="q" access="readwrite"/>
+ <property name="i" type="i" access="readwrite"/>
+ <property name="u" type="u" access="readwrite"/>
+ <property name="x" type="x" access="readwrite"/>
+ <property name="t" type="t" access="readwrite"/>
+ <property name="d" type="d" access="readwrite"/>
+ <property name="s" type="s" access="readwrite"/>
+ <property name="o" type="o" access="readwrite"/>
+ <property name="g" type="g" access="readwrite"/>
+ <property name="ay" type="ay" access="readwrite"/>
+ <property name="as" type="as" access="readwrite"/>
+ <property name="aay" type="aay" access="readwrite"/>
+ <property name="ao" type="ao" access="readwrite"/>
+ <property name="ag" type="ag" access="readwrite"/>
+ <property name="FinallyNormalName" type="s" access="readwrite"/>
+ <property name="ReadonlyProperty" type="s" access="read"/>
+ <property name="WriteonlyProperty" type="s" access="write"/>
+
+ <!-- unset properties -->
+ <property name="unset_i" type="i" access="readwrite"/>
+ <property name="unset_d" type="d" access="readwrite"/>
+ <property name="unset_s" type="s" access="readwrite"/>
+ <property name="unset_o" type="o" access="readwrite"/>
+ <property name="unset_g" type="g" access="readwrite"/>
+ <property name="unset_ay" type="ay" access="readwrite"/>
+ <property name="unset_as" type="as" access="readwrite"/>
+ <property name="unset_ao" type="ao" access="readwrite"/>
+ <property name="unset_ag" type="ag" access="readwrite"/>
+ <property name="unset_struct" type="(idsogayasaoag)" access="readwrite"/>
+ </interface> <!-- End org.project.Bar -->
+
+ <!-- Namespaced -->
+ <interface name="org.project.Bar.Frobnicator">
+ <method name="RandomMethod"/>
+ </interface>
+
+ <!-- Empty -->
+ <interface name="org.project.Baz">
+ </interface>
+
+ <!-- Outside D-Bus prefix -->
+ <interface name="com.acme.Coyote">
+ <method name="Run"/>
+ <method name="Sleep"/>
+ <method name="Attack"/>
+ <signal name="Surprised"/>
+ <property name="Mood" type="s" access="read"/>
+ </interface>
+
+ <!-- force various names -->
+ <interface name="com.acme.Rocket">
+ <!-- Forcing the typename via an annotation -->
+ <annotation name="org.gtk.GDBus.Name" value="Rocket123"/>
+
+ <!-- ditto method -->
+ <method name="Ignite">
+ <annotation name="org.gtk.GDBus.Name" value="ignite_xyz"/>
+ </method>
+
+ <!-- ditto signal -->
+ <signal name="Exploded">
+ <annotation name="org.gtk.GDBus.Name" value="exploded-xyz"/>
+ </signal>
+
+ <!-- ditto property -->
+ <property name="Speed" type="d" access="read">
+ <annotation name="org.gtk.GDBus.Name" value="speed-xyz"/>
+ </property>
+
+ <property name="Direction" type="(ddd)" access="read"/>
+
+ <!-- Check there's no conflict with the GType iface_name_get_type() function -->
+ <property name="Type" type="s" access="read"/>
+ </interface>
+
+ <!-- Test interface for forcing use of GVariant -->
+ <interface name="org.project.Bat">
+
+ <!-- Forcing GVariant for types that would be mapped -->
+ <method name="ForceMethod">
+ <arg name="force_in_i" type="i" direction="in">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <arg name="force_in_s" type="s" direction="in">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <arg name="force_in_ay" type="ay" direction="in">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <arg name="force_in_struct" type="(i)" direction="in">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <arg name="force_out_i" type="i" direction="out">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <arg name="force_out_s" type="s" direction="out">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <arg name="force_out_ay" type="ay" direction="out">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <arg name="force_out_struct" type="(i)" direction="out">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ </method>
+
+ <signal name="ForceSignal">
+ <arg name="force_i" type="i">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <arg name="force_s" type="s">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <arg name="force_ay" type="ay">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <arg name="force_struct" type="(i)">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ </signal>
+
+ <property name="force_i" type="i" access="readwrite">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </property>
+ <property name="force_s" type="s" access="readwrite">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </property>
+ <property name="force_ay" type="ay" access="readwrite">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </property>
+ <property name="force_struct" type="(i)" access="readwrite">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </property>
+
+ </interface> <!-- End org.project.Bat -->
+
+ <!-- Test interface for g-authorized-method -->
+ <interface name="org.project.Authorize">
+ <method name="CheckNotAuthorized"/>
+ <method name="CheckAuthorized"/>
+ <method name="CheckNotAuthorizedFromObject"/>
+ </interface> <!-- End org.project.Authorize -->
+
+ <!-- Test interfaces for handling methods in a thread -->
+ <interface name="org.project.MethodThreads">
+ <method name="GetSelf">
+ <arg name="self_pointer" direction="out" type="s"/>
+ </method>
+ </interface> <!-- End org.project.MethodThreads -->
+
+ <!--
+ org.project.InlineDocs:
+ @short_description: The short description
+
+ Here is the <emphasis>longer</emphasis> description.
+
+ With lots of stuff.
+ -->
+ <interface name="org.project.InlineDocs">
+
+ <!--
+ FooMethod:
+ @greeting: The docs for greeting parameter.
+ @response: The docs for response parameter.
+
+ The docs for the actual method.
+
+ Multi-paragraph.
+
+ Test of inline links: The #org.project.Bar D-Bus interface,
+ org.project.Bar.HelloWorld() method, the
+ #org.project.Bar::TestSignal, the
+ #org.project.InlineDocs:Property3 property.
+ -->
+ <method name="FooMethod">
+ <arg name="greeting" direction="in" type="s"/>
+ <arg name="response" direction="out" type="s"/>
+ </method>
+
+ <!-- Method2: foo -->
+ <method name="Method2">
+ <arg name="greeting" direction="in" type="s"/>
+ <arg name="response" direction="out" type="s"/>
+ </method>
+
+ <!--
+ BarSignal:
+ @blah: The docs for blah parameter.
+ @boo: The docs for boo parameter.
+
+ The docs for the actual signal.
+ -->
+ <signal name="BarSignal">
+ <!-- Non-Doc comment -->
+ <arg name="blah" type="s"/>
+ <arg name="boo" type="s"/>
+ </signal>
+
+ <!-- BazProperty: The docs for the property. -->
+ <property name="BazProperty" type="s" access="read"/>
+
+ <!-- Property2: Another property
+ This should be a new paragraph.
+ -->
+ <property name="Property2" type="s" access="read"/>
+
+ <!-- Property3:
+ First line.
+ This should NOT be a new paragraph.
+ -->
+ <property name="Property3" type="s" access="read"/>
+
+ <!-- Property4:
+ First line. With trailing whitespace.
+ Second line (same paragraph).
+ -->
+ <property name="Property4" type="s" access="read"/>
+
+ <!-- Property5: Foo
+ First line (second paragraph). With trailing whitespace.
+ Second line (same paragraph).
+<programlisting>
+1 program listing
+ 2 should include indented space
+ 3
+ 4
+ 5
+</programlisting>
+ -->
+ <property name="Property5" type="s" access="read"/>
+
+
+ <!--
+ FancyProperty:
+ Here's some fancy use of XML inside the comment.
+ <variablelist>
+ <varlistentry>
+ <term><option>namespace</option></term>
+ <listitem>
+ <para>The namespace to use for generated code. In CamelCase format.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>output-prefix</option></term>
+ <listitem>
+ <para>
+ A prefix to use for all generated files. Defaults to <filename>generated</filename>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ -->
+ <property name="FancyProperty" type="s" access="read"/>
+ </interface>
+
+</node>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]