changeset 87361:0b387233ea86

* dbusbind.c (XD_BASIC_DBUS_TYPE, XD_DBUS_TYPE_P, XD_NEXT_VALUE): New macros. (XD_SYMBOL_TO_DBUS_TYPE): Renamed from XD_LISP_SYMBOL_TO_DBUS_TYPE. (XD_OBJECT_TO_DBUS_TYPE): Renamed from XD_LISP_OBJECT_TO_DBUS_TYPE. Simplify. (xd_signature): New function. (xd_append_arg): Compute also signatures. Major rewrite. (xd_retrieve_arg): Make debug messages friendly. (Fdbus_call_method, Fdbus_send_signal): Extend docstring. Check for signatures of arguments.
author Michael Albinus <michael.albinus@gmx.de>
date Fri, 21 Dec 2007 22:01:43 +0000
parents c7024d3b9ea3
children 85cef0528c37
files src/ChangeLog src/dbusbind.c
diffstat 2 files changed, 366 insertions(+), 181 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Fri Dec 21 11:41:33 2007 +0000
+++ b/src/ChangeLog	Fri Dec 21 22:01:43 2007 +0000
@@ -1,3 +1,17 @@
+2007-12-21  Michael Albinus  <michael.albinus@gmx.de>
+
+	* dbusbind.c (XD_BASIC_DBUS_TYPE, XD_DBUS_TYPE_P, XD_NEXT_VALUE):
+	New macros.
+	(XD_SYMBOL_TO_DBUS_TYPE): Renamed from
+	XD_LISP_SYMBOL_TO_DBUS_TYPE.
+	(XD_OBJECT_TO_DBUS_TYPE): Renamed from
+	XD_LISP_OBJECT_TO_DBUS_TYPE. Simplify.
+	(xd_signature): New function.
+	(xd_append_arg): Compute also signatures.  Major rewrite.
+	(xd_retrieve_arg): Make debug messages friendly.
+	(Fdbus_call_method, Fdbus_send_signal): Extend docstring.  Check
+	for signatures of arguments.
+
 2007-12-19  Michael Albinus  <michael.albinus@gmx.de>
 
 	* dbusbind.c (QCdbus_type_byte, QCdbus_type_boolean)
--- a/src/dbusbind.c	Fri Dec 21 11:41:33 2007 +0000
+++ b/src/dbusbind.c	Fri Dec 21 22:01:43 2007 +0000
@@ -103,44 +103,218 @@
 #define XD_DEBUG_VALID_LISP_OBJECT_P(object)
 #endif
 
+/* Check whether TYPE is a basic DBusType.  */
+#define XD_BASIC_DBUS_TYPE(type)					\
+  ((type ==  DBUS_TYPE_BYTE)						\
+   || (type ==  DBUS_TYPE_BOOLEAN)					\
+   || (type ==  DBUS_TYPE_INT16)					\
+   || (type ==  DBUS_TYPE_UINT16)					\
+   || (type ==  DBUS_TYPE_INT32)					\
+   || (type ==  DBUS_TYPE_UINT32)					\
+   || (type ==  DBUS_TYPE_INT64)					\
+   || (type ==  DBUS_TYPE_UINT64)					\
+   || (type ==  DBUS_TYPE_DOUBLE)					\
+   || (type ==  DBUS_TYPE_STRING)					\
+   || (type ==  DBUS_TYPE_OBJECT_PATH)					\
+   || (type ==  DBUS_TYPE_SIGNATURE))
+
 /* Determine the DBusType of a given Lisp symbol.  OBJECT must be one
    of the predefined D-Bus type symbols.  */
