dbus/doc dbus-tutorial.xml,1.10,1.11 TODO,1.77,1.78

Colin Walters walters at freedesktop.org
Sun Jun 12 20:01:28 PDT 2005


Update of /cvs/dbus/dbus/doc
In directory gabe:/tmp/cvs-serv11651/doc

Modified Files:
	dbus-tutorial.xml TODO 
Log Message:
2005-06-12  Colin Walters  <walters at verbum.org>

	Async signals and various bugfixes and testing by
	Ross Burton <ross at burtonini.com>.

	* glib/dbus-gvalue.h: (struct DBusBasicGValue): Delete.
	(dbus_gvalue_genmarshal_name_from_type)
	(dbus_gvalue_ctype_from_type): Moved to dbus-binding-tool-glib.c.
	(dbus_gtype_to_dbus_type): Renamed to dbus_gtype_from_signature.
	(dbus_g_value_types_init, dbus_gtype_from_signature)
	(dbus_gtype_from_signature_iter, dbus_gtype_to_signature)
	(dbus_gtypes_from_arg_signature): New function prototypes.
	(dbus_gvalue_demarshal): Take context and error arguments.
	(dbus_gvalue_demarshal_variant): New function.
	(dbus_gvalue_demarshal_message): New function.
	(dbus_gvalue_store): Delete.

	* glib/dbus-gvalue.c:

	File has been almost entirely rewritten; now we special-case
	more types such as DBUS_TYPE_SIGNATURE, handle arrays and
	hash tables correctly, etc.  Full support for recursive values
	is not yet complete.

	* glib/dbus-gproxy.c (dbus_g_proxy_class_init): Change last
	argument of signal to G_TYPE_POINTER since we now pass a
	structure.
	(lookup_g_marshaller): Delete in favor of
	_dbus_gobject_lookup_marshaller.
	(marshal_dbus_message_to_g_marshaller): Use
	_dbus_gobject_lookup_marshaller and dbus_gvalue_demarshal_message
	to handle remote signal callbacks.
	(dbus_g_proxy_new_from_proxy): New function; creates a new
	DBusGProxy by copying an existing one.
	(dbus_g_proxy_get_interface, dbus_g_proxy_set_interface)
	(dbus_g_proxy_get_path): New functions.
	(dbus_g_proxy_marshal_args_to_message): New function;
	factored out of existing code.
	(DBUS_G_VALUE_ARRAY_COLLECT_ALL): Collect all arguments
	from a varargs array.
	(dbus_g_proxy_begin_call_internal): New function.
	(dbus_g_proxy_end_call_internal): New function.
	(dbus_g_proxy_begin_call): Take GTypes instead of DBus types
	as arguments; simply invoke dbus_g_proxy_begin_call_internal
	after collecting args into value array.
	(dbus_g_proxy_end_call): Take GTypes instead of DBus types;
	invoke dbus_g_proxy_end_call_internal.
	(dbus_g_proxy_invoke): Simply invoke begin_call_interanl and
	end_call_internal.
	(dbus_g_proxy_call_no_reply): Take GTypes instead of DBus
	types.
	(array_free_all): New function.
	(dbus_g_proxy_add_signal): Take GTypes.

	* glib/dbus-gobject.h:
	(_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete.
	(_dbus_gobject_get_path, _dbus_gobject_lookup_marshaller):
	Prototype.

	* glib/dbus-gobject.c: Add a global marshal_table hash which
	stores mappings from type signatures to marshallers.  Change lots
	of invocations of dbus_gtype_to_dbus_type to
	dbus_gtype_to_signature.
	(_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete.
	(introspect_signals): Fix test for query.return_type.
	(set_object_property): Update invocation of dbus_gvalue_demarshal.
	(invoke_object_method): Many changes.  Handle asynchronous
	invocations.  Convert arguments with
	dbus_gvalue_demarshal_message.  Handle errors.  Use
	DBusSignatureIter instead of strlen on args. Handle all arguments
	generically.  Special-case variants.
	(dbus_g_method_return, dbus_g_method_return_error): New function.
	(DBusGSignalClosure): New structure, closes over signal
	information.
	(dbus_g_signal_closure_new): New function.
	(dbus_g_signal_closure_finalize): New function.
	(signal_emitter_marshaller): New function; is special marshaller
	which emits signals on bus.
	(export_signals): New function; introspects object signals and
	connects to them.
	(dbus_g_object_type_install_info): Take GType instead of
	GObjectClass.
	(dbus_g_connection_register_g_object): Invoke export_signals.
	(dbus_g_connection_lookup_g_object): New function.
	(DBusGFuncSignature) New structure; used for mapping type
	signatures to marshallers.
	(funcsig_hash): New function; hashes DBusGFuncSignature.
	(funcsig_equal): New function; compares DBusGFuncSignature.
	(_dbus_gobject_lookup_marshaller): New function.
	(dbus_g_object_register_marshaller): New function; used to
	register a marshaller at runtime for a particular signature.

	* glib/dbus-gmain.c (_dbus_gmain_test): Add various tests.

	* glib/dbus-binding-tool-glib.h: Add DBUS_GLIB_ANNOTATION_ASYNC
	which notes a server method implementation should be
	asynchronous.

	* glib/dbus-binding-tool-glib.c
	(dbus_binding_tool_output_glib_server): Call
	dbus_g_value_types_init.
	(write_formal_parameters): Use dbus_gtype_from_signature.  Handle
	variants specially.
	(dbus_g_type_get_lookup_function): Turn GType into an invocation
	of a lookup function.
	(write_args_for_direction): Use dbus_g_type_get_lookup_function.
	(write_untyped_out_args): New method; write output arguments.
	(write_formal_declarations_for_direction): Function for
	writing prototypes.
	(write_formal_parameters_for_direction): Function for
	writing implementations.
	(write_typed_args_for_direction): Function for writing
	arguments prefixed with GTypes.
	(write_async_method_client): Write out async version
	of method.

	* glib/dbus-binding-tool-glib.c: Include dbus-gvalue-utils.h.
	(dbus_g_type_get_marshal_name): Move mapping from GType
	to marshal name into here.
	(dbus_g_type_get_c_name): Move into here.
	(compute_marshaller): Convert signature to type with
	dbus_gtype_from_signature, use dbus_g_type_get_marshal_name.
	(compute_marshaller_name): Ditto.
	(compute_marshaller): Handle async signal annotations.
	(gather_marshallers): Return if we don't have a known
	prefix.
	(generate_glue): Collect introspection blob here, and
	write all of the blob at the end.  This allows an object
	with multiple interfaces to work.
	Mark async methods in introspection blob.

	* glib/Makefile.am (libdbus_glib_1_la_SOURCES): Add
	dbus-gtype-specialized.c, dbus-gtype-specialized.h,
	dbus-gvalue-utils.h, dbus-gvalue-utils.c.

	* dbus/dbus-glib.h: Don't include dbus-protocol.h; this
	avoids people accidentally using DBUS_TYPE_* which should
	not be necessary anymore.
	Do include dbus-gtype-specialized.h, which are utilities
	for GLib container types.
	Add various #defines for types such as
	DBUS_TYPE_G_BOOLEAN_ARRAY.
	(DBusGValueIterator, DBusGValue): Define, not fully used
	yet.
	(dbus_g_value_get_g_type): Type for recursive value.
	(dbus_g_value_open, dbus_g_value_iterator_get_value)
	(dbus_g_value_iterator_get_values, dbus_g_value_iterator_recurse)
	(dbus_g_value_free): Prototypes.
	(dbus_g_object_register_marshaller, dbus_g_proxy_new_from_proxy): Prototype.
	(dbus_g_proxy_set_interface): Prototype.
	(dbus_g_proxy_begin_call, dbus_g_proxy_end_call)
	(dbus_g_proxy_call_no_reply): Take GLib types instead of DBus
	types.
	(dbus_g_proxy_get_path, dbus_g_proxy_get_interface):
	Accessors.
	(DBusGAsyncData, DBusGMethodInvocation): Structures for
	doing async invocations.
	(dbus_g_method_return, dbus_g_method_return_error):
	Prototypes.
	* doc/dbus-tutorial.xml: Update GLib section.
	
	* tools/dbus-viewer.c (load_child_nodes): Update
	for new invocation type of dbus_g_proxy_end_call.
	(load_from_service_thread_func): Ditto.

	* tools/print-introspect.c (main): Ditto.

	* tools/dbus-names-model.c (have_names_notify)
	(names_model_reload, names_model_set_connection)
	Use GTypes.

	* python/Makefile.am (INCLUDES): Define DBUS_COMPILATION,
	needed since Python bindings use GLib bindings.

	* test/glib/Makefile.am (INCLUDES): Define DBUS_COMPILATION.
	Add --prefix argument.

	* tools/Makefile.am: Define DBUS_COMPILATION.  Remove
	unneeded --ignore-unsupported arg.
	
	* test/glib/test-service-glib.c: 
	* test/glib/test-service-glib.xml:
	* test/glib/test-dbus-glib.c: Add many more tests.


Index: dbus-tutorial.xml
===================================================================
RCS file: /cvs/dbus/dbus/doc/dbus-tutorial.xml,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- dbus-tutorial.xml	23 Jan 2005 03:53:34 -0000	1.10
+++ dbus-tutorial.xml	13 Jun 2005 03:01:26 -0000	1.11
@@ -449,20 +449,294 @@
     <title>GLib API: Using Remote Objects</title>
 
     <para>
-      
       The GLib binding is defined in the header file
-      &lt;dbus/dbus-glib.h&gt;. The API is very small, in sharp contrast to the
-      low-level &lt;dbus/dbus.h&gt;.
-
-    </para>
-
-    <para>
-      The GLib bindings are incomplete, see the TODO file and comments in the
-      source code.
+      &lt;dbus/dbus-glib.h&gt;.
     </para>
 
-    <para>
-Here is a D-BUS program using the GLib bindings.
+    <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 G_TYPE_INT16 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 G_TYPE_UINT16 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 G_TYPE_INT32 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 G_TYPE_UINT32 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>g_free</entry>
+		  <entry></entry>
+		  </row><row>
+		  <entry><literal>OBJECT_PATH</literal></entry>
+		  <entry><literal>DBUS_TYPE_G_PROXY</literal></entry>
+		  <entry>g_object_unref</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 builtin 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>g_strfreev</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>g_value_unset</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_BYTE_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)
@@ -470,10 +744,8 @@
   DBusGConnection *connection;
   GError *error;
   DBusGProxy *proxy;
-  DBusGPendingCall *call;
   char **name_list;
-  int name_list_len;
-  int i;
+  char **name_list_ptr;
   
   g_type_init ();
 
@@ -495,15 +767,10 @@
                                      DBUS_PATH_ORG_FREEDESKTOP_DBUS,
                                      DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS);
 
