2 <title>Migrating to GDBus</title>
5 <title>Conceptual differences</title>
8 The central concepts of D-Bus are modelled in a very similar way
9 in dbus-glib and GDBus. Both have a objects representing connections,
10 proxies and method invocations. But there are some important
14 dbus-glib uses libdbus, GDBus doesn't. Instead, it relies on GIO
15 streams as transport layer, and has its own implementation for the
16 the D-Bus connection setup and authentication. Apart from using
17 streams as transport, avoiding libdbus also lets GDBus avoid some
18 thorny multithreading issues.
21 dbus-glib uses the GObject type system for method arguments and
22 return values, including a homegrown container specialization
23 mechanism. GDBus relies uses the #GVariant type system which is
24 explicitly designed to match D-Bus types.
27 The typical way to export an object in dbus-glib involves generating
28 glue code from XML introspection data using <command>dbus-binding-tool</command>. GDBus does not (yet?) use code generation; you are expected to
29 embed the introspection data in your application code.
36 <title>API comparison</title>
38 <table id="dbus-glib-vs-gdbus">
39 <title>dbus-glib APIs and their GDBus counterparts</title>
42 <row><entry>dbus-glib</entry><entry>GDBus</entry></row>
45 <row><entry>#DBusGConnection</entry><entry>#GDBusConnection</entry></row>
46 <row><entry>#DBusGProxy</entry><entry>#GDBusProxy</entry></row>
47 <row><entry>#DBusGMethodInvocation</entry><entry>#GDBusMethodInvocation</entry></row>
48 <row><entry>dbus_g_bus_get()</entry><entry>g_bus_get_sync(), also see
49 g_bus_get()</entry></row>
50 <row><entry>dbus_g_proxy_new_for_name()</entry><entry>g_dbus_proxy_new_sync() and
51 g_dbus_proxy_new_for_bus_sync(), also see g_dbus_proxy_new()</entry></row>
52 <row><entry>dbus_g_proxy_add_signal()</entry><entry>not needed, use the generic #GDBusProxy::g-signal</entry></row>
53 <row><entry>dbus_g_proxy_connect_signal()</entry><entry>use g_signal_connect() with #GDBusProxy::g-signal</entry></row>
54 <row><entry>dbus_g_connection_register_g_object()</entry><entry>g_dbus_connection_register_object()</entry></row>
55 <row><entry>dbus_g_connection_unregister_g_object()</entry><entry>g_dbus_connection_unregister_object()</entry></row>
56 <row><entry>dbus_g_object_type_install_info()</entry><entry>introspection data is installed while registering
57 an object, see g_dbus_connection_register_object()</entry></row>
58 <row><entry>dbus_g_proxy_begin_call()</entry><entry>g_dbus_proxy_call()</entry></row>
59 <row><entry>dbus_g_proxy_end_call()</entry><entry>g_dbus_proxy_call_finish()</entry></row>
60 <row><entry>dbus_g_proxy_call()</entry><entry>g_dbus_proxy_call_sync()</entry></row>
61 <row><entry>dbus_g_error_domain_register()</entry><entry>g_dbus_error_register_error_domain()</entry></row>
62 <row><entry>dbus_g_error_has_name()</entry><entry>no direct equivalent, see g_dbus_error_get_remote_error()</entry></row>
63 <row><entry>dbus_g_method_return()</entry><entry>g_dbus_method_invocation_return_value()</entry></row>
64 <row><entry>dbus_g_method_return_error()</entry><entry>g_dbus_method_invocation_return_error() and variants</entry></row>
65 <row><entry>dbus_g_method_get_sender()</entry><entry>g_dbus_method_invocation_get_sender()</entry></row>
72 <title>Owning bus names</title>
74 Using dbus-glib, you typically call RequestName manually
75 to own a name, like in the following excerpt:
76 <informalexample><programlisting><![CDATA[
78 res = dbus_g_proxy_call (system_bus_proxy,
81 G_TYPE_STRING, NAME_TO_CLAIM,
82 G_TYPE_UINT, DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
90 g_warning ("Failed to acquire %s: %s",
91 NAME_TO_CLAIM, error->message);
96 g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
101 if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
105 g_warning ("Failed to acquire %s: %s",
106 NAME_TO_CLAIM, error->message);
107 g_error_free (error);
111 g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
116 dbus_g_proxy_add_signal (system_bus_proxy, "NameLost",
117 G_TYPE_STRING, G_TYPE_INVALID);
118 dbus_g_proxy_connect_signal (system_bus_proxy, "NameLost",
119 G_CALLBACK (on_name_lost), NULL, NULL);
121 /* further setup ... */
123 </programlisting></informalexample>
126 While you can do things this way with GDBus too, using
127 g_dbus_proxy_call_sync(), it is much nicer to use the high-level API
129 <informalexample><programlisting><![CDATA[
131 on_name_acquired (GDBusConnection *connection,
135 /* further setup ... */
140 owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
142 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
149 g_main_loop_run (loop);
151 g_bus_unown_name (owner_id);
153 </programlisting></informalexample>
154 Note that g_bus_own_name() works asynchronously and requires
155 you to enter your mainloop to await the on_name_aquired()
156 callback. Also note that in order to avoid race conditions (e.g.
157 when your service is activated by a method call), you have to export
158 your manager object <emphasis>before</emphasis> acquiring the
159 name. The on_bus_acquired() callback is the right place to do
165 <title>Creating proxies for well-known names</title>
167 dbus-glib lets you create proxy objects for well-known names, like the
169 <informalexample><programlisting><![CDATA[
170 proxy = dbus_g_proxy_new_for_name (system_bus_connection,
171 "org.freedesktop.Accounts",
172 "/org/freedesktop/Accounts",
173 "org.freedesktop.Accounts");
175 </programlisting></informalexample>
176 For a #DBusGProxy constructed like this, method calls will be sent to
177 the current owner of the name, and that owner can change over time.
180 The same can be achieved with #GDBusProxy:
181 <informalexample><programlisting><![CDATA[
183 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
184 G_DBUS_PROXY_FLAGS_NONE,
185 NULL, /* GDBusInterfaceInfo */
186 "org.freedesktop.Accounts",
187 "/org/freedesktop/Accounts",
188 "org.freedesktop.Accounts",
189 NULL, /* GCancellable */
192 </programlisting></informalexample>
193 For an added layer of safety, you can specify what D-Bus
194 interface the proxy is expected to conform to by using the
195 #GDBusInterfaceInfo type.
198 Additionally, #GDBusProxy loads, caches and tracks changes to
199 the D-Bus properties on the remote object. It also sets up match
200 rules so D-Bus signals from the remote object are delivered
205 <title>Client-side GObject bindings</title>
208 dbus-glib comes with <command>dbus-binding-tool</command>, which
209 can produce somewhat nice client-side wrappers for a D-Bus interface.
210 GDBus does not have code-generation at this point, but #GDBusProxy
211 is designed to allow the creating of client-side wrappers by
212 subclassing #GDBusProxy.
215 For an example of a #GDBusProxy-derived class that wraps a D-Bus
216 interface in a type-safe way, see <xref
217 linkend="gdbus-example-proxy-subclass"/>. The comparison is as
219 <table id="gdbus-example-type-safe-proxy">
220 <title>Wrapping the org.freedesktop.Accounts.User D-Bus interface in the AccountUser GObject type</title>
223 <row><entry>D-Bus concept</entry><entry>GObject concept</entry></row>
227 <entry>AutomaticLogin property</entry>
229 <para><literal>AccountsUser:automatic-login</literal> GObject property</para>
230 <para>C getter: accounts_user_get_automatic_login()</para>
231 <para>Watch changes via the <literal>notify::automatic-login</literal> signal</para>
235 <entry>RealName property</entry>
237 <para><literal>AccountsUser:real-name</literal> GObject property</para>
238 <para>C getter: accounts_user_get_real_name()</para>
239 <para>Watch changes via the <literal>notify::real-name signal</literal></para>
243 <entry>UserName property</entry>
245 <para><literal>AccountsUser:user-name</literal> GObject property</para>
246 <para>C getter: accounts_user_get_user_name()</para>
247 <para>Watch changes via the <literal>notify::user-name</literal> signal</para>
251 <entry>Changed signal</entry>
253 <para><literal>AccountsUser::changed</literal> GObject signal</para>
254 <para>Watch via e.g. g_signal_connect()</para>
258 <entry>Frobnicate method</entry>
260 <para>Use accounts_user_frobnicate() + accounts_user_frobnicate_finish() or accounts_user_frobnicate_sync() to invoke</para>
267 <example id="gdbus-example-proxy-subclass"><title>GDBusProxy subclass example</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-proxy-subclass.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
271 <title>Exporting objects</title>
274 With dbus-glib, exporting an object over D-Bus works by generating
275 a bunch of glue code from your introspection XML with
276 <command>dbus-binding-tool</command>. The glue code gets included in
277 your source, and you need to call
278 <informalexample><programlisting>
279 dbus_g_object_type_install_info (TYPE_MYOBJECT,
280 &dbus_glib_myobject_object_info);
281 </programlisting></informalexample>
282 in your class_init() function to tell dbus-glib about your type.
283 To actually export an instance, you call
284 <informalexample><programlisting>
285 dbus_g_connection_register_g_object (system_bus_connection,
287 G_OBJECT (my_object));
288 </programlisting></informalexample>
292 The GDBus way of exporting an object works by embedding the
293 introspection XML in the source, creating introspection data
294 structures from it with g_dbus_node_info_new_for_xml(), and
295 passing that along when you register the object:
296 <informalexample><programlisting><![CDATA[
298 static const gchar introspection_xml[] =
300 " <interface name='org.gtk.GDBus.TestPeerInterface'>"
301 " <method name='HelloWorld'>"
302 " <arg type='s' name='greeting' direction='in'/>"
303 " <arg type='s' name='response' direction='out'/>"
308 /* parse introspection data */
309 introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
312 id = g_dbus_connection_register_object (connection,
313 "/org/gtk/GDBus/TestObject",
314 "org.gtk.GDBus.TestPeerInterface",
315 introspection_data->interfaces[0],
317 NULL, /* user_data */
318 NULL, /* user_data_free_func */
319 NULL); /* GError** */
322 </programlisting></informalexample>
325 The actual implementation of the exported object is done by specifying
326 a #GDBusInterfaceVTable that has method_call(), get_property() and
327 set_property() methods. There is no direct support beyond that for
328 exporting #GObjects, so there is quite a bit of manual work involved,
329 as you can see in the following example.
332 Since the VTable methods don't have any direct #GObject support, we
333 pass the exported object as @user_data. Also note that we have to handle
334 the emission of the PropertiesChanged signal ourselves, by connecting
337 <example id="gdbus-export"><title>Exporting a GObject</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-export.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>