• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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