-#define XD_LISP_SYMBOL_TO_DBUS_TYPE(object)				\
-  (EQ (object, QCdbus_type_byte)) ? DBUS_TYPE_BYTE			\
-  : (EQ (object, QCdbus_type_boolean)) ? DBUS_TYPE_BOOLEAN		\
-  : (EQ (object, QCdbus_type_int16)) ? DBUS_TYPE_INT16			\
-  : (EQ (object, QCdbus_type_uint16)) ? DBUS_TYPE_UINT16		\
-  : (EQ (object, QCdbus_type_int32)) ? DBUS_TYPE_INT32			\
-  : (EQ (object, QCdbus_type_uint32)) ? DBUS_TYPE_UINT32		\
-  : (EQ (object, QCdbus_type_int64)) ? DBUS_TYPE_INT64			\
-  : (EQ (object, QCdbus_type_uint64)) ? DBUS_TYPE_UINT64		\
-  : (EQ (object, QCdbus_type_double)) ? DBUS_TYPE_DOUBLE		\
-  : (EQ (object, QCdbus_type_string)) ? DBUS_TYPE_STRING		\
-  : (EQ (object, QCdbus_type_object_path)) ? DBUS_TYPE_OBJECT_PATH	\
-  : (EQ (object, QCdbus_type_signature)) ? DBUS_TYPE_SIGNATURE		\
-  : (EQ (object, QCdbus_type_array)) ? DBUS_TYPE_ARRAY			\
-  : (EQ (object, QCdbus_type_variant)) ? DBUS_TYPE_VARIANT		\
-  : (EQ (object, QCdbus_type_struct)) ? DBUS_TYPE_STRUCT		\
-  : (EQ (object, QCdbus_type_dict_entry)) ? DBUS_TYPE_DICT_ENTRY	\
-  : DBUS_TYPE_INVALID
+#define XD_SYMBOL_TO_DBUS_TYPE(object)					\
+  ((EQ (object, QCdbus_type_byte)) ? DBUS_TYPE_BYTE			\
+   : (EQ (object, QCdbus_type_boolean)) ? DBUS_TYPE_BOOLEAN		\
+   : (EQ (object, QCdbus_type_int16)) ? DBUS_TYPE_INT16			\
+   : (EQ (object, QCdbus_type_uint16)) ? DBUS_TYPE_UINT16		\
+   : (EQ (object, QCdbus_type_int32)) ? DBUS_TYPE_INT32			\
+   : (EQ (object, QCdbus_type_uint32)) ? DBUS_TYPE_UINT32		\
+   : (EQ (object, QCdbus_type_int64)) ? DBUS_TYPE_INT64			\
+   : (EQ (object, QCdbus_type_uint64)) ? DBUS_TYPE_UINT64		\
+   : (EQ (object, QCdbus_type_double)) ? DBUS_TYPE_DOUBLE		\
+   : (EQ (object, QCdbus_type_string)) ? DBUS_TYPE_STRING		\
+   : (EQ (object, QCdbus_type_object_path)) ? DBUS_TYPE_OBJECT_PATH	\
+   : (EQ (object, QCdbus_type_signature)) ? DBUS_TYPE_SIGNATURE		\
+   : (EQ (object, QCdbus_type_array)) ? DBUS_TYPE_ARRAY			\
+   : (EQ (object, QCdbus_type_variant)) ? DBUS_TYPE_VARIANT		\
+   : (EQ (object, QCdbus_type_struct)) ? DBUS_TYPE_STRUCT		\
+   : (EQ (object, QCdbus_type_dict_entry)) ? DBUS_TYPE_DICT_ENTRY	\
+   : DBUS_TYPE_INVALID)
+
+/* Check whether a Lisp symbol is a predefined D-Bus type symbol.  */
+#define XD_DBUS_TYPE_P(object)						\
+  (SYMBOLP (object) && ((XD_SYMBOL_TO_DBUS_TYPE (object) != DBUS_TYPE_INVALID)))
 
 /* Determine the DBusType of a given Lisp OBJECT.  It is used to
    convert Lisp objects, being arguments of `dbus-call-method' or
    `dbus-send-signal', into corresponding C values appended as
    arguments to a D-Bus message.  */
