+ </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", &error,
+ G_TYPE_INT, 42, G_TYPE_STRING, "hello",
+ G_TYPE_INVALID,
+ DBUS_TYPE_G_UCHAR_ARRAY, &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", &error,
+ DBUS_TYPE_G_STRING_STRING_HASH, hash, G_TYPE_INVALID,
+ G_TYPE_UINT, &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", &error,
+ G_TYPE_INVALID,
+ G_TYPE_BOOLEAN, &boolret,
+ G_TYPE_STRING, &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", &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", &error,
+ G_TYPE_BOOLEAN, blah,
+ G_TYPE_INVALID,
+ G_TYPE_STRV, &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 (&val, G_TYPE_STRING);
+ g_value_set_string (&val, "hello world");
+
+ error = NULL;
+ if (!dbus_g_proxy_call (proxy, "SendVariant", &error,
+ G_TYPE_VALUE, &val, G_TYPE_INVALID,
+ G_TYPE_INVALID))
+ {
+ /* Handle error */
+ }
+ g_assert (ret == 2);
+ g_value_unset (&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", &error, G_TYPE_INVALID,
+ G_TYPE_VALUE, &val, G_TYPE_INVALID))
+ {
+ /* Handle error */
+ }
+ if (G_VALUE_TYPE (&val) == G_TYPE_STRING)
+ printf ("%s\n", g_value_get_string (&val));
+ else if (G_VALUE_TYPE (&val) == G_TYPE_INT)
+ printf ("%d\n", g_value_get_int (&val));
+ else
+ ...
+ g_value_unset (&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>
+<?xml version="1.0" encoding="UTF-8" ?>
+<node name="/com/example/MyObject">
+ <interface name="com.example.MyObject">
+ <method name="ManyArgs">
+ <arg type="u" name="x" direction="in" />
+ <arg type="s" name="str" direction="in" />
+ <arg type="d" name="trouble" direction="in" />
+ <arg type="d" name="d_ret" direction="out" />
+ <arg type="s" name="str_ret" direction="out" />
+ </method>
+ </interface>
+</node>
+</programlisting>
+ </para>
+ <para>
+ Run <literal>dbus-binding-tool --mode=glib-client
+ <replaceable>FILENAME</replaceable> >
+ <replaceable>HEADER_NAME</replaceable></literal> to generate the header
+ file. For example: <command>dbus-binding-tool --mode=glib-client
+ my-object.xml > 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>