-  /* Call ListNames method */
-  
-  call = dbus_g_proxy_begin_call (proxy, "ListNames", DBUS_TYPE_INVALID);
-
+  /* Call ListNames method, wait for reply */
   error = NULL;
-  if (!dbus_g_proxy_end_call (proxy, call, &amp;error,
-                              DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
-                              &amp;name_list, &amp;name_list_len,
-                              DBUS_TYPE_INVALID))
+  if (!dbus_g_proxy_invoke (proxy, "ListNames", &amp;error, G_TYPE_INVALID,
+                            G_TYPE_STRV, &amp;name_list, G_TYPE_INVALID))
     {
       g_printerr ("Failed to complete ListNames call: %s\n",
                   error-&gt;message);
@@ -514,77 +781,348 @@
   /* Print the results */
  
   g_print ("Names on the message bus:\n");
-  i = 0;
-  while (i &lt; name_list_len)
+  
+  for (name_list_ptr = name_list; *name_list_ptr; name_list_ptr++)
     {
-      g_assert (name_list[i] != NULL);
-      g_print ("  %s\n", name_list[i]);
-      ++i;
+      g_print ("  %s\n", *name_list_ptr);
     }
-  g_assert (name_list[i] == NULL);
-
   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_invoke</literal> sends a
+	method call to the remote object, and blocks until 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>.  At the
+	moment, <literal>dbus_g_proxy_add_signal</literal> requires
+	the D-BUS types of the remote object; this will likely be
+	changed later.
+      </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_invoke (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))
+    {
+      g_printerr ("Failed to complete Foobar: %s\n",
+                  error-&gt;message);
+      g_error_free (error);
+      exit (1);
+    }
+   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");
 