-#define XD_LISP_OBJECT_TO_DBUS_TYPE(object)				\
-  (EQ (object, Qt) || EQ (object, Qnil)) ? DBUS_TYPE_BOOLEAN		\
-  : (SYMBOLP (object)) ? XD_LISP_SYMBOL_TO_DBUS_TYPE (object)		\
-  : (CONSP (object)) ? ((SYMBOLP (XCAR (object))			\
-			 && !EQ (XCAR (object), Qt)			\
-			 && !EQ (XCAR (object), Qnil))			\
-			? XD_LISP_SYMBOL_TO_DBUS_TYPE (XCAR (object))	\
-			: DBUS_TYPE_ARRAY)				\
-  : (NATNUMP (object)) ? DBUS_TYPE_UINT32				\
-  : (INTEGERP (object)) ? DBUS_TYPE_INT32				\
-  : (FLOATP (object)) ? DBUS_TYPE_DOUBLE				\
-  : (STRINGP (object)) ? DBUS_TYPE_STRING				\
-  : DBUS_TYPE_INVALID
+#define XD_OBJECT_TO_DBUS_TYPE(object)					\
+  ((EQ (object, Qt) || EQ (object, Qnil)) ? DBUS_TYPE_BOOLEAN		\
+   : (NATNUMP (object)) ? DBUS_TYPE_UINT32				\
+   : (INTEGERP (object)) ? DBUS_TYPE_INT32				\
+   : (FLOATP (object)) ? DBUS_TYPE_DOUBLE				\
+   : (STRINGP (object)) ? DBUS_TYPE_STRING				\
+   : (XD_DBUS_TYPE_P (object)) ? XD_SYMBOL_TO_DBUS_TYPE (object)	\
+   : (CONSP (object)) ? ((XD_DBUS_TYPE_P (XCAR (object)))		\
+			 ? XD_SYMBOL_TO_DBUS_TYPE (XCAR (object))	\
+			 : DBUS_TYPE_ARRAY)				\
+   : DBUS_TYPE_INVALID)
+
+/* Return a list pointer which does not have a Lisp symbol as car.  */
+#define XD_NEXT_VALUE(object)					\
+  ((XD_DBUS_TYPE_P (XCAR (object))) ? XCDR (object) : object)
+
+/* Compute SIGNATURE of OBJECT.  It must have a form that it can be
+   used in dbus_message_iter_open_container.  DTYPE is the DBusType
+   the object is related to.  It is passed as argument, because it
+   cannot be detected in basic type objects, when they are preceded by
+   a type symbol.  PARENT_TYPE is the DBusType of a container this
+   signature is embedded, or DBUS_TYPE_INVALID.  It is needed for the
+   check that DBUS_TYPE_DICT_ENTRY occurs only as array element.  */
+void
+xd_signature(signature, dtype, parent_type, object)
+     char *signature;
+     unsigned int dtype, parent_type;
+     Lisp_Object object;
+{
+  unsigned int subtype;
+  Lisp_Object elt;
+  char x[DBUS_MAXIMUM_SIGNATURE_LENGTH];
+
+  elt = object;
+
+  switch (dtype)
+    {
+    case DBUS_TYPE_BYTE:
+    case DBUS_TYPE_UINT16:
+    case DBUS_TYPE_UINT32:
+    case DBUS_TYPE_UINT64:
+      CHECK_NATNUM (object);
+      sprintf (signature, "%c", dtype);
+      break;
+
+    case DBUS_TYPE_BOOLEAN:
+      if (!EQ (object, Qt) && !EQ (object, Qnil))
+	wrong_type_argument (intern ("booleanp"), object);
+      sprintf (signature, "%c", dtype);
+      break;
+
+    case DBUS_TYPE_INT16:
+    case DBUS_TYPE_INT32:
+    case DBUS_TYPE_INT64:
+      CHECK_NUMBER (object);
+      sprintf (signature, "%c", dtype);
+      break;
+
+    case DBUS_TYPE_DOUBLE:
+      CHECK_FLOAT (object);
+      sprintf (signature, "%c", dtype);
+      break;
+
+    case DBUS_TYPE_STRING:
+    case DBUS_TYPE_OBJECT_PATH:
+    case DBUS_TYPE_SIGNATURE:
+      CHECK_STRING (object);
+      sprintf (signature, "%c", dtype);
+      break;
+
+    case DBUS_TYPE_ARRAY:
+      /* Check that all elements have the same D-Bus type.  For
+	 complex element types, we just check the container type, not
+	 the whole element's signature.  */
+      CHECK_CONS (object);
+
+      if (EQ (QCdbus_type_array, XCAR (elt))) /* Type symbol is optional.  */
+	elt = XD_NEXT_VALUE (elt);
+      subtype = XD_OBJECT_TO_DBUS_TYPE (XCAR (elt));
+      xd_signature (x, subtype, dtype, XCAR (XD_NEXT_VALUE (elt)));
+
+      while (!NILP (elt))
+	{
+	  if (subtype != XD_OBJECT_TO_DBUS_TYPE (XCAR (elt)))
+	    wrong_type_argument (intern ("D-Bus"), XCAR (elt));
+	  elt = XCDR (XD_NEXT_VALUE (elt));
+	}
+
+      sprintf (signature, "%c%s", dtype, x);
+      break;
+
+    case DBUS_TYPE_VARIANT:
+      /* Check that there is exactly one element.  */
+      CHECK_CONS (object);
+
+      elt = XD_NEXT_VALUE (elt);
+      subtype = XD_OBJECT_TO_DBUS_TYPE (XCAR (elt));
+      xd_signature (x, subtype, dtype, XCAR (XD_NEXT_VALUE (elt)));
+
+      if (!NILP (XCDR (XD_NEXT_VALUE (elt))))
+	wrong_type_argument (intern ("D-Bus"),
+			     XCAR (XCDR (XD_NEXT_VALUE (elt))));
+
+      sprintf (signature, "%c%s", dtype, x);
+      break;
+
+    case DBUS_TYPE_STRUCT:
+      /* A struct might contain any number of objects with different
+	 types.  No further check needed.  */
+      CHECK_CONS (object);
+
+      elt = XD_NEXT_VALUE (elt);
+
+      /* Compose the signature from the elements.  It is enclosed by
+	 parentheses.  */
+      sprintf (signature, "%c", DBUS_STRUCT_BEGIN_CHAR );
+      while (!NILP (elt))
+	{
+	  subtype = XD_OBJECT_TO_DBUS_TYPE (XCAR (elt));
+	  xd_signature (x, subtype, dtype, XCAR (XD_NEXT_VALUE (elt)));
+	  strcat (signature, x);
+	  elt = XCDR (XD_NEXT_VALUE (elt));
+	}
+      sprintf (signature, "%s%c", signature, DBUS_STRUCT_END_CHAR);
+      break;
+
+    case DBUS_TYPE_DICT_ENTRY:
+      /* Check that there are exactly two elements, and the first one
+	 is of basic type.  It must also be an element of an
+	 array.  */
+      CHECK_CONS (object);
+
+      if (parent_type != DBUS_TYPE_ARRAY)
+	wrong_type_argument (intern ("D-Bus"), object);
+
+      /* Compose the signature from the elements.  It is enclosed by
+	 curly braces.  */
+      sprintf (signature, "%c", DBUS_DICT_ENTRY_BEGIN_CHAR);
+
+      /* First element.  */
+      elt = XD_NEXT_VALUE (elt);
+      subtype = XD_OBJECT_TO_DBUS_TYPE (XCAR (elt));
+      xd_signature (x, subtype, dtype, XCAR (XD_NEXT_VALUE (elt)));
+      strcat (signature, x);
+
+      if (!XD_BASIC_DBUS_TYPE (subtype))
+	wrong_type_argument (intern ("D-Bus"), XCAR (XD_NEXT_VALUE (elt)));
+
+      /* Second element.  */
+      elt = XCDR (XD_NEXT_VALUE (elt));
+      subtype = XD_OBJECT_TO_DBUS_TYPE (XCAR (elt));
+      xd_signature (x, subtype, dtype, XCAR (XD_NEXT_VALUE (elt)));
+      strcat (signature, x);
+
+      if (!NILP (XCDR (XD_NEXT_VALUE (elt))))
+	wrong_type_argument (intern ("D-Bus"),
+			     XCAR (XCDR (XD_NEXT_VALUE (elt))));
+
+      /* Closing signature.  */
+      sprintf (signature, "%s%c", signature, DBUS_DICT_ENTRY_END_CHAR);
+      break;
+
+    default:
+      wrong_type_argument (intern ("D-Bus"), object);
+    }
+
+  XD_DEBUG_MESSAGE ("%s", signature);
+}
 
 /* Append C value, extracted from Lisp OBJECT, to iteration ITER.
    DTYPE must be a valid DBusType.  It is used to convert Lisp
@@ -150,157 +324,133 @@
 void
 xd_append_arg (dtype, object, iter)
      unsigned int dtype;
+     Lisp_Object object;
      DBusMessageIter *iter;
-     Lisp_Object object;
 {
+  Lisp_Object elt;
+  char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
+  DBusMessageIter subiter;
   char *value;
 
-  /* Check type of object.  If this has been detected implicitely, it
-     is OK already, but there might be cases the type symbol and the
-     corresponding object do'nt match.  */
-  switch (dtype)
+  XD_DEBUG_MESSAGE ("%c %s", dtype, SDATA (format2 ("%s", object, Qnil)));
+
+  if (XD_BASIC_DBUS_TYPE (dtype))
     {
-    case DBUS_TYPE_BYTE:
-    case DBUS_TYPE_UINT16:
-    case DBUS_TYPE_UINT32:
-    case DBUS_TYPE_UINT64:
-      CHECK_NATNUM (object);
-      break;
-    case DBUS_TYPE_BOOLEAN:
-      if (!EQ (object, Qt) && !EQ (object, Qnil))
-	wrong_type_argument (intern ("booleanp"), object);
-      break;
-    case DBUS_TYPE_INT16:
-    case DBUS_TYPE_INT32:
-    case DBUS_TYPE_INT64:
-      CHECK_NUMBER (object);
-      break;
-    case DBUS_TYPE_DOUBLE:
-      CHECK_FLOAT (object);
-      break;
-    case DBUS_TYPE_STRING:
-    case DBUS_TYPE_OBJECT_PATH:
-    case DBUS_TYPE_SIGNATURE:
-      CHECK_STRING (object);
-      break;
-    case DBUS_TYPE_ARRAY:
-      CHECK_CONS (object);
-      /* ToDo: Check that all list elements have the same type.  */
-      break;
-    case DBUS_TYPE_VARIANT:
-      CHECK_CONS (object);
-      /* ToDo: Check that there is exactly one element of basic type.  */
-      break;
-    case DBUS_TYPE_STRUCT:
-     CHECK_CONS (object);
-      break;
-    case DBUS_TYPE_DICT_ENTRY:
-      /* ToDo: Check that there are exactly two elements, and the
-	 first one is of basic type.  */
-       CHECK_CONS (object);
-      break;
-    default:
-      xsignal1 (Qdbus_error, build_string ("Unknown D-Bus type"));
+      switch (dtype)
+	{
+	case DBUS_TYPE_BYTE:
+	  XD_DEBUG_MESSAGE ("%c %u", dtype, XUINT (object));
+	  value = (unsigned char *) XUINT (object);
+	  break;
+
+	case DBUS_TYPE_BOOLEAN:
+	  XD_DEBUG_MESSAGE ("%c %s", dtype, (NILP (object)) ? "false" : "true");
+	  value = (NILP (object))
+	    ? (unsigned char *) FALSE : (unsigned char *) TRUE;
+	  break;
+
+	case DBUS_TYPE_INT16:
+	  XD_DEBUG_MESSAGE ("%c %d", dtype, XINT (object));
+	  value = (char *) (dbus_int16_t *) XINT (object);
+	  break;
+
+	case DBUS_TYPE_UINT16:
+	  XD_DEBUG_MESSAGE ("%c %u", dtype, XUINT (object));
+	  value = (char *) (dbus_uint16_t *) XUINT (object);
+	  break;
+
+	case DBUS_TYPE_INT32:
+	  XD_DEBUG_MESSAGE ("%c %d", dtype, XINT (object));
+	  value = (char *) (dbus_int32_t *) XINT (object);
+	  break;
+
+	case DBUS_TYPE_UINT32:
+	  XD_DEBUG_MESSAGE ("%c %u", dtype, XUINT (object));
+	  value = (char *) (dbus_uint32_t *) XUINT (object);
+	  break;
+
+	case DBUS_TYPE_INT64:
+	  XD_DEBUG_MESSAGE ("%c %d", dtype, XINT (object));
+	  value = (char *) (dbus_int64_t *) XINT (object);
+	  break;
+
+	case DBUS_TYPE_UINT64:
+	  XD_DEBUG_MESSAGE ("%c %u", dtype, XUINT (object));
+	  value = (char *) (dbus_int64_t *) XUINT (object);
+	  break;
+
+	case DBUS_TYPE_DOUBLE:
+	  XD_DEBUG_MESSAGE ("%c %f", dtype, XFLOAT (object));
+	  value = (char *) (float *) XFLOAT (object);
+	  break;
+
+	case DBUS_TYPE_STRING:
+	case DBUS_TYPE_OBJECT_PATH:
+	case DBUS_TYPE_SIGNATURE:
+	  XD_DEBUG_MESSAGE ("%c %s", dtype, SDATA (object));
+	  value = SDATA (object);
+	  break;
+	}
+
+      if (!dbus_message_iter_append_basic (iter, dtype, &value))
+	xsignal2 (Qdbus_error,
+		  build_string ("Unable to append argument"), object);
     }
 
