dbus-tutorial: replace the entire GLib section with "use GDBus"

Also provide links to relevant GLib and Qt documentation.

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=25140
This commit is contained in:
Simon McVittie 2014-09-10 13:53:39 +01:00
parent 2e4d069ac4
commit acec88f32a

View file

@ -704,939 +704,19 @@
</sect1>
<sect1 id="glib-client">
<title>GLib API: Using Remote Objects</title>
<title>GLib APIs</title>
<para>
The recommended GLib API for D-Bus is GDBus, which has been
distributed with GLib since version 2.26. It is not documented here.
See <ulink url="https://developer.gnome.org/gio/stable/gdbus-convenience.html">the
GLib documentation</ulink> for details of how to use GDBus.
</para>
<para>
The GLib binding is defined in the header file
<literal>&lt;dbus/dbus-glib.h&gt;</literal>.
An older API, dbus-glib, also exists. It is deprecated and should
not be used in new code. Whenever possible, porting existing code
from dbus-glib to GDBus is also recommended.
</para>
<sect2 id="glib-typemappings">
<title>D-Bus - GLib type mappings</title>
<para>
The heart of the GLib bindings for D-Bus is the mapping it
provides between D-Bus "type signatures" and GLib types
(<literal>GType</literal>). The D-Bus type system is composed of
a number of "basic" types, along with several "container" types.
</para>
<sect3 id="glib-basic-typemappings">
<title>Basic type mappings</title>
<para>
Below is a list of the basic types, along with their associated
mapping to a <literal>GType</literal>.
<informaltable>
<tgroup cols="4">
<thead>
<row>
<entry>D-Bus basic type</entry>
<entry>GType</entry>
<entry>Free function</entry>
<entry>Notes</entry>
</row>
</thead>
<tbody>
<row>
<entry><literal>BYTE</literal></entry>
<entry><literal>G_TYPE_UCHAR</literal></entry>
<entry></entry>
<entry></entry>
</row><row>
<entry><literal>BOOLEAN</literal></entry>
<entry><literal>G_TYPE_BOOLEAN</literal></entry>
<entry></entry>
<entry></entry>
</row><row>
<entry><literal>INT16</literal></entry>
<entry><literal>G_TYPE_INT</literal></entry>
<entry></entry>
<entry>Will be changed to a <literal>G_TYPE_INT16</literal> once GLib has it</entry>
</row><row>
<entry><literal>UINT16</literal></entry>
<entry><literal>G_TYPE_UINT</literal></entry>
<entry></entry>
<entry>Will be changed to a <literal>G_TYPE_UINT16</literal> once GLib has it</entry>
</row><row>
<entry><literal>INT32</literal></entry>
<entry><literal>G_TYPE_INT</literal></entry>
<entry></entry>
<entry>Will be changed to a <literal>G_TYPE_INT32</literal> once GLib has it</entry>
</row><row>
<entry><literal>UINT32</literal></entry>
<entry><literal>G_TYPE_UINT</literal></entry>
<entry></entry>
<entry>Will be changed to a <literal>G_TYPE_UINT32</literal> once GLib has it</entry>
</row><row>
<entry><literal>INT64</literal></entry>
<entry><literal>G_TYPE_GINT64</literal></entry>
<entry></entry>
<entry></entry>
</row><row>
<entry><literal>UINT64</literal></entry>
<entry><literal>G_TYPE_GUINT64</literal></entry>
<entry></entry>
<entry></entry>
</row><row>
<entry><literal>DOUBLE</literal></entry>
<entry><literal>G_TYPE_DOUBLE</literal></entry>
<entry></entry>
<entry></entry>
</row><row>
<entry><literal>STRING</literal></entry>
<entry><literal>G_TYPE_STRING</literal></entry>
<entry><literal>g_free</literal></entry>
<entry></entry>
</row><row>
<entry><literal>OBJECT_PATH</literal></entry>
<entry><literal>DBUS_TYPE_G_PROXY</literal></entry>
<entry><literal>g_object_unref</literal></entry>
<entry>The returned proxy does not have an interface set; use <literal>dbus_g_proxy_set_interface</literal> to invoke methods</entry>
</row>
</tbody>
</tgroup>
</informaltable>
As you can see, the basic mapping is fairly straightforward.
</para>
</sect3>
<sect3 id="glib-container-typemappings">
<title>Container type mappings</title>
<para>
The D-Bus type system also has a number of "container"
types, such as <literal>DBUS_TYPE_ARRAY</literal> and
<literal>DBUS_TYPE_STRUCT</literal>. The D-Bus type system
is fully recursive, so one can for example have an array of
array of strings (i.e. type signature
<literal>aas</literal>).
</para>
<para>
However, not all of these types are in common use; for
example, at the time of this writing the author knows of no
one using <literal>DBUS_TYPE_STRUCT</literal>, or a
<literal>DBUS_TYPE_ARRAY</literal> containing any non-basic
type. The approach the GLib bindings take is pragmatic; try
to map the most common types in the most obvious way, and
let using less common and more complex types be less
"natural".
</para>
<para>
First, D-Bus type signatures which have an "obvious"
corresponding built-in GLib type are mapped using that type:
<informaltable>
<tgroup cols="6">
<thead>
<row>
<entry>D-Bus type signature</entry>
<entry>Description</entry>
<entry>GType</entry>
<entry>C typedef</entry>
<entry>Free function</entry>
<entry>Notes</entry>
</row>
</thead>
<tbody>
<row>
<entry><literal>as</literal></entry>
<entry>Array of strings</entry>
<entry><literal>G_TYPE_STRV</literal></entry>
<entry><literal>char **</literal></entry>
<entry><literal>g_strfreev</literal></entry>
<entry></entry>
</row><row>
<entry><literal>v</literal></entry>
<entry>Generic value container</entry>
<entry><literal>G_TYPE_VALUE</literal></entry>
<entry><literal>GValue *</literal></entry>
<entry><literal>g_value_unset</literal></entry>
<entry>The calling conventions for values expect that method callers have allocated return values; see below.</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>
The next most common recursive type signatures are arrays of
basic values. The most obvious mapping for arrays of basic
types is a <literal>GArray</literal>. Now, GLib does not
provide a builtin <literal>GType</literal> for
<literal>GArray</literal>. However, we actually need more than
that - we need a "parameterized" type which includes the
contained type. Why we need this we will see below.
</para>
<para>
The approach taken is to create these types in the D-Bus GLib
bindings; however, there is nothing D-Bus specific about them.
In the future, we hope to include such "fundamental" types in GLib
itself.
<informaltable>
<tgroup cols="6">
<thead>
<row>
<entry>D-Bus type signature</entry>
<entry>Description</entry>
<entry>GType</entry>
<entry>C typedef</entry>
<entry>Free function</entry>
<entry>Notes</entry>
</row>
</thead>
<tbody>
<row>
<entry><literal>ay</literal></entry>
<entry>Array of bytes</entry>
<entry><literal>DBUS_TYPE_G_UCHAR_ARRAY</literal></entry>
<entry><literal>GArray *</literal></entry>
<entry>g_array_free</entry>
<entry></entry>
</row>
<row>
<entry><literal>au</literal></entry>
<entry>Array of uint</entry>
<entry><literal>DBUS_TYPE_G_UINT_ARRAY</literal></entry>
<entry><literal>GArray *</literal></entry>
<entry>g_array_free</entry>
<entry></entry>
</row>
<row>
<entry><literal>ai</literal></entry>
<entry>Array of int</entry>
<entry><literal>DBUS_TYPE_G_INT_ARRAY</literal></entry>
<entry><literal>GArray *</literal></entry>
<entry>g_array_free</entry>
<entry></entry>
</row>
<row>
<entry><literal>ax</literal></entry>
<entry>Array of int64</entry>
<entry><literal>DBUS_TYPE_G_INT64_ARRAY</literal></entry>
<entry><literal>GArray *</literal></entry>
<entry>g_array_free</entry>
<entry></entry>
</row>
<row>
<entry><literal>at</literal></entry>
<entry>Array of uint64</entry>
<entry><literal>DBUS_TYPE_G_UINT64_ARRAY</literal></entry>
<entry><literal>GArray *</literal></entry>
<entry>g_array_free</entry>
<entry></entry>
</row>
<row>
<entry><literal>ad</literal></entry>
<entry>Array of double</entry>
<entry><literal>DBUS_TYPE_G_DOUBLE_ARRAY</literal></entry>
<entry><literal>GArray *</literal></entry>
<entry>g_array_free</entry>
<entry></entry>
</row>
<row>
<entry><literal>ab</literal></entry>
<entry>Array of boolean</entry>
<entry><literal>DBUS_TYPE_G_BOOLEAN_ARRAY</literal></entry>
<entry><literal>GArray *</literal></entry>
<entry>g_array_free</entry>
<entry></entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>
D-Bus also includes a special type DBUS_TYPE_DICT_ENTRY which
is only valid in arrays. It's intended to be mapped to a "dictionary"
type by bindings. The obvious GLib mapping here is GHashTable. Again,
however, there is no builtin <literal>GType</literal> for a GHashTable.
Moreover, just like for arrays, we need a parameterized type so that
the bindings can communiate which types are contained in the hash table.
</para>
<para>
At present, only strings are supported. Work is in progress to
include more types.
<informaltable>
<tgroup cols="6">
<thead>
<row>
<entry>D-Bus type signature</entry>
<entry>Description</entry>
<entry>GType</entry>
<entry>C typedef</entry>
<entry>Free function</entry>
<entry>Notes</entry>
</row>
</thead>
<tbody>
<row>
<entry><literal>a{ss}</literal></entry>
<entry>Dictionary mapping strings to strings</entry>
<entry><literal>DBUS_TYPE_G_STRING_STRING_HASHTABLE</literal></entry>
<entry><literal>GHashTable *</literal></entry>
<entry>g_hash_table_destroy</entry>
<entry></entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
</sect3>
<sect3 id="glib-generic-typemappings">
<title>Arbitrarily recursive type mappings</title>
<para>
Finally, it is possible users will want to write or invoke D-Bus
methods which have arbitrarily complex type signatures not
directly supported by these bindings. For this case, we have a
<literal>DBusGValue</literal> which acts as a kind of special
variant value which may be iterated over manually. The
<literal>GType</literal> associated is
<literal>DBUS_TYPE_G_VALUE</literal>.
</para>
<para>
TODO insert usage of <literal>DBUS_TYPE_G_VALUE</literal> here.
</para>
</sect3>
</sect2>
<sect2 id="sample-program-1">
<title>A sample program</title>
<para>Here is a D-Bus program using the GLib bindings.
<programlisting>
int
main (int argc, char **argv)
{
DBusGConnection *connection;
GError *error;
DBusGProxy *proxy;
char **name_list;
char **name_list_ptr;
g_type_init ();
error = NULL;
connection = dbus_g_bus_get (DBUS_BUS_SESSION,
&amp;error);
if (connection == NULL)
{
g_printerr ("Failed to open connection to bus: %s\n",
error-&gt;message);
g_error_free (error);
exit (1);
}
/* Create a proxy object for the "bus driver" (name "org.freedesktop.DBus") */
proxy = dbus_g_proxy_new_for_name (connection,
DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS);
/* Call ListNames method, wait for reply */
error = NULL;
if (!dbus_g_proxy_call (proxy, "ListNames", &amp;error, G_TYPE_INVALID,
G_TYPE_STRV, &amp;name_list, G_TYPE_INVALID))
{
/* Just do demonstrate remote exceptions versus regular GError */
if (error->domain == DBUS_GERROR &amp;&amp; error->code == DBUS_GERROR_REMOTE_EXCEPTION)
g_printerr ("Caught remote method exception %s: %s",
dbus_g_error_get_name (error),
error-&gt;message);
else
g_printerr ("Error: %s\n", error-&gt;message);
g_error_free (error);
exit (1);
}
/* Print the results */
g_print ("Names on the message bus:\n");
for (name_list_ptr = name_list; *name_list_ptr; name_list_ptr++)
{
g_print (" %s\n", *name_list_ptr);
}
g_strfreev (name_list);
g_object_unref (proxy);
return 0;
}
</programlisting>
</para>
</sect2>
<sect2 id="glib-program-setup">
<title>Program initalization</title>
<para>
A connection to the bus is acquired using
<literal>dbus_g_bus_get</literal>. Next, a proxy
is created for the object "/org/freedesktop/DBus" with
interface <literal>org.freedesktop.DBus</literal>
on the service <literal>org.freedesktop.DBus</literal>.
This is a proxy for the message bus itself.
</para>
</sect2>
<sect2 id="glib-method-invocation">
<title>Understanding method invocation</title>
<para>
You have a number of choices for method invocation. First, as
used above, <literal>dbus_g_proxy_call</literal> sends a
method call to the remote object, and blocks until a reply is
recieved. The outgoing arguments are specified in the varargs
array, terminated with <literal>G_TYPE_INVALID</literal>.
Next, pointers to return values are specified, followed again
by <literal>G_TYPE_INVALID</literal>.
</para>
<para>
To invoke a method asynchronously, use
<literal>dbus_g_proxy_begin_call</literal>. This returns a
<literal>DBusGPendingCall</literal> object; you may then set a
notification function using
<literal>dbus_g_pending_call_set_notify</literal>.
</para>
</sect2>
<sect2 id="glib-signal-connection">
<title>Connecting to object signals</title>
<para>
You may connect to signals using
<literal>dbus_g_proxy_add_signal</literal> and
<literal>dbus_g_proxy_connect_signal</literal>. You must
invoke <literal>dbus_g_proxy_add_signal</literal> to specify
the signature of your signal handlers; you may then invoke
<literal>dbus_g_proxy_connect_signal</literal> multiple times.
</para>
<para>
Note that it will often be the case that there is no builtin
marshaller for the type signature of a remote signal. In that
case, you must generate a marshaller yourself by using
<application>glib-genmarshal</application>, and then register
it using <literal>dbus_g_object_register_marshaller</literal>.
</para>
</sect2>
<sect2 id="glib-error-handling">
<title>Error handling and remote exceptions</title>
<para>
All of the GLib binding methods such as
<literal>dbus_g_proxy_end_call</literal> return a
<literal>GError</literal>. This <literal>GError</literal> can
represent two different things:
<itemizedlist>
<listitem>
<para>
An internal D-Bus error, such as an out-of-memory
condition, an I/O error, or a network timeout. Errors
generated by the D-Bus library itself have the domain
<literal>DBUS_GERROR</literal>, and a corresponding code
such as <literal>DBUS_GERROR_NO_MEMORY</literal>. It will
not be typical for applications to handle these errors
specifically.
</para>
</listitem>
<listitem>
<para>
A remote D-Bus exception, thrown by the peer, bus, or
service. D-Bus remote exceptions have both a textual
"name" and a "message". The GLib bindings store this
information in the <literal>GError</literal>, but some
special rules apply.
</para>
<para>
The set error will have the domain
<literal>DBUS_GERROR</literal> as above, and will also
have the code
<literal>DBUS_GERROR_REMOTE_EXCEPTION</literal>. In order
to access the remote exception name, you must use a
special accessor, such as
<literal>dbus_g_error_has_name</literal> or
<literal>dbus_g_error_get_name</literal>. The remote
exception detailed message is accessible via the regular
GError <literal>message</literal> member.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
<sect2 id="glib-more-examples">
<title>More examples of method invocation</title>
<sect3 id="glib-sending-stuff">
<title>Sending an integer and string, receiving an array of bytes</title>
<para>
<programlisting>
GArray *arr;
error = NULL;
if (!dbus_g_proxy_call (proxy, "Foobar", &amp;error,
G_TYPE_INT, 42, G_TYPE_STRING, "hello",
G_TYPE_INVALID,
DBUS_TYPE_G_UCHAR_ARRAY, &amp;arr, G_TYPE_INVALID))
{
/* Handle error */
}
g_assert (arr != NULL);
printf ("got back %u values", arr->len);
</programlisting>
</para>
</sect3>
<sect3 id="glib-sending-hash">
<title>Sending a GHashTable</title>
<para>
<programlisting>
GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal);
guint32 ret;
g_hash_table_insert (hash, "foo", "bar");
g_hash_table_insert (hash, "baz", "whee");
error = NULL;
if (!dbus_g_proxy_call (proxy, "HashSize", &amp;error,
DBUS_TYPE_G_STRING_STRING_HASH, hash, G_TYPE_INVALID,
G_TYPE_UINT, &amp;ret, G_TYPE_INVALID))
{
/* Handle error */
}
g_assert (ret == 2);
g_hash_table_destroy (hash);
</programlisting>
</para>
</sect3>
<sect3 id="glib-receiving-bool-int">
<title>Receiving a boolean and a string</title>
<para>
<programlisting>
gboolean boolret;
char *strret;
error = NULL;
if (!dbus_g_proxy_call (proxy, "GetStuff", &amp;error,
G_TYPE_INVALID,
G_TYPE_BOOLEAN, &amp;boolret,
G_TYPE_STRING, &amp;strret,
G_TYPE_INVALID))
{
/* Handle error */
}
printf ("%s %s", boolret ? "TRUE" : "FALSE", strret);
g_free (strret);
</programlisting>
</para>
</sect3>
<sect3 id="glib-sending-str-arrays">
<title>Sending two arrays of strings</title>
<para>
<programlisting>
/* NULL terminate */
char *strs_static[] = {"foo", "bar", "baz", NULL};
/* Take pointer to array; cannot pass array directly */
char **strs_static_p = strs_static;
char **strs_dynamic;
strs_dynamic = g_new (char *, 4);
strs_dynamic[0] = g_strdup ("hello");
strs_dynamic[1] = g_strdup ("world");
strs_dynamic[2] = g_strdup ("!");
/* NULL terminate */
strs_dynamic[3] = NULL;
error = NULL;
if (!dbus_g_proxy_call (proxy, "TwoStrArrays", &amp;error,
G_TYPE_STRV, strs_static_p,
G_TYPE_STRV, strs_dynamic,
G_TYPE_INVALID,
G_TYPE_INVALID))
{
/* Handle error */
}
g_strfreev (strs_dynamic);
</programlisting>
</para>
</sect3>
<sect3 id="glib-getting-str-array">
<title>Sending a boolean, receiving an array of strings</title>
<para>
<programlisting>
char **strs;
char **strs_p;
gboolean blah;
error = NULL;
blah = TRUE;
if (!dbus_g_proxy_call (proxy, "GetStrs", &amp;error,
G_TYPE_BOOLEAN, blah,
G_TYPE_INVALID,
G_TYPE_STRV, &amp;strs,
G_TYPE_INVALID))
{
/* Handle error */
}
for (strs_p = strs; *strs_p; strs_p++)
printf ("got string: \"%s\"", *strs_p);
g_strfreev (strs);
</programlisting>
</para>
</sect3>
<sect3 id="glib-sending-variant">
<title>Sending a variant</title>
<para>
<programlisting>
GValue val = {0, };
g_value_init (&amp;val, G_TYPE_STRING);
g_value_set_string (&amp;val, "hello world");
error = NULL;
if (!dbus_g_proxy_call (proxy, "SendVariant", &amp;error,
G_TYPE_VALUE, &amp;val, G_TYPE_INVALID,
G_TYPE_INVALID))
{
/* Handle error */
}
g_assert (ret == 2);
g_value_unset (&amp;val);
</programlisting>
</para>
</sect3>
<sect3 id="glib-receiving-variant">
<title>Receiving a variant</title>
<para>
<programlisting>
GValue val = {0, };
error = NULL;
if (!dbus_g_proxy_call (proxy, "GetVariant", &amp;error, G_TYPE_INVALID,
G_TYPE_VALUE, &amp;val, G_TYPE_INVALID))
{
/* Handle error */
}
if (G_VALUE_TYPE (&amp;val) == G_TYPE_STRING)
printf ("%s\n", g_value_get_string (&amp;val));
else if (G_VALUE_TYPE (&amp;val) == G_TYPE_INT)
printf ("%d\n", g_value_get_int (&amp;val));
else
...
g_value_unset (&amp;val);
</programlisting>
</para>
</sect3>
</sect2>
<sect2 id="glib-generated-bindings">
<title>Generated Bindings</title>
<para>
By using the Introspection XML files, convenient client-side bindings
can be automatically created to ease the use of a remote DBus object.
</para>
<para>
Here is a sample XML file which describes an object that exposes
one method, named <literal>ManyArgs</literal>.
<programlisting>
&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;node name="/com/example/MyObject"&gt;
&lt;interface name="com.example.MyObject"&gt;
&lt;method name="ManyArgs"&gt;
&lt;arg type="u" name="x" direction="in" /&gt;
&lt;arg type="s" name="str" direction="in" /&gt;
&lt;arg type="d" name="trouble" direction="in" /&gt;
&lt;arg type="d" name="d_ret" direction="out" /&gt;
&lt;arg type="s" name="str_ret" direction="out" /&gt;
&lt;/method&gt;
&lt;/interface&gt;
&lt;/node&gt;
</programlisting>
</para>
<para>
Run <literal>dbus-binding-tool --mode=glib-client
<replaceable>FILENAME</replaceable> &gt;
<replaceable>HEADER_NAME</replaceable></literal> to generate the header
file. For example: <command>dbus-binding-tool --mode=glib-client
my-object.xml &gt; my-object-bindings.h</command>. This will generate
inline functions with the following prototypes:
<programlisting>
/* This is a blocking call */
gboolean
com_example_MyObject_many_args (DBusGProxy *proxy, const guint IN_x,
const char * IN_str, const gdouble IN_trouble,
gdouble* OUT_d_ret, char ** OUT_str_ret,
GError **error);
/* This is a non-blocking call */
DBusGProxyCall*
com_example_MyObject_many_args_async (DBusGProxy *proxy, const guint IN_x,
const char * IN_str, const gdouble IN_trouble,
com_example_MyObject_many_args_reply callback,
gpointer userdata);
/* This is the typedef for the non-blocking callback */
typedef void
(*com_example_MyObject_many_args_reply)
(DBusGProxy *proxy, gdouble OUT_d_ret, char * OUT_str_ret,
GError *error, gpointer userdata);
</programlisting>
The first argument in all functions is a <literal>DBusGProxy
*</literal>, which you should create with the usual
<literal>dbus_g_proxy_new_*</literal> functions. Following that are the
"in" arguments, and then either the "out" arguments and a
<literal>GError *</literal> for the synchronous (blocking) function, or
callback and user data arguments for the asynchronous (non-blocking)
function. The callback in the asynchronous function passes the
<literal>DBusGProxy *</literal>, the returned "out" arguments, an
<literal>GError *</literal> which is set if there was an error otherwise
<literal>NULL</literal>, and the user data.
</para>
<para>
As with the server-side bindings support (see <xref
linkend="glib-server"/>), the exact behaviour of the client-side
bindings can be manipulated using "annotations". Currently the only
annotation used by the client bindings is
<literal>org.freedesktop.DBus.GLib.NoReply</literal>, which sets the
flag indicating that the client isn't expecting a reply to the method
call, so a reply shouldn't be sent. This is often used to speed up
rapid method calls where there are no "out" arguments, and not knowing
if the method succeeded is an acceptable compromise to half the traffic
on the bus.
</para>
</sect2>
</sect1>
<sect1 id="glib-server">
<title>GLib API: Implementing Objects</title>
<para>
At the moment, to expose a GObject via D-Bus, you must
write XML by hand which describes the methods exported
by the object. In the future, this manual step will
be obviated by the upcoming GLib introspection support.
</para>
<para>
Here is a sample XML file which describes an object that exposes
one method, named <literal>ManyArgs</literal>.
<programlisting>
&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;node name="/com/example/MyObject"&gt;
&lt;interface name="com.example.MyObject"&gt;
&lt;annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object"/&gt;
&lt;method name="ManyArgs"&gt;
&lt;!-- This is optional, and in this case is redunundant --&gt;
&lt;annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_many_args"/&gt;
&lt;arg type="u" name="x" direction="in" /&gt;
&lt;arg type="s" name="str" direction="in" /&gt;
&lt;arg type="d" name="trouble" direction="in" /&gt;
&lt;arg type="d" name="d_ret" direction="out" /&gt;
&lt;arg type="s" name="str_ret" direction="out" /&gt;
&lt;/method&gt;
&lt;/interface&gt;
&lt;/node&gt;
</programlisting>
</para>
<para>
This XML is in the same format as the D-Bus introspection XML
format. Except we must include an "annotation" which give the C
symbols corresponding to the object implementation prefix
(<literal>my_object</literal>). In addition, if particular
methods symbol names deviate from C convention
(i.e. <literal>ManyArgs</literal> -&gt;
<literal>many_args</literal>), you may specify an annotation
giving the C symbol.
</para>
<para>
Once you have written this XML, run <literal>dbus-binding-tool --mode=glib-server <replaceable>FILENAME</replaceable> &gt; <replaceable>HEADER_NAME</replaceable>.</literal> to
generate a header file. For example: <command>dbus-binding-tool --mode=glib-server my-object.xml &gt; my-object-glue.h</command>.
</para>
<para>
Next, include the generated header in your program, and invoke
<literal>dbus_g_object_class_install_info</literal> in the class
initializer, passing the object class and "object info" included in the
header. For example:
<programlisting>
dbus_g_object_type_install_info (COM_FOO_TYPE_MY_OBJECT, &amp;com_foo_my_object_info);
</programlisting>
This should be done exactly once per object class.
</para>
<para>
To actually implement the method, just define a C function named e.g.
<literal>my_object_many_args</literal> in the same file as the info
header is included. At the moment, it is required that this function
conform to the following rules:
<itemizedlist>
<listitem>
<para>
The function must return a value of type <literal>gboolean</literal>;
<literal>TRUE</literal> on success, and <literal>FALSE</literal>
otherwise.
</para>
</listitem>
<listitem>
<para>
The first parameter is a pointer to an instance of the object.
</para>
</listitem>
<listitem>
<para>
Following the object instance pointer are the method
input values.
</para>
</listitem>
<listitem>
<para>
Following the input values are pointers to return values.
</para>
</listitem>
<listitem>
<para>
The final parameter must be a <literal>GError **</literal>.
If the function returns <literal>FALSE</literal> for an
error, the error parameter must be initalized with
<literal>g_set_error</literal>.
</para>
</listitem>
</itemizedlist>
</para>
<para>
Finally, you can export an object using <literal>dbus_g_connection_register_g_object</literal>. For example:
<programlisting>
dbus_g_connection_register_g_object (connection,
"/com/foo/MyObject",
obj);
</programlisting>
</para>
<sect2 id="glib-annotations">
<title>Server-side Annotations</title>
<para>
There are several annotations that are used when generating the
server-side bindings. The most common annotation is
<literal>org.freedesktop.DBus.GLib.CSymbol</literal> but there are other
annotations which are often useful.
<variablelist>
<varlistentry>
<term><literal>org.freedesktop.DBus.GLib.CSymbol</literal></term>
<listitem>
<para>
This annotation is used to specify the C symbol names for
the various types (interface, method, etc), if it differs from the
name DBus generates.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>org.freedesktop.DBus.GLib.Async</literal></term>
<listitem>
<para>
This annotation marks the method implementation as an
asynchronous function, which doesn't return a response straight
away but will send the response at some later point to complete
the call. This is used to implement non-blocking services where
method calls can take time.
</para>
<para>
When a method is asynchronous, the function prototype is
different. It is required that the function conform to the
following rules:
<itemizedlist>
<listitem>
<para>
The function must return a value of type <literal>gboolean</literal>;
<literal>TRUE</literal> on success, and <literal>FALSE</literal>
otherwise. TODO: the return value is currently ignored.
</para>
</listitem>
<listitem>
<para>
The first parameter is a pointer to an instance of the object.
</para>
</listitem>
<listitem>
<para>
Following the object instance pointer are the method
input values.
</para>
</listitem>
<listitem>
<para>
The final parameter must be a
<literal>DBusGMethodInvocation *</literal>. This is used
when sending the response message back to the client, by
calling <literal>dbus_g_method_return</literal> or
<literal>dbus_g_method_return_error</literal>.
</para>
</listitem>
</itemizedlist>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>org.freedesktop.DBus.GLib.Const</literal></term>
<listitem>
<para>This attribute can only be applied to "out"
<literal>&lt;arg&gt;</literal> nodes, and specifies that the
parameter isn't being copied when returned. For example, this
turns a 's' argument from a <literal>char **</literal> to a
<literal>const char **</literal>, and results in the argument not
being freed by DBus after the message is sent.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>org.freedesktop.DBus.GLib.ReturnVal</literal></term>
<listitem>
<para>
This attribute can only be applied to "out"
<literal>&lt;arg&gt;</literal> nodes, and alters the expected
function signature. It currently can be set to two values:
<literal>""</literal> or <literal>"error"</literal>. The
argument marked with this attribute is not returned via a
pointer argument, but by the function's return value. If the
attribute's value is the empty string, the <literal>GError
*</literal> argument is also omitted so there is no standard way
to return an error value. This is very useful for interfacing
with existing code, as it is possible to match existing APIs.
If the attribute's value is <literal>"error"</literal>, then the
final argument is a <literal>GError *</literal> as usual.
</para>
<para>
Some examples to demonstrate the usage. This introspection XML:
<programlisting>
&lt;method name="Increment"&gt;
&lt;arg type="u" name="x" /&gt;
&lt;arg type="u" direction="out" /&gt;
&lt;/method&gt;
</programlisting>
Expects the following function declaration:
<programlisting>
gboolean
my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error);
</programlisting>
</para>
<para>
This introspection XML:
<programlisting>
&lt;method name="IncrementRetval"&gt;
&lt;arg type="u" name="x" /&gt;
&lt;arg type="u" direction="out" &gt;
&lt;annotation name="org.freedesktop.DBus.GLib.ReturnVal" value=""/&gt;
&lt;/arg&gt;
&lt;/method&gt;
</programlisting>
Expects the following function declaration:
<programlisting>
gint32
my_object_increment_retval (MyObject *obj, gint32 x)
</programlisting>
</para>
<para>
This introspection XML:
<programlisting>
&lt;method name="IncrementRetvalError"&gt;
&lt;arg type="u" name="x" /&gt;
&lt;arg type="u" direction="out" &gt;
&lt;annotation name="org.freedesktop.DBus.GLib.ReturnVal" value="error"/&gt;
&lt;/arg&gt;
&lt;/method&gt;
</programlisting>
Expects the following function declaration:
<programlisting>
gint32
my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error)
</programlisting>
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</sect2>
</sect1>
<sect1 id="python-client">
@ -1650,18 +730,12 @@ my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error)
</sect1>
<sect1 id="qt-client">
<title>Qt API: Using Remote Objects</title>
<title>Qt API</title>
<para>
The Qt bindings are not yet documented.
</para>
</sect1>
<sect1 id="qt-server">
<title>Qt API: Implementing Objects</title>
<para>
The Qt bindings are not yet documented.
The Qt binding for libdbus, QtDBus, has been distributed with Qt
since version 4.2. It is not documented here. See
<ulink url="http://qt-project.org/doc/qt-5/qtdbus-index.html">the Qt
documentation</ulink> for details of how to use QtDBus.
</para>
</sect1>
</article>