![]() |
![]() |
![]() |
GIO Reference Manual | ![]() |
---|
dbus-glib comes with dbus-binding-tool, which can produce somewhat nice client- and server-side wrappers for a D-Bus interface. With GDBus, gdbus-codegen is used and like its counterpart, it also takes D-Bus Introspection XML as input:
Example 22. Example D-Bus Introspection XML
<node> <!-- org.gtk.GDBus.Example.ObjectManager.Animal: @short_description: Example docs generated by gdbus-codegen @since: 2.30 This D-Bus interface is used to describe a simple animal. --> <interface name="org.gtk.GDBus.Example.ObjectManager.Animal"> <!-- Mood: The mood of the animal. @since: 2.30 Known values for this property include <literal>Happy</literal> and <literal>Sad</literal>. Use the org.gtk.GDBus.Example.ObjectManager.Animal.Poke() method to change this property. This property influences how often the animal jumps up and down, see the #org.gtk.GDBus.Example.ObjectManager.Animal::Jumped signal for more details. --> <property name="Mood" type="s" access="read"/> <!-- Poke: @make_sad: Whether to make the animal sad. @make_happy: Whether to make the animal happy. @since: 2.30 Method used to changing the mood of the animal. See also the #org.gtk.GDBus.Example.ObjectManager.Animal:Mood property. --> <method name="Poke"> <arg direction="in" type="b" name="make_sad"/> <arg direction="in" type="b" name="make_happy"/> </method> <!-- Jumped: @height: Height, in meters, that the animal jumped. @since: 2.30 Emitted when the animal decides to jump. --> <signal name="Jumped"> <arg type="d" name="height"/> </signal> </interface> <!-- org.gtk.GDBus.Example.ObjectManager.Cat: @short_description: More example docs generated by gdbus-codegen This D-Bus interface is used to describe a cat. Right now there are no properties, methods or signals associated with this interface so it is essentially a <ulink url="http://en.wikipedia.org/wiki/Marker_interface_pattern">Marker Interface</ulink>. Note that D-Bus objects implementing this interface also implement the #org.gtk.GDBus.Example.ObjectManager.Animal interface. --> <interface name="org.gtk.GDBus.Example.ObjectManager.Cat"> </interface> </node>
If this XML is processed like this
gdbus-codegen --interface-prefix org.gtk.GDBus.Example.ObjectManager. \ --generate-c-code generated-code \ --c-namespace Example \ --c-generate-object-manager \ --generate-docbook generated-docs \ gdbus-example-objectmanager.xml
then two files generated-code.h
and
generated-code.c
are
generated. Additionally, two XML files
generated-docs-org.gtk.GDBus.Example.ObjectManager.Animal
and
generated-docs-org.gtk.GDBus.Example.ObjectManager.Cat
with Docbook XML are generated. For an example of what the docs look
like see the Animal D-Bus interface documentation.
and
the Cat D-Bus interface documentation.
While the contents of generated-code.h
and
generated-code.c
are best described by the
gdbus-codegen manual
page, brief examples of how this generated code can be used can be found in
Example 23, “Server-side application using generated code”
and Example 24, “Client-side application using generated code”. Additionally, since
the generated code has 100% gtk-doc coverage, see
ExampleAnimal, ExampleCat, ExampleObject and
ExampleObjectManagerClient pages for documentation.
Example 23. Server-side application using generated code
#include "gdbus-example-objectmanager-generated.h" /* ---------------------------------------------------------------------------------------------------- */ static GDBusObjectManagerServer *manager = NULL; static gboolean on_animal_poke (ExampleAnimal *animal, GDBusMethodInvocation *invocation, gboolean make_sad, gboolean make_happy, gpointer user_data) { if ((make_sad && make_happy) || (!make_sad && !make_happy)) { g_dbus_method_invocation_return_dbus_error (invocation, "org.gtk.GDBus.Examples.ObjectManager.Error.Failed", "Exactly one of make_sad or make_happy must be TRUE"); goto out; } if (make_sad) { if (g_strcmp0 (example_animal_get_mood (animal), "Sad") == 0) { g_dbus_method_invocation_return_dbus_error (invocation, "org.gtk.GDBus.Examples.ObjectManager.Error.SadAnimalIsSad", "Sad animal is already sad"); goto out; } example_animal_set_mood (animal, "Sad"); example_animal_complete_poke (animal, invocation); goto out; } if (make_happy) { if (g_strcmp0 (example_animal_get_mood (animal), "Happy") == 0) { g_dbus_method_invocation_return_dbus_error (invocation, "org.gtk.GDBus.Examples.ObjectManager.Error.HappyAnimalIsHappy", "Happy animal is already happy"); goto out; } example_animal_set_mood (animal, "Happy"); example_animal_complete_poke (animal, invocation); goto out; } g_assert_not_reached (); out: return TRUE; /* to indicate that the method was handled */ } static void on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { ExampleObjectSkeleton *object; guint n; g_print ("Acquired a message bus connection\n"); /* Create a new org.freedesktop.DBus.ObjectManager rooted at /example/Animals */ manager = g_dbus_object_manager_server_new ("/example/Animals"); for (n = 0; n < 10; n++) { gchar *s; ExampleAnimal *animal; /* Create a new D-Bus object at the path /example/Animals/N where N is 000..009 */ s = g_strdup_printf ("/example/Animals/%03d", n); object = example_object_skeleton_new (s); g_free (s); /* Make the newly created object export the interface * org.gtk.GDBus.Example.ObjectManager.Animal (note * that @object takes its own reference to @animal). */ animal = example_animal_skeleton_new (); example_animal_set_mood (animal, "Happy"); example_object_skeleton_set_animal (object, animal); g_object_unref (animal); /* Cats are odd animals - so some of our objects implement the * org.gtk.GDBus.Example.ObjectManager.Cat interface in addition * to the .Animal interface */ if (n % 2 == 1) { ExampleCat *cat; cat = example_cat_skeleton_new (); example_object_skeleton_set_cat (object, cat); g_object_unref (cat); } /* Handle Poke() D-Bus method invocations on the .Animal interface */ g_signal_connect (animal, "handle-poke", G_CALLBACK (on_animal_poke), NULL); /* user_data */ /* Export the object (@manager takes its own reference to @object) */ g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object)); g_object_unref (object); } /* Export all objects */ g_dbus_object_manager_server_set_connection (manager, connection); } static void on_name_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { g_print ("Acquired the name %s\n", name); } static void on_name_lost (GDBusConnection *connection, const gchar *name, gpointer user_data) { g_print ("Lost the name %s\n", name); } gint main (gint argc, gchar *argv[]) { GMainLoop *loop; guint id; g_type_init (); loop = g_main_loop_new (NULL, FALSE); id = g_bus_own_name (G_BUS_TYPE_SESSION, "org.gtk.GDBus.Examples.ObjectManager", G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | G_BUS_NAME_OWNER_FLAGS_REPLACE, on_bus_acquired, on_name_acquired, on_name_lost, loop, NULL); g_main_loop_run (loop); g_bus_unown_name (id); g_main_loop_unref (loop); return 0; }
Example 24. Client-side application using generated code
#include "gdbus-example-objectmanager-generated.h" /* ---------------------------------------------------------------------------------------------------- */ static void print_objects (GDBusObjectManager *manager) { GList *objects; GList *l; g_print ("Object manager at %s\n", g_dbus_object_manager_get_object_path (manager)); objects = g_dbus_object_manager_get_objects (manager); for (l = objects; l != NULL; l = l->next) { ExampleObject *object = EXAMPLE_OBJECT (l->data); GList *interfaces; GList *ll; g_print (" - Object at %s\n", g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (object)); for (ll = interfaces; ll != NULL; ll = ll->next) { GDBusInterface *interface = G_DBUS_INTERFACE (ll->data); g_print (" - Interface %s\n", g_dbus_interface_get_info (interface)->name); /* Note that @interface is really a GDBusProxy instance - and additionally also * an ExampleAnimal or ExampleCat instance - either of these can be used to * invoke methods on the remote object. For example, the generated function * * void example_animal_call_poke_sync (ExampleAnimal *proxy, * gboolean make_sad, * gboolean make_happy, * GCancellable *cancellable, * GError **error); * * can be used to call the Poke() D-Bus method on the .Animal interface. * Additionally, the generated function * * const gchar *example_animal_get_mood (ExampleAnimal *object); * * can be used to get the value of the :Mood property. */ } g_list_foreach (interfaces, (GFunc) g_object_unref, NULL); g_list_free (interfaces); } g_list_foreach (objects, (GFunc) g_object_unref, NULL); g_list_free (objects); } static void on_object_added (GDBusObjectManager *manager, GDBusObject *object, gpointer user_data) { gchar *owner; owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (manager)); g_print ("Added object at %s (owner %s)\n", g_dbus_object_get_object_path (object), owner); g_free (owner); } static void on_object_removed (GDBusObjectManager *manager, GDBusObject *object, gpointer user_data) { gchar *owner; owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (manager)); g_print ("Removed object at %s (owner %s)\n", g_dbus_object_get_object_path (object), owner); g_free (owner); } static void on_notify_name_owner (GObject *object, GParamSpec *pspec, gpointer user_data) { GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object); gchar *name_owner; name_owner = g_dbus_object_manager_client_get_name_owner (manager); g_print ("name-owner: %s\n", name_owner); g_free (name_owner); } static void on_interface_proxy_properties_changed (GDBusObjectManagerClient *manager, GDBusObjectProxy *object_proxy, GDBusProxy *interface_proxy, GVariant *changed_properties, const gchar *const *invalidated_properties, gpointer user_data) { GVariantIter iter; const gchar *key; GVariant *value; gchar *s; g_print ("Properties Changed on %s:\n", g_dbus_object_get_object_path (G_DBUS_OBJECT (object_proxy))); g_variant_iter_init (&iter, changed_properties); while (g_variant_iter_next (&iter, "{&sv}", &key, &value)) { s = g_variant_print (value, TRUE); g_print (" %s -> %s\n", key, s); g_variant_unref (value); g_free (s); } } gint main (gint argc, gchar *argv[]) { GDBusObjectManager *manager; GMainLoop *loop; GError *error; gchar *name_owner; manager = NULL; loop = NULL; g_type_init (); loop = g_main_loop_new (NULL, FALSE); error = NULL; manager = example_object_manager_client_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, "org.gtk.GDBus.Examples.ObjectManager", "/example/Animals", NULL, /* GCancellable */ &error); if (manager == NULL) { g_printerr ("Error getting object manager client: %s", error->message); g_error_free (error); goto out; } name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (manager)); g_print ("name-owner: %s\n", name_owner); g_free (name_owner); print_objects (manager); g_signal_connect (manager, "notify::name-owner", G_CALLBACK (on_notify_name_owner), NULL); g_signal_connect (manager, "object-added", G_CALLBACK (on_object_added), NULL); g_signal_connect (manager, "object-removed", G_CALLBACK (on_object_removed), NULL); g_signal_connect (manager, "interface-proxy-properties-changed", G_CALLBACK (on_interface_proxy_properties_changed), NULL); g_main_loop_run (loop); out: if (manager != NULL) g_object_unref (manager); if (loop != NULL) g_main_loop_unref (loop); return 0; }