-  if (CONSP (object))
-
-    /* Compound types.  */
+  else /* Compound types.  */
     {
-      DBusMessageIter subiter;
-      char subtype;
 
-      if (SYMBOLP (XCAR (object))
-	  && (strncmp (SDATA (XSYMBOL (XCAR (object))->xname), ":", 1) == 0))
-	object = XCDR (object);
+      /* All compound types except array have a type symbol.  For
+	 array, it is optional.  Skip it.  */
+      if (!XD_BASIC_DBUS_TYPE (XD_OBJECT_TO_DBUS_TYPE (XCAR (object))))
+	object = XD_NEXT_VALUE (object);
 
       /* Open new subiteration.  */
       switch (dtype)
 	{
 	case DBUS_TYPE_ARRAY:
 	case DBUS_TYPE_VARIANT:
-	  subtype = (char) XD_LISP_OBJECT_TO_DBUS_TYPE (XCAR (object));
-	  dbus_message_iter_open_container (iter, dtype, &subtype, &subiter);
+	  /* A variant has just one element.  An array has elements of
+	     the same type.  Both have been checked already, it is
+	     sufficient to retrieve just the signature of the first
+	     element.  */
+	  xd_signature (signature, XD_OBJECT_TO_DBUS_TYPE (XCAR (object)),
+			dtype, XCAR (XD_NEXT_VALUE (object)));
+	  XD_DEBUG_MESSAGE ("%c %s %s", dtype, signature,
+			    SDATA (format2 ("%s", object, Qnil)));
+	  if (!dbus_message_iter_open_container (iter, dtype,
+						 signature, &subiter))
+	    xsignal3 (Qdbus_error,
+		      build_string ("Cannot open container"),
+		      make_number (dtype), build_string (signature));
 	  break;
+
 	case DBUS_TYPE_STRUCT:
 	case DBUS_TYPE_DICT_ENTRY:
-	  dbus_message_iter_open_container (iter, dtype, NULL, &subiter);
+	  XD_DEBUG_MESSAGE ("%c %s", dtype,
+			    SDATA (format2 ("%s", object, Qnil)));
+	  if (!dbus_message_iter_open_container (iter, dtype, NULL, &subiter))
+	    xsignal2 (Qdbus_error,
+		      build_string ("Cannot open container"),
+		      make_number (dtype));
+	  break;
 	}
 
       /* Loop over list elements.  */
       while (!NILP (object))
 	{
-	  dtype = XD_LISP_OBJECT_TO_DBUS_TYPE (XCAR (object));
-	  if (dtype == DBUS_TYPE_INVALID)
-	    xsignal2 (Qdbus_error,
-		      build_string ("Not a valid argument"), XCAR (object));
-
-	  if (SYMBOLP (XCAR (object))
-	      && (strncmp (SDATA (XSYMBOL (XCAR (object))->xname), ":", 1)
-		  == 0))
-	    object = XCDR (object);
+	  dtype = XD_OBJECT_TO_DBUS_TYPE (XCAR (object));
+	  object = XD_NEXT_VALUE (object);
 
 	  xd_append_arg (dtype, XCAR (object), &subiter);
 
 	  object = XCDR (object);
 	}
 
-      dbus_message_iter_close_container (iter, &subiter);
-    }
-
-  else
-
-    /* Basic type.  */
-    {
-      switch (dtype)
-	{
-	case DBUS_TYPE_BYTE:
-	  XD_DEBUG_MESSAGE ("%d %u", dtype, XUINT (object));
-	  value = (unsigned char *) XUINT (object);
-	  break;
-	case DBUS_TYPE_BOOLEAN:
-	  XD_DEBUG_MESSAGE ("%d %s", dtype, (NILP (object)) ? "false" : "true");
-	  value = (NILP (object))
-	    ? (unsigned char *) FALSE : (unsigned char *) TRUE;
-	  break;
-	case DBUS_TYPE_INT16:
-	  XD_DEBUG_MESSAGE ("%d %d", dtype, XINT (object));
-	  value = (char *) (dbus_int16_t *) XINT (object);
-	  break;
-	case DBUS_TYPE_UINT16:
-	  XD_DEBUG_MESSAGE ("%d %u", dtype, XUINT (object));
-	  value = (char *) (dbus_uint16_t *) XUINT (object);
-	  break;
-	case DBUS_TYPE_INT32:
-	  XD_DEBUG_MESSAGE ("%d %d", dtype, XINT (object));
-	  value = (char *) (dbus_int32_t *) XINT (object);
-	  break;
-	case DBUS_TYPE_UINT32:
-	  XD_DEBUG_MESSAGE ("%d %u", dtype, XUINT (object));
-	  value = (char *) (dbus_uint32_t *) XUINT (object);
-	  break;
-	case DBUS_TYPE_INT64:
-	  XD_DEBUG_MESSAGE ("%d %d", dtype, XINT (object));
-	  value = (char *) (dbus_int64_t *) XINT (object);
-	  break;
-	case DBUS_TYPE_UINT64:
-	  XD_DEBUG_MESSAGE ("%d %u", dtype, XUINT (object));
-	  value = (char *) (dbus_int64_t *) XUINT (object);
-	  break;
-	case DBUS_TYPE_DOUBLE:
-	  XD_DEBUG_MESSAGE ("%d %f", dtype, XFLOAT (object));
-	  value = (char *) (float *) XFLOAT (object);
-	  break;
-	case DBUS_TYPE_STRING:
-	case DBUS_TYPE_OBJECT_PATH:
-	case DBUS_TYPE_SIGNATURE:
-	  XD_DEBUG_MESSAGE ("%d %s", dtype, SDATA (object));
-	  value = SDATA (object);
-	  break;
-	}
-      if (!dbus_message_iter_append_basic (iter, dtype, &value))
+      if (!dbus_message_iter_close_container (iter, &subiter))
 	xsignal2 (Qdbus_error,
-		  build_string ("Unable to append argument"), object);
+		  build_string ("Cannot close container"),
+		  make_number (dtype));
     }
 }
 
