Migrating from dbus-glib to GDBus
Conceptual differences The central concepts of D-Bus are modelled in a very similar way in dbus-glib and GDBus. Both have a objects representing connections, proxies and method invocations. But there are some important differences: dbus-glib uses libdbus, GDBus doesn't. Instead, it relies on GIO streams as transport layer, and has its own implementation for the 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 uses the #GVariant type system which is explicitly designed to match D-Bus types. The typical way to export an object in dbus-glib involves generating glue code from XML introspection data using dbus-binding-tool. GDBus does not (yet?) use code generation; you are expected to embed the introspection data in your application code.
API comparison dbus-glib APIs and their GDBus counterparts dbus-glibGDBus#DBusGConnection#GDBusConnection#DBusGProxy#GDBusProxy#DBusGMethodInvocation#GDBusMethodInvocationdbus_g_bus_get()g_bus_get_sync(), also see g_bus_get()dbus_g_proxy_new_for_name()g_dbus_proxy_new_sync(), also see g_dbus_proxy_new()dbus_g_proxy_add_signal()not needed, use the generic #GDBusProxy::g-signaldbus_g_proxy_connect_signal()use g_signal_connect() with #GDBusProxy::g-signaldbus_g_connection_register_g_object()g_dbus_connection_register_object()dbus_g_connection_unregister_g_object()g_dbus_connection_unregister_object()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 variantsdbus_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. In contrast, #GDBusProxy instances are always bound to a unique name. To get a proxy for a well-known name, you either have to call GetNameOwner yourself and construct a proxy for the unique name of the current name owner, or use the high-level API. The latter option is highly recommended: Like g_bus_own_name(), g_bus_watch_proxy() is asynchronous and you are expected to enter your mainloop to await the on_proxy_appeared() callback. Note that GDBus also does all the setup operations for the proxy asynchronously, and only calls your callback when the proxy is ready for use.
Client-side GObject bindings dbus-glib comes with dbus-binding-tool, which can produce somewhat nice client-side wrappers for a D-Bus interface. GDBus does not have code-generation at this point, but #GDBusProxy is designed to allow the creating of client-side wrappers by subclassing #GDBusProxy. For an example of a #GDBusProxy-derived class that wraps a D-Bus interface in a type-safe way, see . The comparison is as follows: Wrapping the org.freedesktop.Accounts.User D-Bus interface in the AccountUser GObject type D-Bus conceptGObject concept AutomaticLogin property AccountsUser:automatic-login GObject property C getter: accounts_user_get_automatic_login() Watch changes via the notify::automatic-login signal RealName property AccountsUser:real-name GObject property C getter: accounts_user_get_real_name() Watch changes via the notify::real-name signal UserName property AccountsUser:user-name GObject property C getter: accounts_user_get_user_name() Watch changes via the notify::user-name signal Changed signal AccountsUser::changed GObject signal Watch via e.g. g_signal_connect() Frobnicate method Use accounts_user_frobnicate() + accounts_user_frobnicate_finish() or accounts_user_frobnicate_sync() to invoke
GDBusProxy subclass exampleFIXME: MISSING XINCLUDE CONTENT
Exporting objects With dbus-glib, exporting an object over D-Bus works by generating a bunch of glue code from your introspection XML with dbus-binding-tool. The glue code gets included in your source, and you need to call dbus_g_object_type_install_info (TYPE_MYOBJECT, &dbus_glib_myobject_object_info); in your class_init() function to tell dbus-glib about your type. To actually export an instance, you call dbus_g_connection_register_g_object (system_bus_connection, my_object_path, G_OBJECT (my_object)); The GDBus way of exporting an object works by embedding the introspection XML in the source, creating introspection data structures from it with g_dbus_node_info_new_for_xml(), and passing that along when you register the object: " " " " " " " " " " " " " ""; /* parse introspection data */ introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); / id = g_dbus_connection_register_object (connection, "/org/gtk/GDBus/TestObject", "org.gtk.GDBus.TestPeerInterface", introspection_data->interfaces[0], &interface_vtable, NULL, /* user_data */ NULL, /* user_data_free_func */ NULL); /* GError** */ ]]> The actual implementation of the exported object is done by specifying a #GDBusInterfaceVTable that has method_call(), get_property() and set_property() methods. There is no direct support beyond that for exporting #GObjects, so there is quite a bit of manual work involved, as you can see in the following example. Since the VTable methods don't have any direct #GObject support, we pass the exported object as @user_data. Also note that we have to handle the emission of the PropertiesChanged signal ourselves, by connecting to ::notify. Exporting a GObjectFIXME: MISSING XINCLUDE CONTENT