1<?xml version="1.0"?> 2<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" 3 "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ 4<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'"> 5<!ENTITY version SYSTEM "version.xml"> 6]> 7<chapter> 8 <title>Migrating to GDBus</title> 9 10 <section> 11 <title>Conceptual differences</title> 12 13 <para> 14 The central concepts of D-Bus are modelled in a very similar way 15 in dbus-glib and GDBus. Both have objects representing connections, 16 proxies and method invocations. But there are some important 17 differences: 18 <itemizedlist> 19 <listitem><para> 20 dbus-glib uses the <ulink 21 url="http://www.freedesktop.org/wiki/Software/dbus#ReferenceImplementation.28dbus-daemonandlibdbus.29">libdbus 22 reference implementation</ulink>, GDBus doesn't. Instead, it 23 relies on GIO streams as transport layer, and has its own 24 implementation for the D-Bus connection setup and 25 authentication. Apart from using streams as transport, 26 avoiding libdbus also lets GDBus avoid some thorny 27 multithreading issues. 28 </para></listitem> 29 <listitem><para> 30 dbus-glib uses the GObject type system for method arguments and 31 return values, including a homegrown container specialization 32 mechanism. GDBus relies on the #GVariant type system which is 33 explicitly designed to match D-Bus types. 34 </para></listitem> 35 <listitem><para> 36 dbus-glib models only D-Bus interfaces and does not provide 37 any types for objects. GDBus models both D-Bus interfaces 38 (via the #GDBusInterface, #GDBusProxy and 39 #GDBusInterfaceSkeleton types) and objects (via the 40 #GDBusObject, #GDBusObjectSkeleton and #GDBusObjectProxy types). 41 </para></listitem> 42 <listitem><para> 43 GDBus includes native support for the <ulink url="http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties">org.freedesktop.DBus.Properties</ulink> (via the #GDBusProxy type) and <ulink url="http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager">org.freedesktop.DBus.ObjectManager</ulink> D-Bus interfaces, dbus-glib doesn't. 44 </para></listitem> 45 <listitem><para> 46 The typical way to export an object in dbus-glib involves 47 generating glue code from XML introspection data using 48 <command>dbus-binding-tool</command>. GDBus provides a 49 similar tool called <command><link 50 linkend="gdbus-codegen">gdbus-codegen</link></command> that 51 can also generate Docbook D-Bus interface documentation. 52 </para></listitem> 53 <listitem><para> 54 dbus-glib doesn't provide any convenience API for owning and 55 watching bus names, GDBus provides the g_bus_own_name() and 56 g_bus_watch_name() family of convenience functions. 57 </para></listitem> 58 <listitem><para> 59 GDBus provides API to parse, generate and work with <link 60 linkend="gio-D-Bus-Introspection-Data">Introspection 61 XML</link>, dbus-glib doesn't. 62 </para></listitem> 63 <listitem><para> 64 GTestDBus provides API to create isolated unit tests <link 65 linkend="gio-D-Bus-Test-Scaffolding">GDBus Test Scaffolding</link>. 66 </para></listitem> 67 </itemizedlist> 68 </para> 69 </section> 70 71 <section> 72 <title>API comparison</title> 73 74 <table id="dbus-glib-vs-gdbus"> 75 <title>dbus-glib APIs and their GDBus counterparts</title> 76 <tgroup cols="2"> 77 <thead> 78 <row><entry>dbus-glib</entry><entry>GDBus</entry></row> 79 </thead> 80 <tbody> 81 <row><entry>#DBusGConnection</entry><entry>#GDBusConnection</entry></row> 82 <row><entry>#DBusGProxy</entry><entry>#GDBusProxy, #GDBusInterface - also see #GDBusObjectProxy</entry></row> 83 <row><entry>#DBusGObject</entry><entry>#GDBusInterfaceSkeleton, #GDBusInterface - also see #GDBusObjectSkeleton</entry></row> 84 <row><entry>#DBusGMethodInvocation</entry><entry>#GDBusMethodInvocation</entry></row> 85 <row><entry>dbus_g_bus_get()</entry><entry>g_bus_get_sync(), also see 86 g_bus_get()</entry></row> 87 <row><entry>dbus_g_proxy_new_for_name()</entry><entry>g_dbus_proxy_new_sync() and 88 g_dbus_proxy_new_for_bus_sync(), also see g_dbus_proxy_new()</entry></row> 89 <row><entry>dbus_g_proxy_add_signal()</entry><entry>not needed, use the generic #GDBusProxy::g-signal</entry></row> 90 <row><entry>dbus_g_proxy_connect_signal()</entry><entry>use g_signal_connect() with #GDBusProxy::g-signal</entry></row> 91 <row><entry>dbus_g_connection_register_g_object()</entry><entry>g_dbus_connection_register_object() - also see g_dbus_object_manager_server_export()</entry></row> 92 <row><entry>dbus_g_connection_unregister_g_object()</entry><entry>g_dbus_connection_unregister_object() - also see g_dbus_object_manager_server_unexport()</entry></row> 93 <row><entry>dbus_g_object_type_install_info()</entry><entry>introspection data is installed while registering 94 an object, see g_dbus_connection_register_object()</entry></row> 95 <row><entry>dbus_g_proxy_begin_call()</entry><entry>g_dbus_proxy_call()</entry></row> 96 <row><entry>dbus_g_proxy_end_call()</entry><entry>g_dbus_proxy_call_finish()</entry></row> 97 <row><entry>dbus_g_proxy_call()</entry><entry>g_dbus_proxy_call_sync()</entry></row> 98 <row><entry>dbus_g_error_domain_register()</entry><entry>g_dbus_error_register_error_domain()</entry></row> 99 <row><entry>dbus_g_error_has_name()</entry><entry>no direct equivalent, see g_dbus_error_get_remote_error()</entry></row> 100 <row><entry>dbus_g_method_return()</entry><entry>g_dbus_method_invocation_return_value()</entry></row> 101 <row><entry>dbus_g_method_return_error()</entry><entry>g_dbus_method_invocation_return_error() and variants</entry></row> 102 <row><entry>dbus_g_method_get_sender()</entry><entry>g_dbus_method_invocation_get_sender()</entry></row> 103 </tbody> 104 </tgroup> 105 </table> 106 </section> 107 108 <section> 109 <title>Owning bus names</title> 110 <para> 111 Using dbus-glib, you typically call RequestName manually 112 to own a name, like in the following excerpt: 113 <informalexample><programlisting><![CDATA[ 114 error = NULL; 115 res = dbus_g_proxy_call (system_bus_proxy, 116 "RequestName", 117 &error, 118 G_TYPE_STRING, NAME_TO_CLAIM, 119 G_TYPE_UINT, DBUS_NAME_FLAG_ALLOW_REPLACEMENT, 120 G_TYPE_INVALID, 121 G_TYPE_UINT, &result, 122 G_TYPE_INVALID); 123 if (!res) 124 { 125 if (error != NULL) 126 { 127 g_warning ("Failed to acquire %s: %s", 128 NAME_TO_CLAIM, error->message); 129 g_error_free (error); 130 } 131 else 132 { 133 g_warning ("Failed to acquire %s", NAME_TO_CLAIM); 134 } 135 goto out; 136 } 137 138 if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) 139 { 140 if (error != NULL) 141 { 142 g_warning ("Failed to acquire %s: %s", 143 NAME_TO_CLAIM, error->message); 144 g_error_free (error); 145 } 146 else 147 { 148 g_warning ("Failed to acquire %s", NAME_TO_CLAIM); 149 } 150 exit (1); 151 } 152 153 dbus_g_proxy_add_signal (system_bus_proxy, "NameLost", 154 G_TYPE_STRING, G_TYPE_INVALID); 155 dbus_g_proxy_connect_signal (system_bus_proxy, "NameLost", 156 G_CALLBACK (on_name_lost), NULL, NULL); 157 158 /* further setup ... */ 159]]> 160 </programlisting></informalexample> 161 </para> 162 <para> 163 While you can do things this way with GDBus too, using 164 g_dbus_proxy_call_sync(), it is much nicer to use the high-level API 165 for this: 166 <informalexample><programlisting><![CDATA[ 167static void 168on_name_acquired (GDBusConnection *connection, 169 const gchar *name, 170 gpointer user_data) 171{ 172 /* further setup ... */ 173} 174 175/* ... */ 176 177 owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, 178 NAME_TO_CLAIM, 179 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT, 180 on_bus_acquired, 181 on_name_acquired, 182 on_name_lost, 183 NULL, 184 NULL); 185 186 g_main_loop_run (loop); 187 188 g_bus_unown_name (owner_id); 189]]> 190 </programlisting></informalexample> 191 Note that g_bus_own_name() works asynchronously and requires 192 you to enter your mainloop to await the on_name_aquired() 193 callback. Also note that in order to avoid race conditions (e.g. 194 when your service is activated by a method call), you have to export 195 your manager object <emphasis>before</emphasis> acquiring the 196 name. The on_bus_acquired() callback is the right place to do 197 such preparations. 198 </para> 199 </section> 200 201 <section> 202 <title>Creating proxies for well-known names</title> 203 <para> 204 dbus-glib lets you create proxy objects for well-known names, like the 205 following example: 206 <informalexample><programlisting><![CDATA[ 207 proxy = dbus_g_proxy_new_for_name (system_bus_connection, 208 "org.freedesktop.Accounts", 209 "/org/freedesktop/Accounts", 210 "org.freedesktop.Accounts"); 211 ]]> 212 </programlisting></informalexample> 213 For a #DBusGProxy constructed like this, method calls will be sent to 214 the current owner of the name, and that owner can change over time. 215 </para> 216 <para> 217 The same can be achieved with #GDBusProxy: 218 <informalexample><programlisting><![CDATA[ 219 error = NULL; 220 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 221 G_DBUS_PROXY_FLAGS_NONE, 222 NULL, /* GDBusInterfaceInfo */ 223 "org.freedesktop.Accounts", 224 "/org/freedesktop/Accounts", 225 "org.freedesktop.Accounts", 226 NULL, /* GCancellable */ 227 &error); 228 ]]> 229 </programlisting></informalexample> 230 For an added layer of safety, you can specify what D-Bus 231 interface the proxy is expected to conform to by using the 232 #GDBusInterfaceInfo type. Additionally, #GDBusProxy loads, 233 caches and tracks changes to the D-Bus properties on the remote 234 object. It also sets up match rules so D-Bus signals from the 235 remote object are delivered locally. 236 </para> 237 <para> 238 The #GDBusProxy type normally isn't used directly - instead 239 proxies subclassing #GDBusProxy generated by <command><link 240 linkend="gdbus-codegen">gdbus-codegen</link></command> is used, see <xref linkend="gdbus-example-gdbus-codegen"/> 241 </para> 242 </section> 243 244 <section> 245 <title>Generating code and docs</title> 246 247 <section id="gdbus-example-gdbus-codegen"> 248 <title>Using gdbus-codegen</title> 249 250 <para> 251 dbus-glib comes with <command>dbus-binding-tool</command>, which 252 can produce somewhat nice client- and server-side wrappers for a D-Bus interface. 253 With GDBus, <command><link 254 linkend="gdbus-codegen">gdbus-codegen</link></command> is used and like 255 its counterpart, it also takes D-Bus Introspection XML as input: 256 </para> 257 <example id="gdbus-example-codegen-input"><title>Example D-Bus Introspection XML</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../../gio/tests/gdbus-object-manager-example/gdbus-example-objectmanager.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: gdbus-example-objectmanager.xml</xi:fallback></xi:include></programlisting></example> 258 <para> 259 If this XML is processed like this 260<informalexample><programlisting><![CDATA[ 261gdbus-codegen --interface-prefix org.gtk.GDBus.Example.ObjectManager. \ 262 --generate-c-code generated-code \ 263 --c-namespace Example \ 264 --c-generate-object-manager \ 265 --generate-docbook generated-docs \ 266 gdbus-example-objectmanager.xml 267]]></programlisting></informalexample> 268 then two files <filename>generated-code.h</filename> and 269 <filename>generated-code.c</filename> are 270 generated. Additionally, two XML files 271 <filename>generated-docs-org.gtk.GDBus.Example.ObjectManager.Animal</filename> and 272 <filename>generated-docs-org.gtk.GDBus.Example.ObjectManager.Cat</filename> 273 with Docbook XML are generated. For an example of what the docs look 274 like see <link 275 linkend="gdbus-interface-org-gtk-GDBus-Example-ObjectManager-Animal">the Animal D-Bus interface documentation</link>. 276 and 277 <link 278 linkend="gdbus-interface-org-gtk-GDBus-Example-ObjectManager-Cat">the Cat D-Bus interface documentation</link>. 279 </para> 280 <para> 281 While the contents of <filename>generated-code.h</filename> and 282 <filename>generated-code.c</filename> are best described by the 283 <command><link 284 linkend="gdbus-codegen">gdbus-codegen</link></command> manual 285 page, brief examples of how this generated code can be used can be found in 286 <xref linkend="gdbus-example-codegen-server"/> 287 and <xref 288 linkend="gdbus-example-codegen-client"/>. Additionally, since 289 the generated code has 100% gtk-doc coverage, see 290 #ExampleAnimal, #ExampleCat, #ExampleObject and 291 #ExampleObjectManagerClient pages for documentation. 292 </para> 293 294 <example id="gdbus-example-codegen-server"><title>Server-side application using generated code</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../../gio/tests/gdbus-example-objectmanager-server.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: gdbus-example-objectmanager-server.c</xi:fallback></xi:include></programlisting></example> 295 296 <example id="gdbus-example-codegen-client"><title>Client-side application using generated code</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../../gio/tests/gdbus-example-objectmanager-client.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: gdbus-example-objectmanager-client.c</xi:fallback></xi:include></programlisting></example> 297 298 </section> 299 300 <!-- All XInclude paths are relative to the html/ directory under the build root directory --> 301 <xi:include href="../../../../gio/tests/gdbus-object-manager-example/objectmanager-gen-org.gtk.GDBus.Example.ObjectManager.Animal.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: objectmanager-gen-org.gtk.GDBus.Example.ObjectManager.Animal.xml</xi:fallback></xi:include> 302 <xi:include href="../../../../gio/tests/gdbus-object-manager-example/objectmanager-gen-org.gtk.GDBus.Example.ObjectManager.Cat.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: objectmanager-gen-org.gtk.GDBus.Example.ObjectManager.Cat.xml</xi:fallback></xi:include> 303 <xi:include href="../gdbus-object-manager-example/xml/ExampleAnimal.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: ExampleAnimal.xml</xi:fallback></xi:include> 304 <xi:include href="../gdbus-object-manager-example/xml/ExampleCat.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: ExampleCat.xml</xi:fallback></xi:include> 305 <xi:include href="../gdbus-object-manager-example/xml/ExampleObject.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: ExampleObject.xml</xi:fallback></xi:include> 306 <xi:include href="../gdbus-object-manager-example/xml/ExampleObjectManagerClient.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: ExampleObjectManagerClient.xml</xi:fallback></xi:include> 307 308 </section> 309 310</chapter> 311