@@ -320,25 +470,28 @@
       {
 	dbus_bool_t val;
 	dbus_message_iter_get_basic (iter, &val);
-	XD_DEBUG_MESSAGE ("%d %s", dtype, (val == FALSE) ? "false" : "true");
+	XD_DEBUG_MESSAGE ("%c %s", dtype, (val == FALSE) ? "false" : "true");
 	return (val == FALSE) ? Qnil : Qt;
       }
+
     case DBUS_TYPE_INT32:
     case DBUS_TYPE_UINT32:
       {
 	dbus_uint32_t val;
 	dbus_message_iter_get_basic (iter, &val);
-	XD_DEBUG_MESSAGE ("%d %d", dtype, val);
+	XD_DEBUG_MESSAGE ("%c %d", dtype, val);
 	return make_number (val);
       }
+
     case DBUS_TYPE_STRING:
     case DBUS_TYPE_OBJECT_PATH:
       {
 	char *val;
 	dbus_message_iter_get_basic (iter, &val);
-	XD_DEBUG_MESSAGE ("%d %s", dtype, val);
+	XD_DEBUG_MESSAGE ("%c %s", dtype, val);
 	return build_string (val);
       }
+
     case DBUS_TYPE_ARRAY:
     case DBUS_TYPE_VARIANT:
     case DBUS_TYPE_STRUCT:
