From 19c9d4ed84bc8eba46642ed46c2d6127f4f5478a Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 10 Sep 2014 13:53:39 +0100 Subject: [PATCH] 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 --- doc/dbus-tutorial.xml | 952 +------------------------------------------------- 1 file changed, 13 insertions(+), 939 deletions(-) diff --git a/doc/dbus-tutorial.xml b/doc/dbus-tutorial.xml index 3d14e5f..c4d9504 100644 --- a/doc/dbus-tutorial.xml +++ b/doc/dbus-tutorial.xml @@ -704,939 +704,19 @@ - GLib API: Using Remote Objects - - - The GLib binding is defined in the header file - <dbus/dbus-glib.h>. - - - - D-Bus - GLib type mappings - - The heart of the GLib bindings for D-Bus is the mapping it - provides between D-Bus "type signatures" and GLib types - (GType). The D-Bus type system is composed of - a number of "basic" types, along with several "container" types. - - - Basic type mappings - - Below is a list of the basic types, along with their associated - mapping to a GType. - - - - - D-Bus basic type - GType - Free function - Notes - - - - - BYTE - G_TYPE_UCHAR - - - - BOOLEAN - G_TYPE_BOOLEAN - - - - INT16 - G_TYPE_INT - - Will be changed to a G_TYPE_INT16 once GLib has it - - UINT16 - G_TYPE_UINT - - Will be changed to a G_TYPE_UINT16 once GLib has it - - INT32 - G_TYPE_INT - - Will be changed to a G_TYPE_INT32 once GLib has it - - UINT32 - G_TYPE_UINT - - Will be changed to a G_TYPE_UINT32 once GLib has it - - INT64 - G_TYPE_GINT64 - - - - UINT64 - G_TYPE_GUINT64 - - - - DOUBLE - G_TYPE_DOUBLE - - - - STRING - G_TYPE_STRING - g_free - - - OBJECT_PATH - DBUS_TYPE_G_PROXY - g_object_unref - The returned proxy does not have an interface set; use dbus_g_proxy_set_interface to invoke methods - - - - - As you can see, the basic mapping is fairly straightforward. - - - - Container type mappings - - The D-Bus type system also has a number of "container" - types, such as DBUS_TYPE_ARRAY and - DBUS_TYPE_STRUCT. The D-Bus type system - is fully recursive, so one can for example have an array of - array of strings (i.e. type signature - aas). - - - 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 DBUS_TYPE_STRUCT, or a - DBUS_TYPE_ARRAY 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". - - - First, D-Bus type signatures which have an "obvious" - corresponding built-in GLib type are mapped using that type: - - - - - D-Bus type signature - Description - GType - C typedef - Free function - Notes - - - - - as - Array of strings - G_TYPE_STRV - char ** - g_strfreev - - - v - Generic value container - G_TYPE_VALUE - GValue * - g_value_unset - The calling conventions for values expect that method callers have allocated return values; see below. - - - - - - - The next most common recursive type signatures are arrays of - basic values. The most obvious mapping for arrays of basic - types is a GArray. Now, GLib does not - provide a builtin GType for - GArray. 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. - - - 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. - - - - - D-Bus type signature - Description - GType - C typedef - Free function - Notes - - - - - ay - Array of bytes - DBUS_TYPE_G_UCHAR_ARRAY - GArray * - g_array_free - - - - au - Array of uint - DBUS_TYPE_G_UINT_ARRAY - GArray * - g_array_free - - - - ai - Array of int - DBUS_TYPE_G_INT_ARRAY - GArray * - g_array_free - - - - ax - Array of int64 - DBUS_TYPE_G_INT64_ARRAY - GArray * - g_array_free - - - - at - Array of uint64 - DBUS_TYPE_G_UINT64_ARRAY - GArray * - g_array_free - - - - ad - Array of double - DBUS_TYPE_G_DOUBLE_ARRAY - GArray * - g_array_free - - - - ab - Array of boolean - DBUS_TYPE_G_BOOLEAN_ARRAY - GArray * - g_array_free - - - - - - - - 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 GType 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. - - - At present, only strings are supported. Work is in progress to - include more types. - - - - - D-Bus type signature - Description - GType - C typedef - Free function - Notes - - - - - a{ss} - Dictionary mapping strings to strings - DBUS_TYPE_G_STRING_STRING_HASHTABLE - GHashTable * - g_hash_table_destroy - - - - - - - - - Arbitrarily recursive type mappings - - 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 - DBusGValue which acts as a kind of special - variant value which may be iterated over manually. The - GType associated is - DBUS_TYPE_G_VALUE. - - - TODO insert usage of DBUS_TYPE_G_VALUE here. - - - - - A sample program - Here is a D-Bus program using the GLib bindings. - -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, - &error); - if (connection == NULL) - { - g_printerr ("Failed to open connection to bus: %s\n", - error->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", &error, G_TYPE_INVALID, - G_TYPE_STRV, &name_list, G_TYPE_INVALID)) - { - /* Just do demonstrate remote exceptions versus regular GError */ - if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) - g_printerr ("Caught remote method exception %s: %s", - dbus_g_error_get_name (error), - error->message); - else - g_printerr ("Error: %s\n", error->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; -} - - - - - Program initalization - - A connection to the bus is acquired using - dbus_g_bus_get. Next, a proxy - is created for the object "/org/freedesktop/DBus" with - interface org.freedesktop.DBus - on the service org.freedesktop.DBus. - This is a proxy for the message bus itself. - - - - Understanding method invocation - - You have a number of choices for method invocation. First, as - used above, dbus_g_proxy_call 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 G_TYPE_INVALID. - Next, pointers to return values are specified, followed again - by G_TYPE_INVALID. - - - To invoke a method asynchronously, use - dbus_g_proxy_begin_call. This returns a - DBusGPendingCall object; you may then set a - notification function using - dbus_g_pending_call_set_notify. - - - - Connecting to object signals - - You may connect to signals using - dbus_g_proxy_add_signal and - dbus_g_proxy_connect_signal. You must - invoke dbus_g_proxy_add_signal to specify - the signature of your signal handlers; you may then invoke - dbus_g_proxy_connect_signal multiple times. - - - 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 - glib-genmarshal, and then register - it using dbus_g_object_register_marshaller. - - - - Error handling and remote exceptions - - All of the GLib binding methods such as - dbus_g_proxy_end_call return a - GError. This GError can - represent two different things: - - - - 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 - DBUS_GERROR, and a corresponding code - such as DBUS_GERROR_NO_MEMORY. It will - not be typical for applications to handle these errors - specifically. - - - - - 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 GError, but some - special rules apply. - - - The set error will have the domain - DBUS_GERROR as above, and will also - have the code - DBUS_GERROR_REMOTE_EXCEPTION. In order - to access the remote exception name, you must use a - special accessor, such as - dbus_g_error_has_name or - dbus_g_error_get_name. The remote - exception detailed message is accessible via the regular - GError message member. - - - - - - - More examples of method invocation - - Sending an integer and string, receiving an array of bytes - - - 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); - - - - - Sending a GHashTable - - - 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); - - - - - Receiving a boolean and a string - - - 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); - - - - - Sending two arrays of strings - - - /* 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); - - - - - Sending a boolean, receiving an array of strings - - - 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); - - - - - Sending a variant - - - 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); - - - - - Receiving a variant - - - 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); - - - - - - - Generated Bindings - - By using the Introspection XML files, convenient client-side bindings - can be automatically created to ease the use of a remote DBus object. - - - Here is a sample XML file which describes an object that exposes - one method, named ManyArgs. - -<?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> - - - - Run dbus-binding-tool --mode=glib-client - FILENAME > - HEADER_NAME to generate the header - file. For example: dbus-binding-tool --mode=glib-client - my-object.xml > my-object-bindings.h. This will generate - inline functions with the following prototypes: - -/* 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); - - The first argument in all functions is a DBusGProxy - *, which you should create with the usual - dbus_g_proxy_new_* functions. Following that are the - "in" arguments, and then either the "out" arguments and a - GError * 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 - DBusGProxy *, the returned "out" arguments, an - GError * which is set if there was an error otherwise - NULL, and the user data. - - - As with the server-side bindings support (see ), the exact behaviour of the client-side - bindings can be manipulated using "annotations". Currently the only - annotation used by the client bindings is - org.freedesktop.DBus.GLib.NoReply, 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. - - - - - - GLib API: Implementing Objects + GLib APIs - 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. + 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 the + GLib documentation for details of how to use GDBus. - - Here is a sample XML file which describes an object that exposes - one method, named ManyArgs. - -<?xml version="1.0" encoding="UTF-8" ?> - -<node name="/com/example/MyObject"> - <interface name="com.example.MyObject"> - <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object"/> - <method name="ManyArgs"> - <!-- This is optional, and in this case is redunundant --> - <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_many_args"/> - <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> - - - 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 - (my_object). In addition, if particular - methods symbol names deviate from C convention - (i.e. ManyArgs -> - many_args), you may specify an annotation - giving the C symbol. + 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. - - Once you have written this XML, run dbus-binding-tool --mode=glib-server FILENAME > HEADER_NAME. to - generate a header file. For example: dbus-binding-tool --mode=glib-server my-object.xml > my-object-glue.h. - - - Next, include the generated header in your program, and invoke - dbus_g_object_class_install_info in the class - initializer, passing the object class and "object info" included in the - header. For example: - - dbus_g_object_type_install_info (COM_FOO_TYPE_MY_OBJECT, &com_foo_my_object_info); - - This should be done exactly once per object class. - - - To actually implement the method, just define a C function named e.g. - my_object_many_args in the same file as the info - header is included. At the moment, it is required that this function - conform to the following rules: - - - - The function must return a value of type gboolean; - TRUE on success, and FALSE - otherwise. - - - - - The first parameter is a pointer to an instance of the object. - - - - - Following the object instance pointer are the method - input values. - - - - - Following the input values are pointers to return values. - - - - - The final parameter must be a GError **. - If the function returns FALSE for an - error, the error parameter must be initalized with - g_set_error. - - - - - - Finally, you can export an object using dbus_g_connection_register_g_object. For example: - - dbus_g_connection_register_g_object (connection, - "/com/foo/MyObject", - obj); - - - - - Server-side Annotations - - There are several annotations that are used when generating the - server-side bindings. The most common annotation is - org.freedesktop.DBus.GLib.CSymbol but there are other - annotations which are often useful. - - - org.freedesktop.DBus.GLib.CSymbol - - - 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. - - - - - org.freedesktop.DBus.GLib.Async - - - 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. - - - When a method is asynchronous, the function prototype is - different. It is required that the function conform to the - following rules: - - - - The function must return a value of type gboolean; - TRUE on success, and FALSE - otherwise. TODO: the return value is currently ignored. - - - - - The first parameter is a pointer to an instance of the object. - - - - - Following the object instance pointer are the method - input values. - - - - - The final parameter must be a - DBusGMethodInvocation *. This is used - when sending the response message back to the client, by - calling dbus_g_method_return or - dbus_g_method_return_error. - - - - - - - - org.freedesktop.DBus.GLib.Const - - This attribute can only be applied to "out" - <arg> nodes, and specifies that the - parameter isn't being copied when returned. For example, this - turns a 's' argument from a char ** to a - const char **, and results in the argument not - being freed by DBus after the message is sent. - - - - - org.freedesktop.DBus.GLib.ReturnVal - - - This attribute can only be applied to "out" - <arg> nodes, and alters the expected - function signature. It currently can be set to two values: - "" or "error". 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 GError - * 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 "error", then the - final argument is a GError * as usual. - - - Some examples to demonstrate the usage. This introspection XML: - -<method name="Increment"> - <arg type="u" name="x" /> - <arg type="u" direction="out" /> -</method> - - Expects the following function declaration: - -gboolean -my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error); - - - - This introspection XML: - -<method name="IncrementRetval"> - <arg type="u" name="x" /> - <arg type="u" direction="out" > - <annotation name="org.freedesktop.DBus.GLib.ReturnVal" value=""/> - </arg> -</method> - - Expects the following function declaration: - -gint32 -my_object_increment_retval (MyObject *obj, gint32 x) - - - - This introspection XML: - -<method name="IncrementRetvalError"> - <arg type="u" name="x" /> - <arg type="u" direction="out" > - <annotation name="org.freedesktop.DBus.GLib.ReturnVal" value="error"/> - </arg> -</method> - - Expects the following function declaration: - -gint32 -my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error) - - - - - - - @@ -1650,18 +730,12 @@ my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error) - Qt API: Using Remote Objects - - - The Qt bindings are not yet documented. - - - - - - Qt API: Implementing Objects + Qt API - 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 + the Qt + documentation for details of how to use QtDBus. -- 2.1.0