Bug 621213 – GDBusProxy and well-known names
[platform/upstream/glib.git] / docs / reference / gio / migrating-gdbus.xml
1 <chapter>
2   <title>Migrating to GDBus</title>
3
4   <section>
5     <title>Conceptual differences</title>
6
7     <para>
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
11       differences:
12       <itemizedlist>
13         <listitem><para>
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.
19         </para></listitem>
20         <listitem><para>
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.
25         </para></listitem>
26         <listitem><para>
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.
30         </para></listitem>
31       </itemizedlist>
32     </para>
33   </section>
34
35   <section>
36     <title>API comparison</title>
37
38     <table id="dbus-glib-vs-gdbus">
39       <title>dbus-glib APIs and their GDBus counterparts</title>
40       <tgroup cols="2">
41         <thead>
42            <row><entry>dbus-glib</entry><entry>GDBus</entry></row>
43         </thead>
44         <tbody>
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>
66         </tbody>
67       </tgroup>
68     </table>
69   </section>
70
71   <section>
72     <title>Owning bus names</title>
73     <para>
74       Using dbus-glib, you typically call RequestName manually
75       to own a name, like in the following excerpt:
76       <informalexample><programlisting><![CDATA[
77   error = NULL;
78   res = dbus_g_proxy_call (system_bus_proxy,
79                            "RequestName",
80                            &error,
81                            G_TYPE_STRING, NAME_TO_CLAIM,
82                            G_TYPE_UINT,   DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
83                            G_TYPE_INVALID,
84                            G_TYPE_UINT,   &result,
85                            G_TYPE_INVALID);
86   if (!res)
87     {
88       if (error != NULL)
89         {
90           g_warning ("Failed to acquire %s: %s",
91                      NAME_TO_CLAIM, error->message);
92           g_error_free (error);
93         }
94       else
95         {
96           g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
97         }
98       goto out;
99     }
100
101   if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
102     {
103       if (error != NULL)
104         {
105           g_warning ("Failed to acquire %s: %s",
106                      NAME_TO_CLAIM, error->message);
107           g_error_free (error);
108         }
109       else
110         {
111           g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
112         }
113       exit (1);
114     }
115
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);
120
121   /* further setup ... */
122 ]]>
123       </programlisting></informalexample>
124     </para>
125     <para>
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
128     for this:
129     <informalexample><programlisting><![CDATA[
130 static void
131 on_name_acquired (GDBusConnection *connection,
132                   const gchar     *name,
133                   gpointer         user_data)
134 {
135   /* further setup ... */
136 }
137
138 /* ... */
139
140   owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
141                              NAME_TO_CLAIM,
142                              G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
143                              on_bus_acquired,
144                              on_name_acquired,
145                              on_name_lost,
146                              NULL,
147                              NULL);
148
149   g_main_loop_run (loop);
150
151   g_bus_unown_name (owner_id);
152 ]]>
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
160     such preparations.
161     </para>
162   </section>
163
164   <section>
165     <title>Creating proxies for well-known names</title>
166     <para>
167       dbus-glib lets you create proxy objects for well-known names, like the
168       following example:
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");
174       ]]>
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.
178     </para>
179     <para>
180       The same can be achieved with #GDBusProxy:
181       <informalexample><programlisting><![CDATA[
182   error = NULL;
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 */
190                                          &error);
191       ]]>
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.
196     </para>
197     <para>
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
201       locally.
202     </para>
203   </section>
204   <section>
205     <title>Client-side GObject bindings</title>
206
207     <para>
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.
213     </para>
214     <para>
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
218       follows:
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>
221         <tgroup cols="2">
222           <thead>
223             <row><entry>D-Bus concept</entry><entry>GObject concept</entry></row>
224           </thead>
225           <tbody>
226             <row>
227               <entry>AutomaticLogin property</entry>
228               <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>
232               </entry>
233             </row>
234             <row>
235               <entry>RealName property</entry>
236               <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>
240               </entry>
241             </row>
242             <row>
243               <entry>UserName property</entry>
244               <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>
248               </entry>
249             </row>
250             <row>
251               <entry>Changed signal</entry>
252               <entry>
253                 <para><literal>AccountsUser::changed</literal> GObject signal</para>
254                 <para>Watch via e.g. g_signal_connect()</para>
255               </entry>
256             </row>
257             <row>
258               <entry>Frobnicate method</entry>
259               <entry>
260                 <para>Use accounts_user_frobnicate() + accounts_user_frobnicate_finish() or accounts_user_frobnicate_sync() to invoke</para>
261               </entry>
262             </row>
263           </tbody>
264         </tgroup>
265       </table>
266     </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>
268   </section>
269
270   <section>
271     <title>Exporting objects</title>
272
273     <para>
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                                    &amp;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,
286                                        my_object_path,
287                                        G_OBJECT (my_object));
288       </programlisting></informalexample>
289
290     </para>
291     <para>
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[
297
298   static const gchar introspection_xml[] =
299     "<node>"
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'/>"
304     "    </method>"
305     "  </interface>"
306     "</node>";
307
308   /* parse introspection data */
309   introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
310
311   /
312   id = g_dbus_connection_register_object (connection,
313                                           "/org/gtk/GDBus/TestObject",
314                                           "org.gtk.GDBus.TestPeerInterface",
315                                           introspection_data->interfaces[0],
316                                           &interface_vtable,
317                                           NULL,  /* user_data */
318                                           NULL,  /* user_data_free_func */
319                                           NULL); /* GError** */
320
321 ]]>
322     </programlisting></informalexample>
323     </para>
324     <para>
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.
330     </para>
331     <para>
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
335       to ::notify.
336     </para>
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>
338   </section>
339
340 </chapter>