@@ -359,8 +512,9 @@
 	  }
 	RETURN_UNGCPRO (Fnreverse (result));
       }
+
     default:
-      XD_DEBUG_MESSAGE ("DBusType %d not supported", dtype);
+      XD_DEBUG_MESSAGE ("DBusType '%c' not supported", dtype);
       return Qnil;
     }
 }
@@ -439,16 +593,33 @@
   integer   => DBUS_TYPE_INT32
   float     => DBUS_TYPE_DOUBLE
   string    => DBUS_TYPE_STRING
+  list      => DBUS_TYPE_ARRAY
 
-Other Lisp objects are not supported as input arguments of METHOD.
+All arguments can be preceded by a type symbol.  For details about
+type symbols, see Info node `(dbus)Type Conversion'.
 
 `dbus-call-method' returns the resulting values of METHOD as a list of
 Lisp objects.  The type conversion happens the other direction as for
-input arguments.  Additionally to the types supported for input
-arguments, the D-Bus compound types DBUS_TYPE_ARRAY, DBUS_TYPE_VARIANT,
-DBUS_TYPE_STRUCT and DBUS_TYPE_DICT_ENTRY are accepted.  All of them
-are converted into a list of Lisp objects which correspond to the
-elements of the D-Bus container.  Example:
+input arguments.  It follows the mapping rules:
+
+  DBUS_TYPE_BOOLEAN     => t or nil
+  DBUS_TYPE_BYTE        => number
+  DBUS_TYPE_UINT16      => number
+  DBUS_TYPE_INT16       => integer
+  DBUS_TYPE_UINT32      => number
+  DBUS_TYPE_INT32       => integer
+  DBUS_TYPE_UINT64      => number
+  DBUS_TYPE_INT64       => integer
+  DBUS_TYPE_DOUBLE      => float
+  DBUS_TYPE_STRING      => string
+  DBUS_TYPE_OBJECT_PATH => string
+  DBUS_TYPE_SIGNATURE   => string
+  DBUS_TYPE_ARRAY       => list
+  DBUS_TYPE_VARIANT     => list
+  DBUS_TYPE_STRUCT      => list
+  DBUS_TYPE_DICT_ENTRY  => list
+
+Example:
 
 \(dbus-call-method
   :session "org.gnome.seahorse" "/org/gnome/seahorse/keys/openpgp"
@@ -482,7 +653,7 @@
   DBusError derror;
   unsigned int dtype;
   int i;
-  char *value;
+  char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
 
   /* Check parameters.  */
   bus = args[0];
@@ -529,16 +700,15 @@
 
       XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
       XD_DEBUG_MESSAGE ("Parameter%d %s",
-			i-4,
-			SDATA (format2 ("%s", args[i], Qnil)));
+			i-4, SDATA (format2 ("%s", args[i], Qnil)));
 