-    <para>
-
-      DBusGProxy represents a remote object. dbus_g_proxy_begin_call() sends 
-      a method call to the remote object, and dbus_g_proxy_end_call() retrieves 
-      any return values or exceptions resulting from the method call. 
-      There are also DBusGProxy functions to connect and disconnect signals, 
-      not shown in the code example.
-
-    </para>
-
-    <para>
-      
-      dbus_g_bus_get() assumes that the application will use GMainLoop. The
-      created connection will be associated with the main loop such that
-      messages will be sent and received when the main loop runs.  However, in
-      the above code example the main loop never runs; D-BUS will not run the
-      loop implicitly. Instead, dbus_g_proxy_end_call() will block until the
-      method call has been sent and the reply received. A more complex GUI
-      application might run the main loop while waiting for the method call
-      reply.  (DBusGPendingCall is currently missing the "notify me when the
-      call is complete" functionality found in DBusPendingCall, but it should be
-      added.)
+  error = NULL;
+  if (!dbus_g_proxy_invoke (proxy, "HashSize", &amp;error,
+                            DBUS_TYPE_G_STRING_STRING_HASH, hash, G_TYPE_INVALID,
+			    G_TYPE_UINT, &amp;ret, G_TYPE_INVALID))
+    {
+      g_printerr ("Failed to complete HashSize: %s\n",
+                  error-&gt;message);
+      g_error_free (error);
+      exit (1);
+    }
+  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_invoke (proxy, "GetStuff", &amp;error,
+			    G_TYPE_INVALID,
+                            G_TYPE_BOOLEAN, &amp;boolret,
+                            G_TYPE_STRING, &amp;strret,
+			    G_TYPE_INVALID))
+    {
+      g_printerr ("Failed to complete GetStuff: %s\n",
+                  error-&gt;message);
+      g_error_free (error);
+      exit (1);
+    }
+  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;
 
