diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml index b29e04df6..8fdbe2ff2 100644 --- a/docs/reference/gio/gio-docs.xml +++ b/docs/reference/gio/gio-docs.xml @@ -268,7 +268,6 @@ Migrating to GIO - diff --git a/docs/reference/gio/gio.toml.in b/docs/reference/gio/gio.toml.in index fba7f14e1..9fe1b3fba 100644 --- a/docs/reference/gio/gio.toml.in +++ b/docs/reference/gio/gio.toml.in @@ -42,6 +42,7 @@ urlmap_file = "urlmap.js" content_files = [ "overview.md", + "migrating-gdbus.md", "migrating-gconf.md", "migrating-gnome-vfs.md", ] diff --git a/docs/reference/gio/meson.build b/docs/reference/gio/meson.build index 63e64f876..0176096fc 100644 --- a/docs/reference/gio/meson.build +++ b/docs/reference/gio/meson.build @@ -162,7 +162,6 @@ if get_option('gtk_doc') content_files = [ 'migrating-posix.xml', - 'migrating-gdbus.xml', 'gio-querymodules.xml', 'glib-compile-schemas.xml', 'glib-compile-resources.xml', @@ -196,7 +195,6 @@ if get_option('gtk_doc') content_files : content_files, expand_content_files : [ 'migrating-posix.xml', - 'migrating-gdbus.xml', 'gdbus-codegen.xml', ], html_assets : [ @@ -232,6 +230,7 @@ endif # gi-docgen version expand_content_files = [ 'migrating-gconf.md', + 'migrating-gdbus.md', 'migrating-gnome-vfs.md', 'overview.md', ] diff --git a/docs/reference/gio/migrating-gdbus.md b/docs/reference/gio/migrating-gdbus.md new file mode 100644 index 000000000..c2c3355ab --- /dev/null +++ b/docs/reference/gio/migrating-gdbus.md @@ -0,0 +1,633 @@ +Title: Migrating to GDBus +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2010 Matthias Clasen +SPDX-FileCopyrightText: 2010, 2011 David Zeuthen + +# Migrating to GDBus + +## Conceptual differences + +The central concepts of D-Bus are modelled in a very similar way in +dbus-glib and GDBus. Both have objects representing connections, proxies and +method invocations. But there are some important differences: + +- dbus-glib uses the libdbus reference implementation, GDBus doesn't. + Instead, it relies on GIO streams as transport layer, and has its own + implementation for the D-Bus connection setup and authentication. Apart + from using streams as transport, avoiding libdbus also lets GDBus avoid + some thorny multithreading issues. +- dbus-glib uses the GObject type system for method arguments and return + values, including a homegrown container specialization mechanism. GDBus + relies on the GVariant type system which is explicitly designed to match + D-Bus types. +- dbus-glib models only D-Bus interfaces and does not provide any types for + objects. GDBus models both D-Bus interfaces (via the GDBusInterface, + GDBusProxy and GDBusInterfaceSkeleton types) and objects (via the + GDBusObject, GDBusObjectSkeleton and GDBusObjectProxy types). +- GDBus includes native support for the org.freedesktop.DBus.Properties (via + the GDBusProxy type) and org.freedesktop.DBus.ObjectManager D-Bus + interfaces, dbus-glib doesn't. +- The typical way to export an object in dbus-glib involves generating glue + code from XML introspection data using dbus-binding-tool. GDBus provides a + similar tool called gdbus-codegen that can also generate Docbook D-Bus + interface documentation. +- dbus-glib doesn't provide any convenience API for owning and watching bus + names, GDBus provides the `g_bus_own_name()` and `g_bus_watch_name()` + family of convenience functions. +- GDBus provides API to parse, generate and work with Introspection XML, + dbus-glib doesn't. +- GTestDBus provides API to create isolated unit tests + +## API comparison + +| dbus-glib | GDBus | +|-----------|-------| +| `DBusGConnection` | `GDBusConnection` | +| `DBusGProxy` | `GDBusProxy`, `GDBusInterface` - also see `GDBusObjectProxy` | +| `DBusGObject` | `GDBusInterfaceSkeleton`, `GDBusInterface` - also see `GDBusObjectSkeleton` | +| `DBusGMethodInvocation` | `GDBusMethodInvocation` | +| `dbus_g_bus_get()` | `g_bus_get_sync()`, also see `g_bus_get()` | +| `dbus_g_proxy_new_for_name()` | `g_dbus_proxy_new_sync()` and `g_dbus_proxy_new_for_bus_sync()`, also see `g_dbus_proxy_new()` | +| `dbus_g_proxy_add_signal()` | not needed, use the generic “g-signal” | +| `dbus_g_proxy_connect_signal()` | use `g_signal_connect()` with “g-signal” | +| `dbus_g_connection_register_g_object()` | `g_dbus_connection_register_object()` - also see `g_dbus_object_manager_server_export()` | +| `dbus_g_connection_unregister_g_object()` | `g_dbus_connection_unregister_object()` - also see `g_dbus_object_manager_server_unexport()` | +| `dbus_g_object_type_install_info()` | introspection data is installed while registering an object, see `g_dbus_connection_register_object()` | +| `dbus_g_proxy_begin_call()` | `g_dbus_proxy_call()` | +| `dbus_g_proxy_end_call()` | `g_dbus_proxy_call_finish()` | +| `dbus_g_proxy_call()` | `g_dbus_proxy_call_sync()` | +| `dbus_g_error_domain_register()` | `g_dbus_error_register_error_domain()` | +| `dbus_g_error_has_name()` | no direct equivalent, see `g_dbus_error_get_remote_error()` | +| `dbus_g_method_return()` | `g_dbus_method_invocation_return_value()` | +| `dbus_g_method_return_error()` | `g_dbus_method_invocation_return_error()` and variants | +| `dbus_g_method_get_sender()` | `g_dbus_method_invocation_get_sender()` | + +## Owning bus names + +Using dbus-glib, you typically call RequestName manually to own a name, like in the following excerpt: + +```c +error = NULL; +res = dbus_g_proxy_call (system_bus_proxy, + "RequestName", + &error, + G_TYPE_STRING, NAME_TO_CLAIM, + G_TYPE_UINT, DBUS_NAME_FLAG_ALLOW_REPLACEMENT, + G_TYPE_INVALID, + G_TYPE_UINT, &result, + G_TYPE_INVALID); +if (!res) + { + if (error != NULL) + { + g_warning ("Failed to acquire %s: %s", + NAME_TO_CLAIM, error->message); + g_error_free (error); + } + else + { + g_warning ("Failed to acquire %s", NAME_TO_CLAIM); + } + goto out; + } + +if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + { + if (error != NULL) + { + g_warning ("Failed to acquire %s: %s", + NAME_TO_CLAIM, error->message); + g_error_free (error); + } + else + { + g_warning ("Failed to acquire %s", NAME_TO_CLAIM); + } + exit (1); + } + +dbus_g_proxy_add_signal (system_bus_proxy, "NameLost", + G_TYPE_STRING, G_TYPE_INVALID); +dbus_g_proxy_connect_signal (system_bus_proxy, "NameLost", + G_CALLBACK (on_name_lost), NULL, NULL); + +/* further setup ... */ +``` + +While you can do things this way with GDBus too, using +`g_dbus_proxy_call_sync()`, it is much nicer to use the high-level API for +this: + +```c +static void +on_name_acquired (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + /* further setup ... */ +} + +/* ... */ + + owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, + NAME_TO_CLAIM, + G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT, + on_bus_acquired, + on_name_acquired, + on_name_lost, + NULL, + NULL); + + g_main_loop_run (loop); + + g_bus_unown_name (owner_id); +``` + +Note that `g_bus_own_name()` works asynchronously and requires you to enter +your mainloop to await the `on_name_aquired()` callback. Also note that in +order to avoid race conditions (e.g. when your service is activated by a +method call), you have to export your manager object before acquiring the +name. The `on_bus_acquired()` callback is the right place to do such +preparations. + +## Creating proxies for well-known names + +dbus-glib lets you create proxy objects for well-known names, like the following example: + +```c +proxy = dbus_g_proxy_new_for_name (system_bus_connection, + "org.freedesktop.Accounts", + "/org/freedesktop/Accounts", + "org.freedesktop.Accounts"); +``` + +For a DBusGProxy constructed like this, method calls will be sent to the current owner of the name, and that owner can change over time. + +The same can be achieved with GDBusProxy: + +```c +error = NULL; +proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, /* GDBusInterfaceInfo */ + "org.freedesktop.Accounts", + "/org/freedesktop/Accounts", + "org.freedesktop.Accounts", + NULL, /* GCancellable */ + &error); +``` + +For an added layer of safety, you can specify what D-Bus interface the proxy +is expected to conform to by using the GDBusInterfaceInfo type. +Additionally, GDBusProxy loads, caches and tracks changes to the D-Bus +properties on the remote object. It also sets up match rules so D-Bus +signals from the remote object are delivered locally. + +The GDBusProxy type normally isn't used directly - instead proxies +subclassing GDBusProxy generated by `gdbus-codegen` is used, see the section +called “Using gdbus-codegen”. + +## Generating code and docs + +### Using gdbus-codegen + +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 D-Bus Introspection XML + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +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. + +While the contents of `generated-code.h` and `generated-code.c` are best described by the `gdbus-codegen` manual page, here's a brief example of how this generated code can be used: + +```c +#include "gdbus-object-manager-example/objectmanager-gen.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 G_DBUS_METHOD_INVOCATION_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; + + 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; +} +``` + +This, on the other hand, is a client-side application using generated code: + +```c +#include "gdbus-object-manager-example/objectmanager-gen.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_free_full (interfaces, g_object_unref); + } + g_list_free_full (objects, g_object_unref); +} + +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; + + 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; +} +``` diff --git a/docs/reference/gio/migrating-gdbus.xml b/docs/reference/gio/migrating-gdbus.xml deleted file mode 100644 index dc4ee75d9..000000000 --- a/docs/reference/gio/migrating-gdbus.xml +++ /dev/null @@ -1,310 +0,0 @@ - - - -]> - - Migrating to GDBus - -
- Conceptual differences - - - The central concepts of D-Bus are modelled in a very similar way - in dbus-glib and GDBus. Both have objects representing connections, - proxies and method invocations. But there are some important - differences: - - - dbus-glib uses the libdbus - reference implementation, GDBus doesn't. Instead, it - relies on GIO streams as transport layer, and has its own - implementation for the D-Bus connection setup and - authentication. Apart from using streams as transport, - avoiding libdbus also lets GDBus avoid some thorny - multithreading issues. - - - dbus-glib uses the GObject type system for method arguments and - return values, including a homegrown container specialization - mechanism. GDBus relies on the #GVariant type system which is - explicitly designed to match D-Bus types. - - - dbus-glib models only D-Bus interfaces and does not provide - any types for objects. GDBus models both D-Bus interfaces - (via the #GDBusInterface, #GDBusProxy and - #GDBusInterfaceSkeleton types) and objects (via the - #GDBusObject, #GDBusObjectSkeleton and #GDBusObjectProxy types). - - - GDBus includes native support for the org.freedesktop.DBus.Properties (via the #GDBusProxy type) and org.freedesktop.DBus.ObjectManager D-Bus interfaces, dbus-glib doesn't. - - - The typical way to export an object in dbus-glib involves - generating glue code from XML introspection data using - dbus-binding-tool. GDBus provides a - similar tool called gdbus-codegen that - can also generate Docbook D-Bus interface documentation. - - - dbus-glib doesn't provide any convenience API for owning and - watching bus names, GDBus provides the g_bus_own_name() and - g_bus_watch_name() family of convenience functions. - - - GDBus provides API to parse, generate and work with Introspection - XML, dbus-glib doesn't. - - - GTestDBus provides API to create isolated unit tests GDBus Test Scaffolding. - - - -
- -
- API comparison - - - dbus-glib APIs and their GDBus counterparts - - - dbus-glibGDBus - - - #DBusGConnection#GDBusConnection - #DBusGProxy#GDBusProxy, #GDBusInterface - also see #GDBusObjectProxy - #DBusGObject#GDBusInterfaceSkeleton, #GDBusInterface - also see #GDBusObjectSkeleton - #DBusGMethodInvocation#GDBusMethodInvocation - dbus_g_bus_get()g_bus_get_sync(), also see - g_bus_get() - dbus_g_proxy_new_for_name()g_dbus_proxy_new_sync() and - g_dbus_proxy_new_for_bus_sync(), also see g_dbus_proxy_new() - dbus_g_proxy_add_signal()not needed, use the generic #GDBusProxy::g-signal - dbus_g_proxy_connect_signal()use g_signal_connect() with #GDBusProxy::g-signal - dbus_g_connection_register_g_object()g_dbus_connection_register_object() - also see g_dbus_object_manager_server_export() - dbus_g_connection_unregister_g_object()g_dbus_connection_unregister_object() - also see g_dbus_object_manager_server_unexport() - dbus_g_object_type_install_info()introspection data is installed while registering - an object, see g_dbus_connection_register_object() - dbus_g_proxy_begin_call()g_dbus_proxy_call() - dbus_g_proxy_end_call()g_dbus_proxy_call_finish() - dbus_g_proxy_call()g_dbus_proxy_call_sync() - dbus_g_error_domain_register()g_dbus_error_register_error_domain() - dbus_g_error_has_name()no direct equivalent, see g_dbus_error_get_remote_error() - dbus_g_method_return()g_dbus_method_invocation_return_value() - dbus_g_method_return_error()g_dbus_method_invocation_return_error() and variants - dbus_g_method_get_sender()g_dbus_method_invocation_get_sender() - - -
-
- -
- Owning bus names - - Using dbus-glib, you typically call RequestName manually - to own a name, like in the following excerpt: - message); - g_error_free (error); - } - else - { - g_warning ("Failed to acquire %s", NAME_TO_CLAIM); - } - goto out; - } - - if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) - { - if (error != NULL) - { - g_warning ("Failed to acquire %s: %s", - NAME_TO_CLAIM, error->message); - g_error_free (error); - } - else - { - g_warning ("Failed to acquire %s", NAME_TO_CLAIM); - } - exit (1); - } - - dbus_g_proxy_add_signal (system_bus_proxy, "NameLost", - G_TYPE_STRING, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (system_bus_proxy, "NameLost", - G_CALLBACK (on_name_lost), NULL, NULL); - - /* further setup ... */ -]]> - - - - While you can do things this way with GDBus too, using - g_dbus_proxy_call_sync(), it is much nicer to use the high-level API - for this: - - - Note that g_bus_own_name() works asynchronously and requires - you to enter your mainloop to await the on_name_aquired() - callback. Also note that in order to avoid race conditions (e.g. - when your service is activated by a method call), you have to export - your manager object before acquiring the - name. The on_bus_acquired() callback is the right place to do - such preparations. - -
- -
- Creating proxies for well-known names - - dbus-glib lets you create proxy objects for well-known names, like the - following example: - - - For a #DBusGProxy constructed like this, method calls will be sent to - the current owner of the name, and that owner can change over time. - - - The same can be achieved with #GDBusProxy: - - - For an added layer of safety, you can specify what D-Bus - interface the proxy is expected to conform to by using the - #GDBusInterfaceInfo type. Additionally, #GDBusProxy loads, - caches and tracks changes to the D-Bus properties on the remote - object. It also sets up match rules so D-Bus signals from the - remote object are delivered locally. - - - The #GDBusProxy type normally isn't used directly - instead - proxies subclassing #GDBusProxy generated by gdbus-codegen is used, see - -
- -
- Generating code and docs - -
- Using gdbus-codegen - - - 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 D-Bus Introspection XMLFIXME: MISSING XINCLUDE CONTENT: gdbus-example-objectmanager.xml - - If this XML is processed like this - - 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 - - and . Additionally, since - the generated code has 100% gtk-doc coverage, see - #ExampleAnimal, #ExampleCat, #ExampleObject and - #ExampleObjectManagerClient pages for documentation. - - - Server-side application using generated codeFIXME: MISSING XINCLUDE CONTENT: gdbus-example-objectmanager-server.c - - Client-side application using generated codeFIXME: MISSING XINCLUDE CONTENT: gdbus-example-objectmanager-client.c - -
- - - FIXME: MISSING XINCLUDE CONTENT: objectmanager-gen-org.gtk.GDBus.Example.ObjectManager.Animal.xml - FIXME: MISSING XINCLUDE CONTENT: objectmanager-gen-org.gtk.GDBus.Example.ObjectManager.Cat.xml - FIXME: MISSING XINCLUDE CONTENT: ExampleAnimal.xml - FIXME: MISSING XINCLUDE CONTENT: ExampleCat.xml - FIXME: MISSING XINCLUDE CONTENT: ExampleObject.xml - FIXME: MISSING XINCLUDE CONTENT: ExampleObjectManagerClient.xml - -
- -