-      dtype = XD_LISP_OBJECT_TO_DBUS_TYPE (args[i]);
-      if (dtype == DBUS_TYPE_INVALID)
-	xsignal2 (Qdbus_error, build_string ("Not a valid argument"), args[i]);
+      dtype = XD_OBJECT_TO_DBUS_TYPE (args[i]);
+      if (XD_DBUS_TYPE_P (args[i]))
+	++i;
 
-      if (SYMBOLP (args[i])
-	  && (strncmp (SDATA (XSYMBOL (args[i])->xname), ":", 1) == 0))
-	++i;
+      /* Check for valid signature.  We use DBUS_TYPE_INVALID is
+	 indication that there is no parent type.  */
+      xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[i]);
 
       xd_append_arg (dtype, args[i], &iter);
     }
@@ -605,8 +775,10 @@
   integer   => DBUS_TYPE_INT32
   float     => DBUS_TYPE_DOUBLE
   string    => DBUS_TYPE_STRING
+  list      => DBUS_TYPE_ARRAY
 
-Other Lisp objects are not supported as arguments of SIGNAL.
+All arguments can be preceded by a type symbol.  For details about
+type symbols, see Info node `(dbus)Type Conversion'.
 
 Example:
 
@@ -626,7 +798,7 @@
   DBusMessageIter iter;
   unsigned int dtype;
   int i;
-  char *value;
+  char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
 
   /* Check parameters.  */
   bus = args[0];
@@ -671,16 +843,15 @@
     {
       XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
       XD_DEBUG_MESSAGE ("Parameter%d %s",
-			i-4,
-			SDATA (format2 ("%s", args[i], Qnil)));
+			i-4, SDATA (format2 ("%s", args[i], Qnil)));
 
-      dtype = XD_LISP_OBJECT_TO_DBUS_TYPE (args[i]);
-      if (dtype == DBUS_TYPE_INVALID)
-	xsignal2 (Qdbus_error, build_string ("Not a valid argument"), args[i]);
+      dtype = XD_OBJECT_TO_DBUS_TYPE (args[i]);
+      if (XD_DBUS_TYPE_P (args[i]))
+	++i;
 
-      if (SYMBOLP (args[i])
-	  && (strncmp (SDATA (XSYMBOL (args[i])->xname), ":", 1) == 0))
-	++i;
+      /* Check for valid signature.  We use DBUS_TYPE_INVALID is
+	 indication that there is no parent type.  */
+      xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[i]);
 
       xd_append_arg (dtype, args[i], &iter);
     }