-    </para>
+  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_invoke (proxy, "TwoStrArrays", &amp;error,
+                            G_TYPE_STRV, strs_static_p,
+                            G_TYPE_STRV, strs_dynamic,
+			    G_TYPE_INVALID,
+			    G_TYPE_INVALID))
+    {
+      g_printerr ("Failed to complete TwoStrArrays: %s\n",
+                  error-&gt;message);
+      g_error_free (error);
+      exit (1);
+    }
+   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;
 
-    <para>
-      
-      Future plans (see doc/TODO) are to use G_TYPE_STRING in place of
-      DBUS_TYPE_STRING and so forth. In fact the above code is slightly
-      incorrect at the moment, since it uses g_strfreev() to free a string array
-      that was not allocated with g_malloc(). dbus_free_string_array() should
-      really be used. However, once the GLib bindings are complete the returned
-      data from dbus_g_proxy_end_call() will be allocated with g_malloc().
+  error = NULL;
+  blah = TRUE;
+  if (!dbus_g_proxy_invoke (proxy, "GetStrs", &amp;error,
+                            G_TYPE_BOOLEAN, blah,
+			    G_TYPE_INVALID,
+                            G_TYPE_STRV, &amp;strs,
+			    G_TYPE_INVALID))
+    {
+      g_printerr ("Failed to complete GetStrs: %s\n",
+                  error-&gt;message);
+      g_error_free (error);
+      exit (1);
+    }
+   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, };
 
-    </para>
+  g_value_init (&amp;val, G_TYPE_STRING);
+  g_value_set_string (&amp;val, "hello world");
+  
+  error = NULL;
+  if (!dbus_g_proxy_invoke (proxy, "SendVariant", &amp;error,
+                            G_TYPE_VALUE, &amp;val, G_TYPE_INVALID,
+			    G_TYPE_INVALID))
+    {
+      g_printerr ("Failed to complete SendVariant: %s\n",
+                  error-&gt;message);
+      g_error_free (error);
+      exit (1);
+    }
+  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_invoke (proxy, "GetVariant", &amp;error, G_TYPE_INVALID,
+                            G_TYPE_VALUE, &amp;val, G_TYPE_INVALID))
+    {
+      g_printerr ("Failed to complete GetVariant: %s\n",
+                  error-&gt;message);
+      g_error_free (error);
+      exit (1);
+    }
+  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>
   </sect1>
 
   <sect1 id="glib-server">
     <title>GLib API: Implementing Objects</title>
-
     <para>
-      
-      The GLib binding is defined in the header file
-      &lt;dbus/dbus-glib.h&gt;. To implement an object, it's also necessary
-      to use the dbus-glib-tool command line tool.
-
+      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>
-      The GLib bindings are incomplete.  Implementing an object is not yet
-      possible, see the TODO file and comments in the source code for details
-      on what work needs doing.
+      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-objet.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>, 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>
-      
   </sect1>
 
   <sect1 id="qt-client">

Index: TODO
===================================================================
RCS file: /cvs/dbus/dbus/doc/TODO,v
retrieving revision 1.77
retrieving revision 1.78
diff -u -d -r1.77 -r1.78
--- TODO	6 Jun 2005 18:55:22 -0000	1.77
+++ TODO	13 Jun 2005 03:01:26 -0000	1.78
@@ -39,12 +39,11 @@
 Important for 1.0 GLib Bindings
 ===
 
- - finish dbus-glib-tool support for adding introspection 
-   data to GObject and autoexporting GObject using same
+ - Annotations for "do not take ownership of this return value" on server
 
- - Need to make sure that dbus-glib.h never returns any 
-   dbus_malloc() memory, only g_malloc(). 
-   dbus_g_proxy_end_call() is the major offender. 
+ - Fix signals
+
+ - Fix errors - need to get specific error back, not UnmappedError crap
 
  - DBusGProxy doesn't emit "destroy" when it should
 



More information about the dbus-commit mailing list