2011-04-12 00:32:11 +02:00
<?xml version="1.0"?>
2012-04-23 03:45:08 +02:00
< !DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
2011-04-12 00:32:11 +02:00
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
<!ENTITY version SYSTEM "version.xml">
]>
2010-05-06 23:52:54 +02:00
<chapter >
2010-06-11 21:45:18 +02:00
<title > Migrating to GDBus</title>
2010-05-06 23:52:54 +02:00
2010-05-09 08:27:09 +02:00
<section >
<title > Conceptual differences</title>
<para >
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:
<itemizedlist >
<listitem > <para >
2011-04-12 00:32:11 +02:00
dbus-glib uses the <ulink
url="http://www.freedesktop.org/wiki/Software/dbus#ReferenceImplementation.28dbus-daemonandlibdbus.29">libdbus
reference implementation</ulink> , 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.
2010-05-09 08:27:09 +02:00
</para> </listitem>
<listitem > <para >
dbus-glib uses the GObject type system for method arguments and
return values, including a homegrown container specialization
2011-04-12 00:32:11 +02:00
mechanism. GDBus relies on the #GVariant type system which is
2010-05-09 08:27:09 +02:00
explicitly designed to match D-Bus types.
</para> </listitem>
<listitem > <para >
2011-04-12 00:32:11 +02:00
dbus-glib models only D-Bus interfaces and does not provide
any types for objects. GDBus models both D-Bus interfaces
(via the #GDBusInterface, #GDBusProxy and
2011-06-04 17:52:08 +02:00
#GDBusInterfaceSkeleton types) and objects (via the
#GDBusObject, #GDBusObjectSkeleton and #GDBusObjectProxy types).
2011-04-12 00:32:11 +02:00
</para> </listitem>
<listitem > <para >
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.
</para> </listitem>
<listitem > <para >
The typical way to export an object in dbus-glib involves
generating glue code from XML introspection data using
<command > dbus-binding-tool</command> . GDBus provides a
similar tool called <command > <link
linkend="gdbus-codegen">gdbus-codegen</link> </command> that
can also generate Docbook D-Bus interface documentation.
</para> </listitem>
<listitem > <para >
dbus-glib doesn't provide any convenience API for owning and
watching bus names, GDBus provides the g_bus_own_name() and
g_bus_watch_name() family of convenience functions.
</para> </listitem>
<listitem > <para >
GDBus provides API to parse, generate and work with <link
linkend="gio-D-Bus-Introspection-Data">Introspection
XML</link> , dbus-glib doesn't.
2010-05-09 08:27:09 +02:00
</para> </listitem>
</itemizedlist>
</para>
</section>
<section >
2010-05-12 04:03:40 +02:00
<title > API comparison</title>
2010-05-09 08:27:09 +02:00
<table id= "dbus-glib-vs-gdbus" >
<title > dbus-glib APIs and their GDBus counterparts</title>
<tgroup cols= "2" >
<thead >
<row > <entry > dbus-glib</entry> <entry > GDBus</entry> </row>
</thead>
<tbody >
2010-05-11 23:15:11 +02:00
<row > <entry > #DBusGConnection</entry> <entry > #GDBusConnection</entry> </row>
2011-04-12 00:32:11 +02:00
<row > <entry > #DBusGProxy</entry> <entry > #GDBusProxy, #GDBusInterface - also see #GDBusObjectProxy</entry> </row>
2011-06-04 17:52:08 +02:00
<row > <entry > #DBusGObject</entry> <entry > #GDBusInterfaceSkeleton, #GDBusInterface - also see #GDBusObjectSkeleton</entry> </row>
2010-05-12 03:32:29 +02:00
<row > <entry > #DBusGMethodInvocation</entry> <entry > #GDBusMethodInvocation</entry> </row>
2010-05-09 08:27:09 +02:00
<row > <entry > dbus_g_bus_get()</entry> <entry > g_bus_get_sync(), also see
g_bus_get()</entry> </row>
2010-06-11 21:45:18 +02:00
<row > <entry > dbus_g_proxy_new_for_name()</entry> <entry > g_dbus_proxy_new_sync() and
g_dbus_proxy_new_for_bus_sync(), also see g_dbus_proxy_new()</entry> </row>
2010-05-09 08:27:09 +02:00
<row > <entry > dbus_g_proxy_add_signal()</entry> <entry > not needed, use the generic #GDBusProxy::g-signal</entry> </row>
<row > <entry > dbus_g_proxy_connect_signal()</entry> <entry > use g_signal_connect() with #GDBusProxy::g-signal</entry> </row>
2011-04-12 15:28:09 +02:00
<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>
<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>
2010-05-09 08:27:09 +02:00
<row > <entry > dbus_g_object_type_install_info()</entry> <entry > introspection data is installed while registering
an object, see g_dbus_connection_register_object()</entry> </row>
2010-05-10 17:47:08 +02:00
<row > <entry > dbus_g_proxy_begin_call()</entry> <entry > g_dbus_proxy_call()</entry> </row>
<row > <entry > dbus_g_proxy_end_call()</entry> <entry > g_dbus_proxy_call_finish()</entry> </row>
<row > <entry > dbus_g_proxy_call()</entry> <entry > g_dbus_proxy_call_sync()</entry> </row>
2010-05-09 08:27:09 +02:00
<row > <entry > dbus_g_error_domain_register()</entry> <entry > g_dbus_error_register_error_domain()</entry> </row>
<row > <entry > dbus_g_error_has_name()</entry> <entry > no direct equivalent, see g_dbus_error_get_remote_error()</entry> </row>
<row > <entry > dbus_g_method_return()</entry> <entry > g_dbus_method_invocation_return_value()</entry> </row>
<row > <entry > dbus_g_method_return_error()</entry> <entry > g_dbus_method_invocation_return_error() and variants</entry> </row>
<row > <entry > dbus_g_method_get_sender()</entry> <entry > g_dbus_method_invocation_get_sender()</entry> </row>
</tbody>
</tgroup>
</table>
</section>
2010-05-11 23:15:11 +02:00
<section >
<title > Owning bus names</title>
<para >
Using dbus-glib, you typically call RequestName manually
to own a name, like in the following excerpt:
<informalexample > <programlisting > < ![CDATA[
2010-05-12 03:30:53 +02:00
error = NULL;
res = dbus_g_proxy_call (system_bus_proxy,
"RequestName",
& error,
G_TYPE_STRING, NAME_TO_CLAIM,
G_TYPE_UINT, DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
G_TYPE_INVALID,
G_TYPE_UINT, & result,
G_TYPE_INVALID);
if (!res)
{
if (error != NULL)
{
g_warning ("Failed to acquire %s: %s",
NAME_TO_CLAIM, error->message);
g_error_free (error);
2010-05-11 23:15:11 +02:00
}
2010-05-12 03:30:53 +02:00
else
{
g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
}
goto out;
}
2010-05-11 23:15:11 +02:00
2010-05-12 03:30:53 +02:00
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);
2010-05-11 23:15:11 +02:00
}
2010-05-12 03:30:53 +02:00
exit (1);
}
2010-05-11 23:15:11 +02:00
2010-05-12 03:30:53 +02:00
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 ... */
2010-05-11 23:15:11 +02:00
]]>
</programlisting> </informalexample>
</para>
<para >
2010-05-12 03:30:53 +02:00
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:
<informalexample > <programlisting > < ![CDATA[
static void
on_name_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
/* further setup ... */
}
/* ... */
owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
NAME_TO_CLAIM,
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
on_bus_acquired,
on_name_acquired,
on_name_lost,
NULL,
NULL);
g_main_loop_run (loop);
g_bus_unown_name (owner_id);
]]>
2010-05-11 23:15:11 +02:00
</programlisting> </informalexample>
2010-05-12 03:30:53 +02:00
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 <emphasis > before</emphasis> acquiring the
name. The on_bus_acquired() callback is the right place to do
such preparations.
</para>
2010-05-11 23:15:11 +02:00
</section>
<section >
<title > Creating proxies for well-known names</title>
<para >
2010-05-12 04:00:06 +02:00
dbus-glib lets you create proxy objects for well-known names, like the
following example:
<informalexample > <programlisting > < ![CDATA[
proxy = dbus_g_proxy_new_for_name (system_bus_connection,
"org.freedesktop.Accounts",
"/org/freedesktop/Accounts",
"org.freedesktop.Accounts");
]]>
</programlisting> </informalexample>
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.
</para>
<para >
2010-06-11 21:45:18 +02:00
The same can be achieved with #GDBusProxy:
2010-05-12 04:00:06 +02:00
<informalexample > <programlisting > < ![CDATA[
2010-06-11 21:45:18 +02:00
error = NULL;
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL, /* GDBusInterfaceInfo */
"org.freedesktop.Accounts",
"/org/freedesktop/Accounts",
"org.freedesktop.Accounts",
NULL, /* GCancellable */
&error);
2010-05-12 04:00:06 +02:00
]]>
</programlisting> </informalexample>
2010-06-11 21:45:18 +02:00
For an added layer of safety, you can specify what D-Bus
interface the proxy is expected to conform to by using the
2011-04-12 00:32:11 +02:00
#GDBusInterfaceInfo type. Additionally, #GDBusProxy loads,
caches and tracks changes to the D-Bus properties on the remote
object. It also sets up match rules so D-Bus signals from the
remote object are delivered locally.
2010-06-11 21:45:18 +02:00
</para>
<para >
2011-04-12 00:32:11 +02:00
The #GDBusProxy type normally isn't used directly - instead
proxies subclassing #GDBusProxy generated by <command > <link
linkend="gdbus-codegen">gdbus-codegen</link> </command> is used, see <xref linkend= "gdbus-example-gdbus-codegen" />
2010-05-11 23:15:11 +02:00
</para>
2010-05-12 23:56:56 +02:00
</section>
2011-04-12 00:32:11 +02:00
2011-04-29 19:11:22 +02:00
<section >
<title > Generating code and docs</title>
2011-04-12 00:32:11 +02:00
<section id= "gdbus-example-gdbus-codegen" >
2011-04-12 17:50:34 +02:00
<title > Using gdbus-codegen</title>
2010-05-12 21:49:48 +02:00
2010-05-12 23:56:56 +02:00
<para >
dbus-glib comes with <command > dbus-binding-tool</command> , which
2011-04-12 00:32:11 +02:00
can produce somewhat nice client- and server-side wrappers for a D-Bus interface.
With GDBus, <command > <link
linkend="gdbus-codegen">gdbus-codegen</link> </command> is used and like
its counterpart, it also takes D-Bus Introspection XML as input:
2010-05-12 23:56:56 +02:00
</para>
2011-06-03 20:45:29 +02:00
<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</xi:fallback> </xi:include> </programlisting> </example>
2010-05-12 21:49:48 +02:00
<para >
2011-04-12 00:32:11 +02:00
If this XML is processed like this
<informalexample > <programlisting > < ![CDATA[
2011-04-12 17:50:34 +02:00
gdbus-codegen --interface-prefix org.gtk.GDBus.Example.ObjectManager. \
2011-04-12 00:32:11 +02:00
--generate-c-code generated-code \
2011-04-12 17:50:34 +02:00
--c-namespace Example \
--c-generate-object-manager \
2011-04-12 00:32:11 +02:00
--generate-docbook generated-docs \
gdbus-example-objectmanager.xml
]]></programlisting> </informalexample>
then two files <filename > generated-code.h</filename> and
<filename > generated-code.c</filename> are
2011-04-12 15:28:09 +02:00
generated. Additionally, two XML files
<filename > generated-docs-org.gtk.GDBus.Example.ObjectManager.Animal</filename> and
<filename > generated-docs-org.gtk.GDBus.Example.ObjectManager.Cat</filename>
with Docbook XML are generated. For an example of what the docs look
2011-04-12 00:32:11 +02:00
like see <link
2011-04-12 15:28:09 +02:00
linkend="gdbus-interface-org-gtk-GDBus-Example-ObjectManager-Animal">the Animal D-Bus interface documentation</link> .
and
<link
linkend="gdbus-interface-org-gtk-GDBus-Example-ObjectManager-Cat">the Cat D-Bus interface documentation</link> .
2010-05-12 21:49:48 +02:00
</para>
2010-05-13 07:04:29 +02:00
<para >
2011-04-12 00:32:11 +02:00
While the contents of <filename > generated-code.h</filename> and
<filename > generated-code.c</filename> are best described by the
<command > <link
linkend="gdbus-codegen">gdbus-codegen</link> </command> manual
page, brief examples of how this generated code can be used can be found in
<xref linkend= "gdbus-example-codegen-server" />
2011-04-23 23:43:03 +02:00
and <xref
linkend="gdbus-example-codegen-client"/>. Additionally, since
the generated code has 100% gtk-doc coverage, see
2011-04-25 15:29:18 +02:00
#ExampleAnimal, #ExampleCat, #ExampleObject and
#ExampleObjectManagerClient pages for documentation.
2010-05-13 07:04:29 +02:00
</para>
2011-04-12 00:32:11 +02:00
<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</xi:fallback> </xi:include> </programlisting> </example>
2010-05-13 07:04:29 +02:00
2011-04-12 00:32:11 +02:00
<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</xi:fallback> </xi:include> </programlisting> </example>
2010-05-13 07:04:29 +02:00
2010-05-12 18:13:57 +02:00
</section>
2011-06-03 19:22:31 +02:00
<xi:include href= "../../../../gio/tests/gdbus-object-manager-example/gdbus-example-objectmanager-generated-org.gtk.GDBus.Example.ObjectManager.Animal.xml" />
<xi:include href= "../../../../gio/tests/gdbus-object-manager-example/gdbus-example-objectmanager-generated-org.gtk.GDBus.Example.ObjectManager.Cat.xml" />
<xi:include href= "../gdbus-object-manager-example/xml/ExampleAnimal.xml" />
<xi:include href= "../gdbus-object-manager-example/xml/ExampleCat.xml" />
<xi:include href= "../gdbus-object-manager-example/xml/ExampleObject.xml" />
<xi:include href= "../gdbus-object-manager-example/xml/ExampleObjectManagerClient.xml" />
2011-04-12 00:32:11 +02:00
2011-04-29 19:11:22 +02:00
</section>
2010-05-06 23:52:54 +02:00
</chapter>