* dbusbind.c (XD_BASIC_DBUS_TYPE): Use dbus_type_is_valid and
[bpt/emacs.git] / src / dbusbind.c
dissimilarity index 60%
index 9785035..d80bb21 100644 (file)
-/* Elisp bindings for D-Bus.
-   Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-GNU Emacs is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
-
-#include "config.h"
-
-#ifdef HAVE_DBUS
-#include <stdlib.h>
-#include <stdio.h>
-#include <dbus/dbus.h>
-#include <setjmp.h>
-#include "lisp.h"
-#include "frame.h"
-#include "termhooks.h"
-#include "keyboard.h"
-
-\f
-/* Subroutines.  */
-Lisp_Object Qdbus_init_bus;
-Lisp_Object Qdbus_get_unique_name;
-Lisp_Object Qdbus_call_method;
-Lisp_Object Qdbus_call_method_asynchronously;
-Lisp_Object Qdbus_method_return_internal;
-Lisp_Object Qdbus_method_error_internal;
-Lisp_Object Qdbus_send_signal;
-Lisp_Object Qdbus_register_signal;
-Lisp_Object Qdbus_register_method;
-
-/* D-Bus error symbol.  */
-Lisp_Object Qdbus_error;
-
-/* Lisp symbols of the system and session buses.  */
-Lisp_Object QCdbus_system_bus, QCdbus_session_bus;
-
-/* Lisp symbol for method call timeout.  */
-Lisp_Object QCdbus_timeout;
-
-/* Lisp symbols of D-Bus types.  */
-Lisp_Object QCdbus_type_byte, QCdbus_type_boolean;
-Lisp_Object QCdbus_type_int16, QCdbus_type_uint16;
-Lisp_Object QCdbus_type_int32, QCdbus_type_uint32;
-Lisp_Object QCdbus_type_int64, QCdbus_type_uint64;
-Lisp_Object QCdbus_type_double, QCdbus_type_string;
-Lisp_Object QCdbus_type_object_path, QCdbus_type_signature;
-Lisp_Object QCdbus_type_array, QCdbus_type_variant;
-Lisp_Object QCdbus_type_struct, QCdbus_type_dict_entry;
-
-/* Hash table which keeps function definitions.  */
-Lisp_Object Vdbus_registered_objects_table;
-
-/* Whether to debug D-Bus.  */
-Lisp_Object Vdbus_debug;
-
-/* Whether we are reading a D-Bus event.  */
-int xd_in_read_queued_messages = 0;
-
-\f
-/* We use "xd_" and "XD_" as prefix for all internal symbols, because
-   we don't want to poison other namespaces with "dbus_".  */
-
-/* Raise a signal.  If we are reading events, we cannot signal; we
-   throw to xd_read_queued_messages then.  */
-#define XD_SIGNAL1(arg)                                                        \
-  do {                                                                 \
-    if (xd_in_read_queued_messages)                                    \
-      Fthrow (Qdbus_error, Qnil);                                      \
-    else                                                               \
-      xsignal1 (Qdbus_error, arg);                                     \
-  } while (0)
-
-#define XD_SIGNAL2(arg1, arg2)                                         \
-  do {                                                                 \
-    if (xd_in_read_queued_messages)                                    \
-      Fthrow (Qdbus_error, Qnil);                                      \
-    else                                                               \
-      xsignal2 (Qdbus_error, arg1, arg2);                              \
-  } while (0)
-
-#define XD_SIGNAL3(arg1, arg2, arg3)                                   \
-  do {                                                                 \
-    if (xd_in_read_queued_messages)                                    \
-      Fthrow (Qdbus_error, Qnil);                                      \
-    else                                                               \
-      xsignal3 (Qdbus_error, arg1, arg2, arg3);                                \
-  } while (0)
-
-/* Raise a Lisp error from a D-Bus ERROR.  */
-#define XD_ERROR(error)                                                        \
-  do {                                                                 \
-    char s[1024];                                                      \
-    strncpy (s, error.message, 1023);                                  \
-    dbus_error_free (&error);                                          \
-    /* Remove the trailing newline.  */                                        \
-    if (strchr (s, '\n') != NULL)                                      \
-      s[strlen (s) - 1] = '\0';                                                \
-    XD_SIGNAL1 (build_string (s));                                     \
-  } while (0)
-
-/* Macros for debugging.  In order to enable them, build with
-   "make MYCPPFLAGS='-DDBUS_DEBUG -Wall'".  */
-#ifdef DBUS_DEBUG
-#define XD_DEBUG_MESSAGE(...)          \
-  do {                                 \
-    char s[1024];                      \
-    snprintf (s, 1023, __VA_ARGS__);   \
-    printf ("%s: %s\n", __func__, s);  \
-    message ("%s: %s", __func__, s);   \
-  } while (0)
-#define XD_DEBUG_VALID_LISP_OBJECT_P(object)                           \
-  do {                                                                 \
-    if (!valid_lisp_object_p (object))                                 \
-      {                                                                        \
-       XD_DEBUG_MESSAGE ("%d Assertion failure", __LINE__);            \
-       XD_SIGNAL1 (build_string ("Assertion failure"));                \
-      }                                                                        \
-  } while (0)
-
-#else /* !DBUS_DEBUG */
-#define XD_DEBUG_MESSAGE(...)                                          \
-  do {                                                                 \
-    if (!NILP (Vdbus_debug))                                           \
-      {                                                                        \
-       char s[1024];                                                   \
-       snprintf (s, 1023, __VA_ARGS__);                                \
-       message ("%s: %s", __func__, s);                                \
-      }                                                                        \
-  } while (0)
-#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))
-
-/* This was a macro.  On Solaris 2.11 it was said to compile for
-   hours, when optimzation is enabled.  So we have transferred it into
-   a function.  */
-/* Determine the DBusType of a given Lisp symbol.  OBJECT must be one
-   of the predefined D-Bus type symbols.  */
-static int
-xd_symbol_to_dbus_type (object)
-     Lisp_Object object;
-{
-  return
-    ((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_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 (CAR_SAFE (object)))                             \
-      ? ((XD_BASIC_DBUS_TYPE (xd_symbol_to_dbus_type (CAR_SAFE (object)))) \
-        ? DBUS_TYPE_ARRAY                                              \
-        : xd_symbol_to_dbus_type (CAR_SAFE (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 (CAR_SAFE (object))) ? CDR_SAFE (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.  */
-static 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 list 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);
-
-      /* Type symbol is optional.  */
-      if (EQ (QCdbus_type_array, CAR_SAFE (elt)))
-       elt = XD_NEXT_VALUE (elt);
-
-      /* If the array is empty, DBUS_TYPE_STRING is the default
-        element type.  */
-      if (NILP (elt))
-       {
-         subtype = DBUS_TYPE_STRING;
-         strcpy (x, DBUS_TYPE_STRING_AS_STRING);
-       }
-      else
-       {
-         subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
-         xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
-       }
-
-      /* If the element type is DBUS_TYPE_SIGNATURE, and this is the
-        only element, the value of this element is used as he array's
-        element signature.  */
-      if ((subtype == DBUS_TYPE_SIGNATURE)
-         && STRINGP (CAR_SAFE (XD_NEXT_VALUE (elt)))
-         && NILP (CDR_SAFE (XD_NEXT_VALUE (elt))))
-       strcpy (x, SDATA (CAR_SAFE (XD_NEXT_VALUE (elt))));
-
-      while (!NILP (elt))
-       {
-         if (subtype != XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt)))
-           wrong_type_argument (intern ("D-Bus"), CAR_SAFE (elt));
-         elt = CDR_SAFE (XD_NEXT_VALUE (elt));
-       }
-
-      sprintf (signature, "%c%s", dtype, x);
-      break;
-
-    case DBUS_TYPE_VARIANT:
-      /* Check that there is exactly one list element.  */
-      CHECK_CONS (object);
-
-      elt = XD_NEXT_VALUE (elt);
-      subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
-      xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
-
-      if (!NILP (CDR_SAFE (XD_NEXT_VALUE (elt))))
-       wrong_type_argument (intern ("D-Bus"),
-                            CAR_SAFE (CDR_SAFE (XD_NEXT_VALUE (elt))));
-
-      sprintf (signature, "%c", dtype);
-      break;
-
-    case DBUS_TYPE_STRUCT:
-      /* A struct list might contain any number of elements 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 (CAR_SAFE (elt));
-         xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
-         strcat (signature, x);
-         elt = CDR_SAFE (XD_NEXT_VALUE (elt));
-       }
-      strcat (signature, DBUS_STRUCT_END_CHAR_AS_STRING);
-      break;
-
-    case DBUS_TYPE_DICT_ENTRY:
-      /* Check that there are exactly two list elements, and the first
-        one is of basic type.  The dictionary entry itself must be an
-        element of an array.  */
-      CHECK_CONS (object);
-
-      /* Check the parent object type.  */
-      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 (CAR_SAFE (elt));
-      xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
-      strcat (signature, x);
-
-      if (!XD_BASIC_DBUS_TYPE (subtype))
-       wrong_type_argument (intern ("D-Bus"), CAR_SAFE (XD_NEXT_VALUE (elt)));
-
-      /* Second element.  */
-      elt = CDR_SAFE (XD_NEXT_VALUE (elt));
-      subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
-      xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
-      strcat (signature, x);
-
-      if (!NILP (CDR_SAFE (XD_NEXT_VALUE (elt))))
-       wrong_type_argument (intern ("D-Bus"),
-                            CAR_SAFE (CDR_SAFE (XD_NEXT_VALUE (elt))));
-
-      /* Closing signature.  */
-      strcat (signature, DBUS_DICT_ENTRY_END_CHAR_AS_STRING);
-      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
-   objects, being arguments of `dbus-call-method' or
-   `dbus-send-signal', into corresponding C values appended as
-   arguments to a D-Bus message.  */
-static void
-xd_append_arg (dtype, object, iter)
-     unsigned int dtype;
-     Lisp_Object object;
-     DBusMessageIter *iter;
-{
-  char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
-  DBusMessageIter subiter;
-
-  if (XD_BASIC_DBUS_TYPE (dtype))
-    switch (dtype)
-      {
-      case DBUS_TYPE_BYTE:
-       CHECK_NUMBER (object);
-       {
-         unsigned char val = XUINT (object) & 0xFF;
-         XD_DEBUG_MESSAGE ("%c %d", dtype, val);
-         if (!dbus_message_iter_append_basic (iter, dtype, &val))
-           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
-         return;
-       }
-
-      case DBUS_TYPE_BOOLEAN:
-       {
-         dbus_bool_t val = (NILP (object)) ? FALSE : TRUE;
-         XD_DEBUG_MESSAGE ("%c %s", dtype, (val == FALSE) ? "false" : "true");
-         if (!dbus_message_iter_append_basic (iter, dtype, &val))
-           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
-         return;
-       }
-
-      case DBUS_TYPE_INT16:
-       CHECK_NUMBER (object);
-       {
-         dbus_int16_t val = XINT (object);
-         XD_DEBUG_MESSAGE ("%c %d", dtype, (int) val);
-         if (!dbus_message_iter_append_basic (iter, dtype, &val))
-           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
-         return;
-       }
-
-      case DBUS_TYPE_UINT16:
-       CHECK_NUMBER (object);
-       {
-         dbus_uint16_t val = XUINT (object);
-         XD_DEBUG_MESSAGE ("%c %u", dtype, (unsigned int) val);
-         if (!dbus_message_iter_append_basic (iter, dtype, &val))
-           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
-         return;
-       }
-
-      case DBUS_TYPE_INT32:
-       CHECK_NUMBER (object);
-       {
-         dbus_int32_t val = XINT (object);
-         XD_DEBUG_MESSAGE ("%c %d", dtype, val);
-         if (!dbus_message_iter_append_basic (iter, dtype, &val))
-           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
-         return;
-       }
-
-      case DBUS_TYPE_UINT32:
-       CHECK_NUMBER (object);
-       {
-         dbus_uint32_t val = XUINT (object);
-         XD_DEBUG_MESSAGE ("%c %u", dtype, val);
-         if (!dbus_message_iter_append_basic (iter, dtype, &val))
-           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
-         return;
-       }
-
-      case DBUS_TYPE_INT64:
-       CHECK_NUMBER (object);
-       {
-         dbus_int64_t val = XINT (object);
-         XD_DEBUG_MESSAGE ("%c %d", dtype, (int) val);
-         if (!dbus_message_iter_append_basic (iter, dtype, &val))
-           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
-         return;
-       }
-
-      case DBUS_TYPE_UINT64:
-       CHECK_NUMBER (object);
-       {
-         dbus_uint64_t val = XUINT (object);
-         XD_DEBUG_MESSAGE ("%c %u", dtype, (unsigned int) val);
-         if (!dbus_message_iter_append_basic (iter, dtype, &val))
-           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
-         return;
-       }
-
-      case DBUS_TYPE_DOUBLE:
-       CHECK_FLOAT (object);
-       {
-         double val = XFLOAT_DATA (object);
-         XD_DEBUG_MESSAGE ("%c %f", dtype, val);
-         if (!dbus_message_iter_append_basic (iter, dtype, &val))
-           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
-         return;
-       }
-
-      case DBUS_TYPE_STRING:
-      case DBUS_TYPE_OBJECT_PATH:
-      case DBUS_TYPE_SIGNATURE:
-       CHECK_STRING (object);
-       {
-         /* We need to send a valid UTF-8 string.  We could encode `object'
-            but by not encoding it, we guarantee it's valid utf-8, even if
-            it contains eight-bit-bytes.  Of course, you can still send
-            manually-crafted junk by passing a unibyte string.  */
-         char *val = SDATA (object);
-         XD_DEBUG_MESSAGE ("%c %s", dtype, val);
-         if (!dbus_message_iter_append_basic (iter, dtype, &val))
-           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
-         return;
-       }
-      }
-
-  else /* Compound types.  */
-    {
-
-      /* 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 (CAR_SAFE (object))))
-       object = XD_NEXT_VALUE (object);
-
-      /* Open new subiteration.  */
-      switch (dtype)
-       {
-       case DBUS_TYPE_ARRAY:
-         /* An array has only elements of the same type.  So it is
-            sufficient to check the first element's signature
-            only.  */
-
-         if (NILP (object))
-           /* If the array is empty, DBUS_TYPE_STRING is the default
-              element type.  */
-           strcpy (signature, DBUS_TYPE_STRING_AS_STRING);
-
-         else
-           /* If the element type is DBUS_TYPE_SIGNATURE, and this is
-              the only element, the value of this element is used as
-              the array's element signature.  */
-           if ((XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object))
-                == DBUS_TYPE_SIGNATURE)
-               && STRINGP (CAR_SAFE (XD_NEXT_VALUE (object)))
-               && NILP (CDR_SAFE (XD_NEXT_VALUE (object))))
-             {
-               strcpy (signature, SDATA (CAR_SAFE (XD_NEXT_VALUE (object))));
-               object = CDR_SAFE (XD_NEXT_VALUE (object));
-             }
-
-           else
-             xd_signature (signature,
-                           XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object)),
-                           dtype, CAR_SAFE (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))
-           XD_SIGNAL3 (build_string ("Cannot open container"),
-                       make_number (dtype), build_string (signature));
-         break;
-
-       case DBUS_TYPE_VARIANT:
-         /* A variant has just one element.  */
-         xd_signature (signature, XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object)),
-                       dtype, CAR_SAFE (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))
-           XD_SIGNAL3 (build_string ("Cannot open container"),
-                       make_number (dtype), build_string (signature));
-         break;
-
-       case DBUS_TYPE_STRUCT:
-       case DBUS_TYPE_DICT_ENTRY:
-         /* These containers do not require a signature.  */
-         XD_DEBUG_MESSAGE ("%c %s", dtype,
-                           SDATA (format2 ("%s", object, Qnil)));
-         if (!dbus_message_iter_open_container (iter, dtype, NULL, &subiter))
-           XD_SIGNAL2 (build_string ("Cannot open container"),
-                       make_number (dtype));
-         break;
-       }
-
-      /* Loop over list elements.  */
-      while (!NILP (object))
-       {
-         dtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object));
-         object = XD_NEXT_VALUE (object);
-
-         xd_append_arg (dtype, CAR_SAFE (object), &subiter);
-
-         object = CDR_SAFE (object);
-       }
-
-      /* Close the subiteration.  */
-      if (!dbus_message_iter_close_container (iter, &subiter))
-       XD_SIGNAL2 (build_string ("Cannot close container"),
-                   make_number (dtype));
-    }
-}
-
-/* Retrieve C value from a DBusMessageIter structure ITER, and return
-   a converted Lisp object.  The type DTYPE of the argument of the
-   D-Bus message must be a valid DBusType.  Compound D-Bus types
-   result always in a Lisp list.  */
-static Lisp_Object
-xd_retrieve_arg (dtype, iter)
-     unsigned int dtype;
-     DBusMessageIter *iter;
-{
-
-  switch (dtype)
-    {
-    case DBUS_TYPE_BYTE:
-      {
-       unsigned int val;
-       dbus_message_iter_get_basic (iter, &val);
-       val = val & 0xFF;
-       XD_DEBUG_MESSAGE ("%c %d", dtype, val);
-       return make_number (val);
-      }
-
-    case DBUS_TYPE_BOOLEAN:
-      {
-       dbus_bool_t val;
-       dbus_message_iter_get_basic (iter, &val);
-       XD_DEBUG_MESSAGE ("%c %s", dtype, (val == FALSE) ? "false" : "true");
-       return (val == FALSE) ? Qnil : Qt;
-      }
-
-    case DBUS_TYPE_INT16:
-      {
-       dbus_int16_t val;
-       dbus_message_iter_get_basic (iter, &val);
-       XD_DEBUG_MESSAGE ("%c %d", dtype, val);
-       return make_number (val);
-      }
-
-    case DBUS_TYPE_UINT16:
-      {
-       dbus_uint16_t val;
-       dbus_message_iter_get_basic (iter, &val);
-       XD_DEBUG_MESSAGE ("%c %d", dtype, val);
-       return make_number (val);
-      }
-
-    case DBUS_TYPE_INT32:
-      {
-       dbus_int32_t val;
-       dbus_message_iter_get_basic (iter, &val);
-       XD_DEBUG_MESSAGE ("%c %d", dtype, val);
-       return make_fixnum_or_float (val);
-      }
-
-    case DBUS_TYPE_UINT32:
-      {
-       dbus_uint32_t val;
-       dbus_message_iter_get_basic (iter, &val);
-       XD_DEBUG_MESSAGE ("%c %d", dtype, val);
-       return make_fixnum_or_float (val);
-      }
-
-    case DBUS_TYPE_INT64:
-      {
-       dbus_int64_t val;
-       dbus_message_iter_get_basic (iter, &val);
-       XD_DEBUG_MESSAGE ("%c %d", dtype, (int) val);
-       return make_fixnum_or_float (val);
-      }
-
-    case DBUS_TYPE_UINT64:
-      {
-       dbus_uint64_t val;
-       dbus_message_iter_get_basic (iter, &val);
-       XD_DEBUG_MESSAGE ("%c %d", dtype, (int) val);
-       return make_fixnum_or_float (val);
-      }
-
-    case DBUS_TYPE_DOUBLE:
-      {
-       double val;
-       dbus_message_iter_get_basic (iter, &val);
-       XD_DEBUG_MESSAGE ("%c %f", dtype, val);
-       return make_float (val);
-      }
-
-    case DBUS_TYPE_STRING:
-    case DBUS_TYPE_OBJECT_PATH:
-    case DBUS_TYPE_SIGNATURE:
-      {
-       char *val;
-       dbus_message_iter_get_basic (iter, &val);
-       XD_DEBUG_MESSAGE ("%c %s", dtype, val);
-       return build_string (val);
-      }
-
-    case DBUS_TYPE_ARRAY:
-    case DBUS_TYPE_VARIANT:
-    case DBUS_TYPE_STRUCT:
-    case DBUS_TYPE_DICT_ENTRY:
-      {
-       Lisp_Object result;
-       struct gcpro gcpro1;
-       DBusMessageIter subiter;
-       int subtype;
-       result = Qnil;
-       GCPRO1 (result);
-       dbus_message_iter_recurse (iter, &subiter);
-       while ((subtype = dbus_message_iter_get_arg_type (&subiter))
-              != DBUS_TYPE_INVALID)
-         {
-           result = Fcons (xd_retrieve_arg (subtype, &subiter), result);
-           dbus_message_iter_next (&subiter);
-         }
-       XD_DEBUG_MESSAGE ("%c %s", dtype, SDATA (format2 ("%s", result, Qnil)));
-       RETURN_UNGCPRO (Fnreverse (result));
-      }
-
-    default:
-      XD_DEBUG_MESSAGE ("DBusType '%c' not supported", dtype);
-      return Qnil;
-    }
-}
-
-/* Initialize D-Bus connection.  BUS is a Lisp symbol, either :system
-   or :session.  It tells which D-Bus to be initialized.  */
-static DBusConnection *
-xd_initialize (bus)
-     Lisp_Object bus;
-{
-  DBusConnection *connection;
-  DBusError derror;
-
-  /* Parameter check.  */
-  CHECK_SYMBOL (bus);
-  if (!(EQ (bus, QCdbus_system_bus) || EQ (bus, QCdbus_session_bus)))
-    XD_SIGNAL2 (build_string ("Wrong bus name"), bus);
-
-  /* We do not want to have an autolaunch for the session bus.  */
-  if (EQ (bus, QCdbus_session_bus)
-      && getenv ("DBUS_SESSION_BUS_ADDRESS") == NULL)
-    XD_SIGNAL2 (build_string ("No connection to bus"), bus);
-
-  /* Open a connection to the bus.  */
-  dbus_error_init (&derror);
-
-  if (EQ (bus, QCdbus_system_bus))
-    connection = dbus_bus_get (DBUS_BUS_SYSTEM, &derror);
-  else
-    connection = dbus_bus_get (DBUS_BUS_SESSION, &derror);
-
-  if (dbus_error_is_set (&derror))
-    XD_ERROR (derror);
-
-  if (connection == NULL)
-    XD_SIGNAL2 (build_string ("No connection to bus"), bus);
-
-  /* Cleanup.  */
-  dbus_error_free (&derror);
-
-  /* Return the result.  */
-  return connection;
-}
-
-
-/* Add connection file descriptor to input_wait_mask, in order to
-   let select() detect, whether a new message has been arrived.  */
-dbus_bool_t
-xd_add_watch (watch, data)
-     DBusWatch *watch;
-     void *data;
-{
-  /* We check only for incoming data.  */
-  if (dbus_watch_get_flags (watch) & DBUS_WATCH_READABLE)
-    {
-#if HAVE_DBUS_WATCH_GET_UNIX_FD
-      /* TODO: Reverse these on Win32, which prefers the opposite.  */
-      int fd = dbus_watch_get_unix_fd(watch);
-      if (fd == -1)
-       fd = dbus_watch_get_socket(watch);
-#else
-      int fd = dbus_watch_get_fd(watch);
-#endif
-      XD_DEBUG_MESSAGE ("fd %d", fd);
-
-      if (fd == -1)
-       return FALSE;
-
-      /* Add the file descriptor to input_wait_mask.  */
-      add_keyboard_wait_descriptor (fd);
-    }
-
-  /* Return.  */
-  return TRUE;
-}
-
-/* Remove connection file descriptor from input_wait_mask.  DATA is
-   the used bus, either QCdbus_system_bus or QCdbus_session_bus.  */
-void
-xd_remove_watch (watch, data)
-     DBusWatch *watch;
-     void *data;
-{
-  /* We check only for incoming data.  */
-  if (dbus_watch_get_flags (watch) & DBUS_WATCH_READABLE)
-    {
-#if HAVE_DBUS_WATCH_GET_UNIX_FD
-      /* TODO: Reverse these on Win32, which prefers the opposite.  */
-      int fd = dbus_watch_get_unix_fd(watch);
-      if (fd == -1)
-       fd = dbus_watch_get_socket(watch);
-#else
-      int fd = dbus_watch_get_fd(watch);
-#endif
-      XD_DEBUG_MESSAGE ("fd %d", fd);
-
-      if (fd == -1)
-       return;
-
-      /* Unset session environment.  */
-      if ((data != NULL) && (data == (void*) XHASH (QCdbus_session_bus)))
-       {
-         XD_DEBUG_MESSAGE ("unsetenv DBUS_SESSION_BUS_ADDRESS");
-         unsetenv ("DBUS_SESSION_BUS_ADDRESS");
-       }
-
-      /* Remove the file descriptor from input_wait_mask.  */
-      delete_keyboard_wait_descriptor (fd);
-    }
-
-  /* Return.  */
-  return;
-}
-
-DEFUN ("dbus-init-bus", Fdbus_init_bus, Sdbus_init_bus, 1, 1, 0,
-       doc: /* Initialize connection to D-Bus BUS.
-This is an internal function, it shall not be used outside dbus.el.  */)
-     (bus)
-     Lisp_Object bus;
-{
-  DBusConnection *connection;
-
-  /* Check parameters.  */
-  CHECK_SYMBOL (bus);
-
-  /* Open a connection to the bus.  */
-  connection = xd_initialize (bus);
-
-  /* Add the watch functions.  We pass also the bus as data, in order
-     to distinguish between the busses in xd_remove_watch.  */
-  if (!dbus_connection_set_watch_functions (connection,
-                                           xd_add_watch,
-                                           xd_remove_watch,
-                                           NULL, (void*) XHASH (bus), NULL))
-    XD_SIGNAL1 (build_string ("Cannot add watch functions"));
-
-  /* We do not want to abort.  */
-  putenv ("DBUS_FATAL_WARNINGS=0");
-
-  /* Return.  */
-  return Qnil;
-}
-
-DEFUN ("dbus-get-unique-name", Fdbus_get_unique_name, Sdbus_get_unique_name,
-       1, 1, 0,
-       doc: /* Return the unique name of Emacs registered at D-Bus BUS.  */)
-     (bus)
-     Lisp_Object bus;
-{
-  DBusConnection *connection;
-  const char *name;
-
-  /* Check parameters.  */
-  CHECK_SYMBOL (bus);
-
-  /* Open a connection to the bus.  */
-  connection = xd_initialize (bus);
-
-  /* Request the name.  */
-  name = dbus_bus_get_unique_name (connection);
-  if (name == NULL)
-    XD_SIGNAL1 (build_string ("No unique name available"));
-
-  /* Return.  */
-  return build_string (name);
-}
-
-DEFUN ("dbus-call-method", Fdbus_call_method, Sdbus_call_method, 5, MANY, 0,
-       doc: /* Call METHOD on the D-Bus BUS.
-
-BUS is either the symbol `:system' or the symbol `:session'.
-
-SERVICE is the D-Bus service name to be used.  PATH is the D-Bus
-object path SERVICE is registered at.  INTERFACE is an interface
-offered by SERVICE.  It must provide METHOD.
-
-If the parameter `:timeout' is given, the following integer TIMEOUT
-specifies the maximum number of milliseconds the method call must
-return.  The default value is 25,000.  If the method call doesn't
-return in time, a D-Bus error is raised.
-
-All other arguments ARGS are passed to METHOD as arguments.  They are
-converted into D-Bus types via the following rules:
-
-  t and nil => DBUS_TYPE_BOOLEAN
-  number    => DBUS_TYPE_UINT32
-  integer   => DBUS_TYPE_INT32
-  float     => DBUS_TYPE_DOUBLE
-  string    => DBUS_TYPE_STRING
-  list      => DBUS_TYPE_ARRAY
-
-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.  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 or float
-  DBUS_TYPE_INT32       => integer or float
-  DBUS_TYPE_UINT64      => number or float
-  DBUS_TYPE_INT64       => integer or float
-  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"
-  "org.gnome.seahorse.Keys" "GetKeyField"
-  "openpgp:657984B8C7A966DD" "simple-name")
-
-  => (t ("Philip R. Zimmermann"))
-
-If the result of the METHOD call is just one value, the converted Lisp
-object is returned instead of a list containing this single Lisp object.
-
-\(dbus-call-method
-  :system "org.freedesktop.Hal" "/org/freedesktop/Hal/devices/computer"
-  "org.freedesktop.Hal.Device" "GetPropertyString"
-  "system.kernel.machine")
-
-  => "i686"
-
-usage: (dbus-call-method BUS SERVICE PATH INTERFACE METHOD &optional :timeout TIMEOUT &rest ARGS)  */)
-     (nargs, args)
-     int nargs;
-     register Lisp_Object *args;
-{
-  Lisp_Object bus, service, path, interface, method;
-  Lisp_Object result;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
-  DBusConnection *connection;
-  DBusMessage *dmessage;
-  DBusMessage *reply;
-  DBusMessageIter iter;
-  DBusError derror;
-  unsigned int dtype;
-  int timeout = -1;
-  int i = 5;
-  char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
-
-  /* Check parameters.  */
-  bus = args[0];
-  service = args[1];
-  path = args[2];
-  interface = args[3];
-  method = args[4];
-
-  CHECK_SYMBOL (bus);
-  CHECK_STRING (service);
-  CHECK_STRING (path);
-  CHECK_STRING (interface);
-  CHECK_STRING (method);
-  GCPRO5 (bus, service, path, interface, method);
-
-  XD_DEBUG_MESSAGE ("%s %s %s %s",
-                   SDATA (service),
-                   SDATA (path),
-                   SDATA (interface),
-                   SDATA (method));
-
-  /* Open a connection to the bus.  */
-  connection = xd_initialize (bus);
-
-  /* Create the message.  */
-  dmessage = dbus_message_new_method_call (SDATA (service),
-                                          SDATA (path),
-                                          SDATA (interface),
-                                          SDATA (method));
-  UNGCPRO;
-  if (dmessage == NULL)
-    XD_SIGNAL1 (build_string ("Unable to create a new message"));
-
-  /* Check for timeout parameter.  */
-  if ((i+2 <= nargs) && (EQ ((args[i]), QCdbus_timeout)))
-    {
-      CHECK_NATNUM (args[i+1]);
-      timeout = XUINT (args[i+1]);
-      i = i+2;
-    }
-
-  /* Initialize parameter list of message.  */
-  dbus_message_iter_init_append (dmessage, &iter);
-
-  /* Append parameters to the message.  */
-  for (; i < nargs; ++i)
-    {
-      dtype = XD_OBJECT_TO_DBUS_TYPE (args[i]);
-      if (XD_DBUS_TYPE_P (args[i]))
-       {
-         XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
-         XD_DEBUG_VALID_LISP_OBJECT_P (args[i+1]);
-         XD_DEBUG_MESSAGE ("Parameter%d %s %s", i-4,
-                           SDATA (format2 ("%s", args[i], Qnil)),
-                           SDATA (format2 ("%s", args[i+1], Qnil)));
-         ++i;
-       }
-      else
-       {
-         XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
-         XD_DEBUG_MESSAGE ("Parameter%d %s", i-4,
-                           SDATA (format2 ("%s", args[i], Qnil)));
-       }
-
-      /* Check for valid signature.  We use DBUS_TYPE_INVALID as
-        indication that there is no parent type.  */
-      xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[i]);
-
-      xd_append_arg (dtype, args[i], &iter);
-    }
-
-  /* Send the message.  */
-  dbus_error_init (&derror);
-  reply = dbus_connection_send_with_reply_and_block (connection,
-                                                    dmessage,
-                                                    timeout,
-                                                    &derror);
-
-  if (dbus_error_is_set (&derror))
-    XD_ERROR (derror);
-
-  if (reply == NULL)
-    XD_SIGNAL1 (build_string ("No reply"));
-
-  XD_DEBUG_MESSAGE ("Message sent");
-
-  /* Collect the results.  */
-  result = Qnil;
-  GCPRO1 (result);
-
-  if (dbus_message_iter_init (reply, &iter))
-    {
-      /* Loop over the parameters of the D-Bus reply message.  Construct a
-        Lisp list, which is returned by `dbus-call-method'.  */
-      while ((dtype = dbus_message_iter_get_arg_type (&iter))
-            != DBUS_TYPE_INVALID)
-       {
-         result = Fcons (xd_retrieve_arg (dtype, &iter), result);
-         dbus_message_iter_next (&iter);
-       }
-    }
-  else
-    {
-      /* No arguments: just return nil.  */
-    }
-
-  /* Cleanup.  */
-  dbus_error_free (&derror);
-  dbus_message_unref (dmessage);
-  dbus_message_unref (reply);
-
-  /* Return the result.  If there is only one single Lisp object,
-     return it as-it-is, otherwise return the reversed list.  */
-  if (XUINT (Flength (result)) == 1)
-    RETURN_UNGCPRO (CAR_SAFE (result));
-  else
-    RETURN_UNGCPRO (Fnreverse (result));
-}
-
-DEFUN ("dbus-call-method-asynchronously", Fdbus_call_method_asynchronously,
-       Sdbus_call_method_asynchronously, 6, MANY, 0,
-       doc: /* Call METHOD on the D-Bus BUS asynchronously.
-
-BUS is either the symbol `:system' or the symbol `:session'.
-
-SERVICE is the D-Bus service name to be used.  PATH is the D-Bus
-object path SERVICE is registered at.  INTERFACE is an interface
-offered by SERVICE.  It must provide METHOD.
-
-HANDLER is a Lisp function, which is called when the corresponding
-return message has arrived.  If HANDLER is nil, no return message will
-be expected.
-
-If the parameter `:timeout' is given, the following integer TIMEOUT
-specifies the maximum number of milliseconds the method call must
-return.  The default value is 25,000.  If the method call doesn't
-return in time, a D-Bus error is raised.
-
-All other arguments ARGS are passed to METHOD as arguments.  They are
-converted into D-Bus types via the following rules:
-
-  t and nil => DBUS_TYPE_BOOLEAN
-  number    => DBUS_TYPE_UINT32
-  integer   => DBUS_TYPE_INT32
-  float     => DBUS_TYPE_DOUBLE
-  string    => DBUS_TYPE_STRING
-  list      => DBUS_TYPE_ARRAY
-
-All arguments can be preceded by a type symbol.  For details about
-type symbols, see Info node `(dbus)Type Conversion'.
-
-Unless HANDLER is nil, the function returns a key into the hash table
-`dbus-registered-objects-table'.  The corresponding entry in the hash
-table is removed, when the return message has been arrived, and
-HANDLER is called.
-
-Example:
-
-\(dbus-call-method-asynchronously
-  :system "org.freedesktop.Hal" "/org/freedesktop/Hal/devices/computer"
-  "org.freedesktop.Hal.Device" "GetPropertyString" 'message
-  "system.kernel.machine")
-
-  => (:system 2)
-
-  -| i686
-
-usage: (dbus-call-method-asynchronously BUS SERVICE PATH INTERFACE METHOD HANDLER &optional :timeout TIMEOUT &rest ARGS)  */)
-     (nargs, args)
-     int nargs;
-     register Lisp_Object *args;
-{
-  Lisp_Object bus, service, path, interface, method, handler;
-  Lisp_Object result;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
-  DBusConnection *connection;
-  DBusMessage *dmessage;
-  DBusMessageIter iter;
-  unsigned int dtype;
-  int timeout = -1;
-  int i = 6;
-  char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
-
-  /* Check parameters.  */
-  bus = args[0];
-  service = args[1];
-  path = args[2];
-  interface = args[3];
-  method = args[4];
-  handler = args[5];
-
-  CHECK_SYMBOL (bus);
-  CHECK_STRING (service);
-  CHECK_STRING (path);
-  CHECK_STRING (interface);
-  CHECK_STRING (method);
-  if (!NILP (handler) && !FUNCTIONP (handler))
-    wrong_type_argument (intern ("functionp"), handler);
-  GCPRO6 (bus, service, path, interface, method, handler);
-
-  XD_DEBUG_MESSAGE ("%s %s %s %s",
-                   SDATA (service),
-                   SDATA (path),
-                   SDATA (interface),
-                   SDATA (method));
-
-  /* Check dbus-registered-objects-table.  */
-  if (!HASH_TABLE_P (Vdbus_registered_objects_table))
-    XD_SIGNAL1 (build_string ("dbus.el is not loaded"));
-
-  /* Open a connection to the bus.  */
-  connection = xd_initialize (bus);
-
-  /* Create the message.  */
-  dmessage = dbus_message_new_method_call (SDATA (service),
-                                          SDATA (path),
-                                          SDATA (interface),
-                                          SDATA (method));
-  if (dmessage == NULL)
-    XD_SIGNAL1 (build_string ("Unable to create a new message"));
-
-  /* Check for timeout parameter.  */
-  if ((i+2 <= nargs) && (EQ ((args[i]), QCdbus_timeout)))
-    {
-      CHECK_NATNUM (args[i+1]);
-      timeout = XUINT (args[i+1]);
-      i = i+2;
-    }
-
-  /* Initialize parameter list of message.  */
-  dbus_message_iter_init_append (dmessage, &iter);
-
-  /* Append parameters to the message.  */
-  for (; i < nargs; ++i)
-    {
-      dtype = XD_OBJECT_TO_DBUS_TYPE (args[i]);
-      if (XD_DBUS_TYPE_P (args[i]))
-       {
-         XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
-         XD_DEBUG_VALID_LISP_OBJECT_P (args[i+1]);
-         XD_DEBUG_MESSAGE ("Parameter%d %s %s", i-4,
-                           SDATA (format2 ("%s", args[i], Qnil)),
-                           SDATA (format2 ("%s", args[i+1], Qnil)));
-         ++i;
-       }
-      else
-       {
-         XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
-         XD_DEBUG_MESSAGE ("Parameter%d %s", i-4,
-                           SDATA (format2 ("%s", args[i], Qnil)));
-       }
-
-      /* Check for valid signature.  We use DBUS_TYPE_INVALID as
-        indication that there is no parent type.  */
-      xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[i]);
-
-      xd_append_arg (dtype, args[i], &iter);
-    }
-
-  if (!NILP (handler))
-    {
-      /* Send the message.  The message is just added to the outgoing
-        message queue.  */
-      if (!dbus_connection_send_with_reply (connection, dmessage,
-                                           NULL, timeout))
-       XD_SIGNAL1 (build_string ("Cannot send message"));
-
-      /* The result is the key in Vdbus_registered_objects_table.  */
-      result = (list2 (bus, make_number (dbus_message_get_serial (dmessage))));
-
-      /* Create a hash table entry.  */
-      Fputhash (result, handler, Vdbus_registered_objects_table);
-    }
-  else
-    {
-      /* Send the message.  The message is just added to the outgoing
-        message queue.  */
-      if (!dbus_connection_send (connection, dmessage, NULL))
-       XD_SIGNAL1 (build_string ("Cannot send message"));
-
-      result = Qnil;
-    }
-
-  /* Flush connection to ensure the message is handled.  */
-  dbus_connection_flush (connection);
-
-  XD_DEBUG_MESSAGE ("Message sent");
-
-  /* Cleanup.  */
-  dbus_message_unref (dmessage);
-
-  /* Return the result.  */
-  RETURN_UNGCPRO (result);
-}
-
-DEFUN ("dbus-method-return-internal", Fdbus_method_return_internal,
-       Sdbus_method_return_internal,
-       3, MANY, 0,
-       doc: /* Return for message SERIAL on the D-Bus BUS.
-This is an internal function, it shall not be used outside dbus.el.
-
-usage: (dbus-method-return-internal BUS SERIAL SERVICE &rest ARGS)  */)
-     (nargs, args)
-     int nargs;
-     register Lisp_Object *args;
-{
-  Lisp_Object bus, serial, service;
-  struct gcpro gcpro1, gcpro2, gcpro3;
-  DBusConnection *connection;
-  DBusMessage *dmessage;
-  DBusMessageIter iter;
-  unsigned int dtype;
-  int i;
-  char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
-
-  /* Check parameters.  */
-  bus = args[0];
-  serial = args[1];
-  service = args[2];
-
-  CHECK_SYMBOL (bus);
-  CHECK_NUMBER (serial);
-  CHECK_STRING (service);
-  GCPRO3 (bus, serial, service);
-
-  XD_DEBUG_MESSAGE ("%lu %s ", (unsigned long) XUINT (serial), SDATA (service));
-
-  /* Open a connection to the bus.  */
-  connection = xd_initialize (bus);
-
-  /* Create the message.  */
-  dmessage = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN);
-  if ((dmessage == NULL)
-      || (!dbus_message_set_reply_serial (dmessage, XUINT (serial)))
-      || (!dbus_message_set_destination (dmessage, SDATA (service))))
-    {
-      UNGCPRO;
-      XD_SIGNAL1 (build_string ("Unable to create a return message"));
-    }
-
-  UNGCPRO;
-
-  /* Initialize parameter list of message.  */
-  dbus_message_iter_init_append (dmessage, &iter);
-
-  /* Append parameters to the message.  */
-  for (i = 3; i < nargs; ++i)
-    {
-      dtype = XD_OBJECT_TO_DBUS_TYPE (args[i]);
-      if (XD_DBUS_TYPE_P (args[i]))
-       {
-         XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
-         XD_DEBUG_VALID_LISP_OBJECT_P (args[i+1]);
-         XD_DEBUG_MESSAGE ("Parameter%d %s %s", i-2,
-                           SDATA (format2 ("%s", args[i], Qnil)),
-                           SDATA (format2 ("%s", args[i+1], Qnil)));
-         ++i;
-       }
-      else
-       {
-         XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
-         XD_DEBUG_MESSAGE ("Parameter%d %s", i-2,
-                           SDATA (format2 ("%s", args[i], Qnil)));
-       }
-
-      /* Check for valid signature.  We use DBUS_TYPE_INVALID as
-        indication that there is no parent type.  */
-      xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[i]);
-
-      xd_append_arg (dtype, args[i], &iter);
-    }
-
-  /* Send the message.  The message is just added to the outgoing
-     message queue.  */
-  if (!dbus_connection_send (connection, dmessage, NULL))
-    XD_SIGNAL1 (build_string ("Cannot send message"));
-
-  /* Flush connection to ensure the message is handled.  */
-  dbus_connection_flush (connection);
-
-  XD_DEBUG_MESSAGE ("Message sent");
-
-  /* Cleanup.  */
-  dbus_message_unref (dmessage);
-
-  /* Return.  */
-  return Qt;
-}
-
-DEFUN ("dbus-method-error-internal", Fdbus_method_error_internal,
-       Sdbus_method_error_internal,
-       3, MANY, 0,
-       doc: /* Return error message for message SERIAL on the D-Bus BUS.
-This is an internal function, it shall not be used outside dbus.el.
-
-usage: (dbus-method-error-internal BUS SERIAL SERVICE &rest ARGS)  */)
-     (nargs, args)
-     int nargs;
-     register Lisp_Object *args;
-{
-  Lisp_Object bus, serial, service;
-  struct gcpro gcpro1, gcpro2, gcpro3;
-  DBusConnection *connection;
-  DBusMessage *dmessage;
-  DBusMessageIter iter;
-  unsigned int dtype;
-  int i;
-  char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
-
-  /* Check parameters.  */
-  bus = args[0];
-  serial = args[1];
-  service = args[2];
-
-  CHECK_SYMBOL (bus);
-  CHECK_NUMBER (serial);
-  CHECK_STRING (service);
-  GCPRO3 (bus, serial, service);
-
-  XD_DEBUG_MESSAGE ("%lu %s ", (unsigned long) XUINT (serial), SDATA (service));
-
-  /* Open a connection to the bus.  */
-  connection = xd_initialize (bus);
-
-  /* Create the message.  */
-  dmessage = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
-  if ((dmessage == NULL)
-      || (!dbus_message_set_error_name (dmessage, DBUS_ERROR_FAILED))
-      || (!dbus_message_set_reply_serial (dmessage, XUINT (serial)))
-      || (!dbus_message_set_destination (dmessage, SDATA (service))))
-    {
-      UNGCPRO;
-      XD_SIGNAL1 (build_string ("Unable to create a error message"));
-    }
-
-  UNGCPRO;
-
-  /* Initialize parameter list of message.  */
-  dbus_message_iter_init_append (dmessage, &iter);
-
-  /* Append parameters to the message.  */
-  for (i = 3; i < nargs; ++i)
-    {
-      dtype = XD_OBJECT_TO_DBUS_TYPE (args[i]);
-      if (XD_DBUS_TYPE_P (args[i]))
-       {
-         XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
-         XD_DEBUG_VALID_LISP_OBJECT_P (args[i+1]);
-         XD_DEBUG_MESSAGE ("Parameter%d %s %s", i-2,
-                           SDATA (format2 ("%s", args[i], Qnil)),
-                           SDATA (format2 ("%s", args[i+1], Qnil)));
-         ++i;
-       }
-      else
-       {
-         XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
-         XD_DEBUG_MESSAGE ("Parameter%d %s", i-2,
-                           SDATA (format2 ("%s", args[i], Qnil)));
-       }
-
-      /* Check for valid signature.  We use DBUS_TYPE_INVALID as
-        indication that there is no parent type.  */
-      xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[i]);
-
-      xd_append_arg (dtype, args[i], &iter);
-    }
-
-  /* Send the message.  The message is just added to the outgoing
-     message queue.  */
-  if (!dbus_connection_send (connection, dmessage, NULL))
-    XD_SIGNAL1 (build_string ("Cannot send message"));
-
-  /* Flush connection to ensure the message is handled.  */
-  dbus_connection_flush (connection);
-
-  XD_DEBUG_MESSAGE ("Message sent");
-
-  /* Cleanup.  */
-  dbus_message_unref (dmessage);
-
-  /* Return.  */
-  return Qt;
-}
-
-DEFUN ("dbus-send-signal", Fdbus_send_signal, Sdbus_send_signal, 5, MANY, 0,
-       doc: /* Send signal SIGNAL on the D-Bus BUS.
-
-BUS is either the symbol `:system' or the symbol `:session'.
-
-SERVICE is the D-Bus service name SIGNAL is sent from.  PATH is the
-D-Bus object path SERVICE is registered at.  INTERFACE is an interface
-offered by SERVICE.  It must provide signal SIGNAL.
-
-All other arguments ARGS are passed to SIGNAL as arguments.  They are
-converted into D-Bus types via the following rules:
-
-  t and nil => DBUS_TYPE_BOOLEAN
-  number    => DBUS_TYPE_UINT32
-  integer   => DBUS_TYPE_INT32
-  float     => DBUS_TYPE_DOUBLE
-  string    => DBUS_TYPE_STRING
-  list      => DBUS_TYPE_ARRAY
-
-All arguments can be preceded by a type symbol.  For details about
-type symbols, see Info node `(dbus)Type Conversion'.
-
-Example:
-
-\(dbus-send-signal
-  :session "org.gnu.Emacs" "/org/gnu/Emacs"
-  "org.gnu.Emacs.FileManager" "FileModified" "/home/albinus/.emacs")
-
-usage: (dbus-send-signal BUS SERVICE PATH INTERFACE SIGNAL &rest ARGS)  */)
-     (nargs, args)
-     int nargs;
-     register Lisp_Object *args;
-{
-  Lisp_Object bus, service, path, interface, signal;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
-  DBusConnection *connection;
-  DBusMessage *dmessage;
-  DBusMessageIter iter;
-  unsigned int dtype;
-  int i;
-  char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
-
-  /* Check parameters.  */
-  bus = args[0];
-  service = args[1];
-  path = args[2];
-  interface = args[3];
-  signal = args[4];
-
-  CHECK_SYMBOL (bus);
-  CHECK_STRING (service);
-  CHECK_STRING (path);
-  CHECK_STRING (interface);
-  CHECK_STRING (signal);
-  GCPRO5 (bus, service, path, interface, signal);
-
-  XD_DEBUG_MESSAGE ("%s %s %s %s",
-                   SDATA (service),
-                   SDATA (path),
-                   SDATA (interface),
-                   SDATA (signal));
-
-  /* Open a connection to the bus.  */
-  connection = xd_initialize (bus);
-
-  /* Create the message.  */
-  dmessage = dbus_message_new_signal (SDATA (path),
-                                     SDATA (interface),
-                                     SDATA (signal));
-  UNGCPRO;
-  if (dmessage == NULL)
-    XD_SIGNAL1 (build_string ("Unable to create a new message"));
-
-  /* Initialize parameter list of message.  */
-  dbus_message_iter_init_append (dmessage, &iter);
-
-  /* Append parameters to the message.  */
-  for (i = 5; i < nargs; ++i)
-    {
-      dtype = XD_OBJECT_TO_DBUS_TYPE (args[i]);
-      if (XD_DBUS_TYPE_P (args[i]))
-       {
-         XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
-         XD_DEBUG_VALID_LISP_OBJECT_P (args[i+1]);
-         XD_DEBUG_MESSAGE ("Parameter%d %s %s", i-4,
-                           SDATA (format2 ("%s", args[i], Qnil)),
-                           SDATA (format2 ("%s", args[i+1], Qnil)));
-         ++i;
-       }
-      else
-       {
-         XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
-         XD_DEBUG_MESSAGE ("Parameter%d %s", i-4,
-                           SDATA (format2 ("%s", args[i], Qnil)));
-       }
-
-      /* Check for valid signature.  We use DBUS_TYPE_INVALID as
-        indication that there is no parent type.  */
-      xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[i]);
-
-      xd_append_arg (dtype, args[i], &iter);
-    }
-
-  /* Send the message.  The message is just added to the outgoing
-     message queue.  */
-  if (!dbus_connection_send (connection, dmessage, NULL))
-    XD_SIGNAL1 (build_string ("Cannot send message"));
-
-  /* Flush connection to ensure the message is handled.  */
-  dbus_connection_flush (connection);
-
-  XD_DEBUG_MESSAGE ("Signal sent");
-
-  /* Cleanup.  */
-  dbus_message_unref (dmessage);
-
-  /* Return.  */
-  return Qt;
-}
-
-/* Check, whether there is pending input in the message queue of the
-   D-Bus BUS.  BUS is a Lisp symbol, either :system or :session.  */
-static Lisp_Object
-xd_get_dispatch_status (bus)
-     Lisp_Object bus;
-{
-  DBusConnection *connection;
-
-  /* Open a connection to the bus.  */
-  connection = xd_initialize (bus);
-
-  /* Non blocking read of the next available message.  */
-  dbus_connection_read_write (connection, 0);
-
-  /* Return.  */
-  return
-    (dbus_connection_get_dispatch_status (connection)
-     == DBUS_DISPATCH_DATA_REMAINS)
-    ? Qt : Qnil;
-}
-
-/* Check for queued incoming messages from the system and session buses.  */
-int
-xd_pending_messages ()
-{
-  int ret = FALSE;
-  xd_in_read_queued_messages = 1;
-
-  /* Vdbus_registered_objects_table will be initialized as hash table
-     in dbus.el.  When this package isn't loaded yet, it doesn't make
-     sense to handle D-Bus messages.  */
-  if (HASH_TABLE_P (Vdbus_registered_objects_table))
-    {
-      ret = (!NILP (internal_catch (Qdbus_error, xd_get_dispatch_status,
-                                   QCdbus_system_bus)));
-      if (ret) goto theend;
-
-      ret = ((getenv ("DBUS_SESSION_BUS_ADDRESS") != NULL) &&
-            (!NILP (internal_catch (Qdbus_error, xd_get_dispatch_status,
-                                    QCdbus_session_bus))));
-    }
-
-  /* Return.  */
- theend:
-  xd_in_read_queued_messages = 0;
-  return ret;
-}
-
-/* Read queued incoming message of the D-Bus BUS.  BUS is a Lisp
-   symbol, either :system or :session.  */
-static Lisp_Object
-xd_read_message (bus)
-     Lisp_Object bus;
-{
-  Lisp_Object args, key, value;
-  struct gcpro gcpro1;
-  struct input_event event;
-  DBusConnection *connection;
-  DBusMessage *dmessage;
-  DBusMessageIter iter;
-  unsigned int dtype;
-  int mtype, serial;
-  const char *uname, *path, *interface, *member;
-
-  /* Open a connection to the bus.  */
-  connection = xd_initialize (bus);
-
-  /* Non blocking read of the next available message.  */
-  dbus_connection_read_write (connection, 0);
-  dmessage = dbus_connection_pop_message (connection);
-
-  /* Return if there is no queued message.  */
-  if (dmessage == NULL)
-    return Qnil;
-
-  /* Collect the parameters.  */
-  args = Qnil;
-  GCPRO1 (args);
-
-  /* Loop over the resulting parameters.  Construct a list.  */
-  if (dbus_message_iter_init (dmessage, &iter))
-    {
-      while ((dtype = dbus_message_iter_get_arg_type (&iter))
-            != DBUS_TYPE_INVALID)
-       {
-         args = Fcons (xd_retrieve_arg (dtype, &iter), args);
-         dbus_message_iter_next (&iter);
-       }
-      /* The arguments are stored in reverse order.  Reorder them.  */
-      args = Fnreverse (args);
-    }
-
-  /* Read message type, message serial, unique name, object path,
-     interface and member from the message.  */
-  mtype = dbus_message_get_type (dmessage);
-  serial =
-    ((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)
-     || (mtype == DBUS_MESSAGE_TYPE_ERROR))
-    ? dbus_message_get_reply_serial (dmessage)
-    : dbus_message_get_serial (dmessage);
-  uname = dbus_message_get_sender (dmessage);
-  path = dbus_message_get_path (dmessage);
-  interface = dbus_message_get_interface (dmessage);
-  member = dbus_message_get_member (dmessage);
-
-  XD_DEBUG_MESSAGE ("Event received: %s %d %s %s %s %s %s",
-                   (mtype == DBUS_MESSAGE_TYPE_INVALID)
-                   ? "DBUS_MESSAGE_TYPE_INVALID"
-                   : (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
-                   ? "DBUS_MESSAGE_TYPE_METHOD_CALL"
-                   : (mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)
-                   ? "DBUS_MESSAGE_TYPE_METHOD_RETURN"
-                   : (mtype == DBUS_MESSAGE_TYPE_ERROR)
-                   ? "DBUS_MESSAGE_TYPE_ERROR"
-                   : "DBUS_MESSAGE_TYPE_SIGNAL",
-                   serial, uname, path, interface, member,
-                   SDATA (format2 ("%s", args, Qnil)));
-
-  if ((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)
-      || (mtype == DBUS_MESSAGE_TYPE_ERROR))
-    {
-      /* Search for a registered function of the message.  */
-      key = list2 (bus, make_number (serial));
-      value = Fgethash (key, Vdbus_registered_objects_table, Qnil);
-
-      /* There shall be exactly one entry.  Construct an event.  */
-      if (NILP (value))
-       goto cleanup;
-
-      /* Remove the entry.  */
-      Fremhash (key, Vdbus_registered_objects_table);
-
-      /* Construct an event.  */
-      EVENT_INIT (event);
-      event.kind = DBUS_EVENT;
-      event.frame_or_window = Qnil;
-      event.arg = Fcons (value, args);
-    }
-
-  else /* (mtype != DBUS_MESSAGE_TYPE_METHOD_RETURN)  */
-    {
-      /* Vdbus_registered_objects_table requires non-nil interface and
-        member.  */
-      if ((interface == NULL) || (member == NULL))
-       goto cleanup;
-
-      /* Search for a registered function of the message.  */
-      key = list3 (bus, build_string (interface), build_string (member));
-      value = Fgethash (key, Vdbus_registered_objects_table, Qnil);
-
-      /* Loop over the registered functions.  Construct an event.  */
-      while (!NILP (value))
-       {
-         key = CAR_SAFE (value);
-         /* key has the structure (UNAME SERVICE PATH HANDLER).  */
-         if (((uname == NULL)
-              || (NILP (CAR_SAFE (key)))
-              || (strcmp (uname, SDATA (CAR_SAFE (key))) == 0))
-             && ((path == NULL)
-                 || (NILP (CAR_SAFE (CDR_SAFE (CDR_SAFE (key)))))
-                 || (strcmp (path,
-                             SDATA (CAR_SAFE (CDR_SAFE (CDR_SAFE (key)))))
-                     == 0))
-             && (!NILP (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key)))))))
-           {
-             EVENT_INIT (event);
-             event.kind = DBUS_EVENT;
-             event.frame_or_window = Qnil;
-             event.arg = Fcons (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key)))),
-                                args);
-             break;
-           }
-         value = CDR_SAFE (value);
-       }
-
-      if (NILP (value))
-       goto cleanup;
-    }
-
-  /* Add type, serial, uname, path, interface and member to the event.  */
-  event.arg = Fcons ((member == NULL ? Qnil : build_string (member)),
-                    event.arg);
-  event.arg = Fcons ((interface == NULL ? Qnil : build_string (interface)),
-                    event.arg);
-  event.arg = Fcons ((path == NULL ? Qnil : build_string (path)),
-                    event.arg);
-  event.arg = Fcons ((uname == NULL ? Qnil : build_string (uname)),
-                    event.arg);
-  event.arg = Fcons (make_number (serial), event.arg);
-  event.arg = Fcons (make_number (mtype), event.arg);
-
-  /* Add the bus symbol to the event.  */
-  event.arg = Fcons (bus, event.arg);
-
-  /* Store it into the input event queue.  */
-  kbd_buffer_store_event (&event);
-
-  XD_DEBUG_MESSAGE ("Event stored: %s",
-                   SDATA (format2 ("%s", event.arg, Qnil)));
-
-  /* Cleanup.  */
- cleanup:
-  dbus_message_unref (dmessage);
-
-  RETURN_UNGCPRO (Qnil);
-}
-
-/* Read queued incoming messages from the system and session buses.  */
-void
-xd_read_queued_messages ()
-{
-
-  /* Vdbus_registered_objects_table will be initialized as hash table
-     in dbus.el.  When this package isn't loaded yet, it doesn't make
-     sense to handle D-Bus messages.  Furthermore, we ignore all Lisp
-     errors during the call.  */
-  if (HASH_TABLE_P (Vdbus_registered_objects_table))
-    {
-      xd_in_read_queued_messages = 1;
-      internal_catch (Qdbus_error, xd_read_message, QCdbus_system_bus);
-      internal_catch (Qdbus_error, xd_read_message, QCdbus_session_bus);
-      xd_in_read_queued_messages = 0;
-    }
-}
-
-DEFUN ("dbus-register-signal", Fdbus_register_signal, Sdbus_register_signal,
-       6, MANY, 0,
-       doc: /* Register for signal SIGNAL on the D-Bus BUS.
-
-BUS is either the symbol `:system' or the symbol `:session'.
-
-SERVICE is the D-Bus service name used by the sending D-Bus object.
-It can be either a known name or the unique name of the D-Bus object
-sending the signal.  When SERVICE is nil, related signals from all
-D-Bus objects shall be accepted.
-
-PATH is the D-Bus object path SERVICE is registered.  It can also be
-nil if the path name of incoming signals shall not be checked.
-
-INTERFACE is an interface offered by SERVICE.  It must provide SIGNAL.
-HANDLER is a Lisp function to be called when the signal is received.
-It must accept as arguments the values SIGNAL is sending.
-
-All other arguments ARGS, if specified, must be strings.  They stand
-for the respective arguments of the signal in their order, and are
-used for filtering as well.  A nil argument might be used to preserve
-the order.
-
-INTERFACE, SIGNAL and HANDLER must not be nil.  Example:
-
-\(defun my-signal-handler (device)
-  (message "Device %s added" device))
-
-\(dbus-register-signal
-  :system "org.freedesktop.Hal" "/org/freedesktop/Hal/Manager"
-  "org.freedesktop.Hal.Manager" "DeviceAdded" 'my-signal-handler)
-
-  => ((:system "org.freedesktop.Hal.Manager" "DeviceAdded")
-      ("org.freedesktop.Hal" "/org/freedesktop/Hal/Manager" my-signal-handler))
-
-`dbus-register-signal' returns an object, which can be used in
-`dbus-unregister-object' for removing the registration.
-
-usage: (dbus-register-signal BUS SERVICE PATH INTERFACE SIGNAL HANDLER &rest ARGS) */)
-     (nargs, args)
-     int nargs;
-     register Lisp_Object *args;
-{
-  Lisp_Object bus, service, path, interface, signal, handler;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
-  Lisp_Object uname, key, key1, value;
-  DBusConnection *connection;
-  int i;
-  char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
-  char x[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
-  DBusError derror;
-
-  /* Check parameters.  */
-  bus = args[0];
-  service = args[1];
-  path = args[2];
-  interface = args[3];
-  signal = args[4];
-  handler = args[5];
-
-  CHECK_SYMBOL (bus);
-  if (!NILP (service)) CHECK_STRING (service);
-  if (!NILP (path)) CHECK_STRING (path);
-  CHECK_STRING (interface);
-  CHECK_STRING (signal);
-  if (!FUNCTIONP (handler))
-    wrong_type_argument (intern ("functionp"), handler);
-  GCPRO6 (bus, service, path, interface, signal, handler);
-
-  /* Check dbus-registered-objects-table.  */
-  if (!HASH_TABLE_P (Vdbus_registered_objects_table))
-    XD_SIGNAL1 (build_string ("dbus.el is not loaded"));
-
-  /* Retrieve unique name of service.  If service is a known name, we
-     will register for the corresponding unique name, if any.  Signals
-     are sent always with the unique name as sender.  Note: the unique
-     name of "org.freedesktop.DBus" is that string itself.  */
-  if ((STRINGP (service))
-      && (SBYTES (service) > 0)
-      && (strcmp (SDATA (service), DBUS_SERVICE_DBUS) != 0)
-      && (strncmp (SDATA (service), ":", 1) != 0))
-    {
-      uname = call2 (intern ("dbus-get-name-owner"), bus, service);
-      /* When there is no unique name, we mark it with an empty
-        string.  */
-      if (NILP (uname))
-       uname = empty_unibyte_string;
-    }
-  else
-    uname = service;
-
-  /* Create a matching rule if the unique name exists (when no
-     wildcard).  */
-  if (NILP (uname) || (SBYTES (uname) > 0))
-    {
-      /* Open a connection to the bus.  */
-      connection = xd_initialize (bus);
-
-      /* Create a rule to receive related signals.  */
-      sprintf (rule,
-              "type='signal',interface='%s',member='%s'",
-              SDATA (interface),
-              SDATA (signal));
-
-      /* Add unique name and path to the rule if they are non-nil.  */
-      if (!NILP (uname))
-       {
-         sprintf (x, ",sender='%s'", SDATA (uname));
-         strcat (rule, x);
-       }
-
-      if (!NILP (path))
-       {
-         sprintf (x, ",path='%s'", SDATA (path));
-         strcat (rule, x);
-       }
-
-      /* Add arguments to the rule if they are non-nil.  */
-      for (i = 6; i < nargs; ++i)
-       if (!NILP (args[i]))
-         {
-           CHECK_STRING (args[i]);
-           sprintf (x, ",arg%d='%s'", i-6, SDATA (args[i]));
-           strcat (rule, x);
-         }
-
-      /* Add the rule to the bus.  */
-      dbus_error_init (&derror);
-      dbus_bus_add_match (connection, rule, &derror);
-      if (dbus_error_is_set (&derror))
-       {
-         UNGCPRO;
-         XD_ERROR (derror);
-       }
-
-      /* Cleanup.  */
-      dbus_error_free (&derror);
-
-      XD_DEBUG_MESSAGE ("Matching rule \"%s\" created", rule);
-    }
-
-  /* Create a hash table entry.  */
-  key = list3 (bus, interface, signal);
-  key1 = list4 (uname, service, path, handler);
-  value = Fgethash (key, Vdbus_registered_objects_table, Qnil);
-
-  if (NILP (Fmember (key1, value)))
-    Fputhash (key, Fcons (key1, value), Vdbus_registered_objects_table);
-
-  /* Return object.  */
-  RETURN_UNGCPRO (list2 (key, list3 (service, path, handler)));
-}
-
-DEFUN ("dbus-register-method", Fdbus_register_method, Sdbus_register_method,
-       6, 6, 0,
-       doc: /* Register for method METHOD on the D-Bus BUS.
-
-BUS is either the symbol `:system' or the symbol `:session'.
-
-SERVICE is the D-Bus service name of the D-Bus object METHOD is
-registered for.  It must be a known name.
-
-PATH is the D-Bus object path SERVICE is registered.  INTERFACE is the
-interface offered by SERVICE.  It must provide METHOD.  HANDLER is a
-Lisp function to be called when a method call is received.  It must
-accept the input arguments of METHOD.  The return value of HANDLER is
-used for composing the returning D-Bus message.  */)
-     (bus, service, path, interface, method, handler)
-     Lisp_Object bus, service, path, interface, method, handler;
-{
-  Lisp_Object key, key1, value;
-  DBusConnection *connection;
-  int result;
-  DBusError derror;
-
-  /* Check parameters.  */
-  CHECK_SYMBOL (bus);
-  CHECK_STRING (service);
-  CHECK_STRING (path);
-  CHECK_STRING (interface);
-  CHECK_STRING (method);
-  if (!FUNCTIONP (handler))
-    wrong_type_argument (intern ("functionp"), handler);
-  /* TODO: We must check for a valid service name, otherwise there is
-     a segmentation fault.  */
-
-  /* Check dbus-registered-objects-table.  */
-  if (!HASH_TABLE_P (Vdbus_registered_objects_table))
-    XD_SIGNAL1 (build_string ("dbus.el is not loaded"));
-
-  /* Open a connection to the bus.  */
-  connection = xd_initialize (bus);
-
-  /* Request the known name from the bus.  We can ignore the result,
-     it is set to -1 if there is an error - kind of redundancy.  */
-  dbus_error_init (&derror);
-  result = dbus_bus_request_name (connection, SDATA (service), 0, &derror);
-  if (dbus_error_is_set (&derror))
-    XD_ERROR (derror);
-
-  /* Create a hash table entry.  We use nil for the unique name,
-     because the method might be called from anybody.  */
-  key = list3 (bus, interface, method);
-  key1 = list4 (Qnil, service, path, handler);
-  value = Fgethash (key, Vdbus_registered_objects_table, Qnil);
-
-  if (NILP (Fmember (key1, value)))
-    Fputhash (key, Fcons (key1, value), Vdbus_registered_objects_table);
-
-  /* Cleanup.  */
-  dbus_error_free (&derror);
-
-  /* Return object.  */
-  return list2 (key, list3 (service, path, handler));
-}
-
-\f
-void
-syms_of_dbusbind ()
-{
-
-  Qdbus_init_bus = intern_c_string ("dbus-init-bus");
-  staticpro (&Qdbus_init_bus);
-  defsubr (&Sdbus_init_bus);
-
-  Qdbus_get_unique_name = intern_c_string ("dbus-get-unique-name");
-  staticpro (&Qdbus_get_unique_name);
-  defsubr (&Sdbus_get_unique_name);
-
-  Qdbus_call_method = intern_c_string ("dbus-call-method");
-  staticpro (&Qdbus_call_method);
-  defsubr (&Sdbus_call_method);
-
-  Qdbus_call_method_asynchronously = intern_c_string ("dbus-call-method-asynchronously");
-  staticpro (&Qdbus_call_method_asynchronously);
-  defsubr (&Sdbus_call_method_asynchronously);
-
-  Qdbus_method_return_internal = intern_c_string ("dbus-method-return-internal");
-  staticpro (&Qdbus_method_return_internal);
-  defsubr (&Sdbus_method_return_internal);
-
-  Qdbus_method_error_internal = intern_c_string ("dbus-method-error-internal");
-  staticpro (&Qdbus_method_error_internal);
-  defsubr (&Sdbus_method_error_internal);
-
-  Qdbus_send_signal = intern_c_string ("dbus-send-signal");
-  staticpro (&Qdbus_send_signal);
-  defsubr (&Sdbus_send_signal);
-
-  Qdbus_register_signal = intern_c_string ("dbus-register-signal");
-  staticpro (&Qdbus_register_signal);
-  defsubr (&Sdbus_register_signal);
-
-  Qdbus_register_method = intern_c_string ("dbus-register-method");
-  staticpro (&Qdbus_register_method);
-  defsubr (&Sdbus_register_method);
-
-  Qdbus_error = intern_c_string ("dbus-error");
-  staticpro (&Qdbus_error);
-  Fput (Qdbus_error, Qerror_conditions,
-       list2 (Qdbus_error, Qerror));
-  Fput (Qdbus_error, Qerror_message,
-       make_pure_c_string ("D-Bus error"));
-
-  QCdbus_system_bus = intern_c_string (":system");
-  staticpro (&QCdbus_system_bus);
-
-  QCdbus_session_bus = intern_c_string (":session");
-  staticpro (&QCdbus_session_bus);
-
-  QCdbus_timeout = intern_c_string (":timeout");
-  staticpro (&QCdbus_timeout);
-
-  QCdbus_type_byte = intern_c_string (":byte");
-  staticpro (&QCdbus_type_byte);
-
-  QCdbus_type_boolean = intern_c_string (":boolean");
-  staticpro (&QCdbus_type_boolean);
-
-  QCdbus_type_int16 = intern_c_string (":int16");
-  staticpro (&QCdbus_type_int16);
-
-  QCdbus_type_uint16 = intern_c_string (":uint16");
-  staticpro (&QCdbus_type_uint16);
-
-  QCdbus_type_int32 = intern_c_string (":int32");
-  staticpro (&QCdbus_type_int32);
-
-  QCdbus_type_uint32 = intern_c_string (":uint32");
-  staticpro (&QCdbus_type_uint32);
-
-  QCdbus_type_int64 = intern_c_string (":int64");
-  staticpro (&QCdbus_type_int64);
-
-  QCdbus_type_uint64 = intern_c_string (":uint64");
-  staticpro (&QCdbus_type_uint64);
-
-  QCdbus_type_double = intern_c_string (":double");
-  staticpro (&QCdbus_type_double);
-
-  QCdbus_type_string = intern_c_string (":string");
-  staticpro (&QCdbus_type_string);
-
-  QCdbus_type_object_path = intern_c_string (":object-path");
-  staticpro (&QCdbus_type_object_path);
-
-  QCdbus_type_signature = intern_c_string (":signature");
-  staticpro (&QCdbus_type_signature);
-
-  QCdbus_type_array = intern_c_string (":array");
-  staticpro (&QCdbus_type_array);
-
-  QCdbus_type_variant = intern_c_string (":variant");
-  staticpro (&QCdbus_type_variant);
-
-  QCdbus_type_struct = intern_c_string (":struct");
-  staticpro (&QCdbus_type_struct);
-
-  QCdbus_type_dict_entry = intern_c_string (":dict-entry");
-  staticpro (&QCdbus_type_dict_entry);
-
-  DEFVAR_LISP ("dbus-registered-objects-table",
-              &Vdbus_registered_objects_table,
-    doc: /* Hash table of registered functions for D-Bus.
-There are two different uses of the hash table: for accessing
-registered interfaces properties, targeted by signals or method calls,
-and for calling handlers in case of non-blocking method call returns.
-
-In the first case, the key in the hash table is the list (BUS
-INTERFACE MEMBER).  BUS is either the symbol `:system' or the symbol
-`:session'.  INTERFACE is a string which denotes a D-Bus interface,
-and MEMBER, also a string, is either a method, a signal or a property
-INTERFACE is offering.  All arguments but BUS must not be nil.
-
-The value in the hash table is a list of quadruple lists
-\((UNAME SERVICE PATH OBJECT) (UNAME SERVICE PATH OBJECT) ...).
-SERVICE is the service name as registered, UNAME is the corresponding
-unique name.  In case of registered methods and properties, UNAME is
-nil.  PATH is the object path of the sending object.  All of them can
-be nil, which means a wildcard then.  OBJECT is either the handler to
-be called when a D-Bus message, which matches the key criteria,
-arrives (methods and signals), or a cons cell containing the value of
-the property.
-
-In the second case, the key in the hash table is the list (BUS SERIAL).
-BUS is either the symbol `:system' or the symbol `:session'.  SERIAL
-is the serial number of the non-blocking method call, a reply is
-expected.  Both arguments must not be nil.  The value in the hash
-table is HANDLER, the function to be called when the D-Bus reply
-message arrives.  */);
-  /* We initialize Vdbus_registered_objects_table in dbus.el, because
-     we need to define a hash table function first.  */
-  Vdbus_registered_objects_table = Qnil;
-
-  DEFVAR_LISP ("dbus-debug", &Vdbus_debug,
-    doc: /* If non-nil, debug messages of D-Bus bindings are raised.  */);
-#ifdef DBUS_DEBUG
-  Vdbus_debug = Qt;
-  /* We can also set environment variable DBUS_VERBOSE=1 in order to
-     see more traces.  This requires libdbus-1 to be configured with
-     --enable-verbose-mode.  */
-#else
-  Vdbus_debug = Qnil;
-#endif
-
-  Fprovide (intern_c_string ("dbusbind"), Qnil);
-
-}
-
-#endif /* HAVE_DBUS */
-
-/* arch-tag: 0e828477-b571-4fe4-b559-5c9211bc14b8
-   (do not change this comment) */
+/* Elisp bindings for D-Bus.
+   Copyright (C) 2007-2012 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#ifdef HAVE_DBUS
+#include <stdio.h>
+#include <dbus/dbus.h>
+#include <setjmp.h>
+#include "lisp.h"
+#include "frame.h"
+#include "termhooks.h"
+#include "keyboard.h"
+#include "process.h"
+
+#ifndef DBUS_NUM_MESSAGE_TYPES
+#define DBUS_NUM_MESSAGE_TYPES 5
+#endif
+
+\f
+/* Subroutines.  */
+static Lisp_Object Qdbus_init_bus;
+static Lisp_Object Qdbus_get_unique_name;
+static Lisp_Object Qdbus_message_internal;
+
+/* D-Bus error symbol.  */
+static Lisp_Object Qdbus_error;
+
+/* Lisp symbols of the system and session buses.  */
+static Lisp_Object QCdbus_system_bus, QCdbus_session_bus;
+
+/* Lisp symbol for method call timeout.  */
+static Lisp_Object QCdbus_timeout;
+
+/* Lisp symbols of D-Bus types.  */
+static Lisp_Object QCdbus_type_byte, QCdbus_type_boolean;
+static Lisp_Object QCdbus_type_int16, QCdbus_type_uint16;
+static Lisp_Object QCdbus_type_int32, QCdbus_type_uint32;
+static Lisp_Object QCdbus_type_int64, QCdbus_type_uint64;
+static Lisp_Object QCdbus_type_double, QCdbus_type_string;
+static Lisp_Object QCdbus_type_object_path, QCdbus_type_signature;
+#ifdef DBUS_TYPE_UNIX_FD
+static Lisp_Object QCdbus_type_unix_fd;
+#endif
+static Lisp_Object QCdbus_type_array, QCdbus_type_variant;
+static Lisp_Object QCdbus_type_struct, QCdbus_type_dict_entry;
+
+/* Lisp symbols of objects in `dbus-registered-objects-table'.  */
+static Lisp_Object QCdbus_registered_serial, QCdbus_registered_method;
+static Lisp_Object QCdbus_registered_signal;
+
+/* Alist of D-Bus buses we are polling for messages.
+   The key is the symbol or string of the bus, and the value is the
+   connection address.  */
+static Lisp_Object xd_registered_buses;
+
+/* Whether we are reading a D-Bus event.  */
+static int xd_in_read_queued_messages = 0;
+
+\f
+/* We use "xd_" and "XD_" as prefix for all internal symbols, because
+   we don't want to poison other namespaces with "dbus_".  */
+
+/* Raise a signal.  If we are reading events, we cannot signal; we
+   throw to xd_read_queued_messages then.  */
+#define XD_SIGNAL1(arg)                                                        \
+  do {                                                                 \
+    if (xd_in_read_queued_messages)                                    \
+      Fthrow (Qdbus_error, Qnil);                                      \
+    else                                                               \
+      xsignal1 (Qdbus_error, arg);                                     \
+  } while (0)
+
+#define XD_SIGNAL2(arg1, arg2)                                         \
+  do {                                                                 \
+    if (xd_in_read_queued_messages)                                    \
+      Fthrow (Qdbus_error, Qnil);                                      \
+    else                                                               \
+      xsignal2 (Qdbus_error, arg1, arg2);                              \
+  } while (0)
+
+#define XD_SIGNAL3(arg1, arg2, arg3)                                   \
+  do {                                                                 \
+    if (xd_in_read_queued_messages)                                    \
+      Fthrow (Qdbus_error, Qnil);                                      \
+    else                                                               \
+      xsignal3 (Qdbus_error, arg1, arg2, arg3);                                \
+  } while (0)
+
+/* Raise a Lisp error from a D-Bus ERROR.  */
+#define XD_ERROR(error)                                                        \
+  do {                                                                 \
+    /* Remove the trailing newline.  */                                        \
+    char const *mess = error.message;                                  \
+    char const *nl = strchr (mess, '\n');                              \
+    Lisp_Object err = make_string (mess, nl ? nl - mess : strlen (mess)); \
+    dbus_error_free (&error);                                          \
+    XD_SIGNAL1 (err);                                                  \
+  } while (0)
+
+/* Macros for debugging.  In order to enable them, build with
+   "env MYCPPFLAGS='-DDBUS_DEBUG -Wall' make".  */
+#ifdef DBUS_DEBUG
+#define XD_DEBUG_MESSAGE(...)                                          \
+  do {                                                                 \
+    char s[1024];                                                      \
+    snprintf (s, sizeof s, __VA_ARGS__);                               \
+    if (!noninteractive)                                               \
+      printf ("%s: %s\n", __func__, s);                                        \
+    message ("%s: %s", __func__, s);                                   \
+  } while (0)
+#define XD_DEBUG_VALID_LISP_OBJECT_P(object)                           \
+  do {                                                                 \
+    if (!valid_lisp_object_p (object))                                 \
+      {                                                                        \
+       XD_DEBUG_MESSAGE ("%d Assertion failure", __LINE__);            \
+       XD_SIGNAL1 (build_string ("Assertion failure"));                \
+      }                                                                        \
+  } while (0)
+
+#else /* !DBUS_DEBUG */
+#define XD_DEBUG_MESSAGE(...)                                          \
+  do {                                                                 \
+    if (!NILP (Vdbus_debug))                                           \
+      {                                                                        \
+       char s[1024];                                                   \
+       snprintf (s, sizeof s, __VA_ARGS__);                            \
+       message ("%s: %s", __func__, s);                                \
+      }                                                                        \
+  } while (0)
+#define XD_DEBUG_VALID_LISP_OBJECT_P(object)
+#endif
+
+/* Check whether TYPE is a basic DBusType.  */
+#ifdef HAVE_DBUS_TYPE_IS_VALID
+#define XD_BASIC_DBUS_TYPE(type)                                       \
+  (dbus_type_is_valid (type) && dbus_type_is_basic (type))
+#else
+#ifdef DBUS_TYPE_UNIX_FD
+#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)                                   \
+   || (type ==  DBUS_TYPE_UNIX_FD))
+#else
+#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))
+#endif
+#endif
+
+/* This was a macro.  On Solaris 2.11 it was said to compile for
+   hours, when optimization is enabled.  So we have transferred it into
+   a function.  */
+/* Determine the DBusType of a given Lisp symbol.  OBJECT must be one
+   of the predefined D-Bus type symbols.  */
+static int
+xd_symbol_to_dbus_type (Lisp_Object object)
+{
+  return
+    ((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
+#ifdef DBUS_TYPE_UNIX_FD
+     : (EQ (object, QCdbus_type_unix_fd)) ? DBUS_TYPE_UNIX_FD
+#endif
+     : (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_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 (CAR_SAFE (object)))                             \
+      ? ((XD_BASIC_DBUS_TYPE (xd_symbol_to_dbus_type (CAR_SAFE (object)))) \
+        ? DBUS_TYPE_ARRAY                                              \
+        : xd_symbol_to_dbus_type (CAR_SAFE (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 (CAR_SAFE (object))) ? CDR_SAFE (object) : object)
+
+/* Transform the message type to its string representation for debug
+   messages.  */
+#define XD_MESSAGE_TYPE_TO_STRING(mtype)                               \
+  ((mtype == DBUS_MESSAGE_TYPE_INVALID)                                        \
+  ? "DBUS_MESSAGE_TYPE_INVALID"                                                \
+  : (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)                           \
+  ? "DBUS_MESSAGE_TYPE_METHOD_CALL"                                    \
+  : (mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)                         \
+  ? "DBUS_MESSAGE_TYPE_METHOD_RETURN"                                  \
+  : (mtype == DBUS_MESSAGE_TYPE_ERROR)                                 \
+   ? "DBUS_MESSAGE_TYPE_ERROR"                                         \
+   : "DBUS_MESSAGE_TYPE_SIGNAL")
+
+/* Transform the object to its string representation for debug
+   messages.  */
+#define XD_OBJECT_TO_STRING(object)                                    \
+  SDATA (format2 ("%s", object, Qnil))
+
+#define XD_DBUS_VALIDATE_BUS_ADDRESS(bus)                              \
+  do {                                                                 \
+    if (STRINGP (bus))                                                 \
+      {                                                                        \
+       DBusAddressEntry **entries;                                     \
+       int len;                                                        \
+       DBusError derror;                                               \
+       dbus_error_init (&derror);                                      \
+       if (!dbus_parse_address (SSDATA (bus), &entries, &len, &derror)) \
+         XD_ERROR (derror);                                            \
+       /* Cleanup.  */                                                 \
+       dbus_error_free (&derror);                                      \
+       dbus_address_entries_free (entries);                            \
+      }                                                                        \
+                                                                       \
+    else                                                               \
+      {                                                                        \
+       CHECK_SYMBOL (bus);                                             \
+       if (!(EQ (bus, QCdbus_system_bus) || EQ (bus, QCdbus_session_bus))) \
+         XD_SIGNAL2 (build_string ("Wrong bus name"), bus);            \
+       /* We do not want to have an autolaunch for the session bus.  */ \
+       if (EQ (bus, QCdbus_session_bus)                                \
+           && getenv ("DBUS_SESSION_BUS_ADDRESS") == NULL)             \
+         XD_SIGNAL2 (build_string ("No connection to bus"), bus);      \
+      }                                                                        \
+  } while (0)
+
+#if (HAVE_DBUS_VALIDATE_BUS_NAME || HAVE_DBUS_VALIDATE_PATH \
+     || XD_DBUS_VALIDATE_OBJECT || HAVE_DBUS_VALIDATE_MEMBER)
+#define XD_DBUS_VALIDATE_OBJECT(object, func)                          \
+  do {                                                                 \
+    if (!NILP (object))                                                        \
+      {                                                                        \
+       DBusError derror;                                               \
+       CHECK_STRING (object);                                          \
+       dbus_error_init (&derror);                                      \
+       if (!func (SSDATA (object), &derror))                           \
+         XD_ERROR (derror);                                            \
+       /* Cleanup.  */                                                 \
+       dbus_error_free (&derror);                                      \
+      }                                                                        \
+  } while (0)
+#endif
+
+#if HAVE_DBUS_VALIDATE_BUS_NAME
+#define XD_DBUS_VALIDATE_BUS_NAME(bus_name)                            \
+  XD_DBUS_VALIDATE_OBJECT(bus_name, dbus_validate_bus_name);
+#else
+#define XD_DBUS_VALIDATE_BUS_NAME(bus_name)                            \
+  if (!NILP (bus_name)) CHECK_STRING (bus_name);
+#endif
+
+#if HAVE_DBUS_VALIDATE_PATH
+#define XD_DBUS_VALIDATE_PATH(path)                                    \
+  XD_DBUS_VALIDATE_OBJECT(path, dbus_validate_path);
+#else
+#define XD_DBUS_VALIDATE_PATH(path)                                    \
+  if (!NILP (path)) CHECK_STRING (path);
+#endif
+
+#if HAVE_DBUS_VALIDATE_INTERFACE
+#define XD_DBUS_VALIDATE_INTERFACE(interface)                          \
+  XD_DBUS_VALIDATE_OBJECT(interface, dbus_validate_interface);
+#else
+#define XD_DBUS_VALIDATE_INTERFACE(interface)                          \
+  if (!NILP (interface)) CHECK_STRING (interface);
+#endif
+
+#if HAVE_DBUS_VALIDATE_MEMBER
+#define XD_DBUS_VALIDATE_MEMBER(member)                                        \
+  XD_DBUS_VALIDATE_OBJECT(member, dbus_validate_member);
+#else
+#define XD_DBUS_VALIDATE_MEMBER(member)                                        \
+  if (!NILP (member)) CHECK_STRING (member);
+#endif
+
+/* Append to SIGNATURE a copy of X, making sure SIGNATURE does
+   not become too long.  */
+static void
+xd_signature_cat (char *signature, char const *x)
+{
+  ptrdiff_t siglen = strlen (signature);
+  ptrdiff_t xlen = strlen (x);
+  if (DBUS_MAXIMUM_SIGNATURE_LENGTH - xlen <= siglen)
+    string_overflow ();
+  strcat (signature, x);
+}
+
+/* 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.  */
+static void
+xd_signature (char *signature, int dtype, int parent_type, Lisp_Object object)
+{
+  int subtype;
+  Lisp_Object elt;
+  char const *subsig;
+  int subsiglen;
+  char x[DBUS_MAXIMUM_SIGNATURE_LENGTH];
+
+  elt = object;
+
+  switch (dtype)
+    {
+    case DBUS_TYPE_BYTE:
+    case DBUS_TYPE_UINT16:
+      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:
+      CHECK_NUMBER (object);
+      sprintf (signature, "%c", dtype);
+      break;
+
+    case DBUS_TYPE_UINT32:
+    case DBUS_TYPE_UINT64:
+#ifdef DBUS_TYPE_UNIX_FD
+    case DBUS_TYPE_UNIX_FD:
+#endif
+    case DBUS_TYPE_INT32:
+    case DBUS_TYPE_INT64:
+    case DBUS_TYPE_DOUBLE:
+      CHECK_NUMBER_OR_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 list 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);
+
+      /* Type symbol is optional.  */
+      if (EQ (QCdbus_type_array, CAR_SAFE (elt)))
+       elt = XD_NEXT_VALUE (elt);
+
+      /* If the array is empty, DBUS_TYPE_STRING is the default
+        element type.  */
+      if (NILP (elt))
+       {
+         subtype = DBUS_TYPE_STRING;
+         subsig = DBUS_TYPE_STRING_AS_STRING;
+       }
+      else
+       {
+         subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
+         xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
+         subsig = x;
+       }
+
+      /* If the element type is DBUS_TYPE_SIGNATURE, and this is the
+        only element, the value of this element is used as the
+        array's element signature.  */
+      if ((subtype == DBUS_TYPE_SIGNATURE)
+         && STRINGP (CAR_SAFE (XD_NEXT_VALUE (elt)))
+         && NILP (CDR_SAFE (XD_NEXT_VALUE (elt))))
+       subsig = SSDATA (CAR_SAFE (XD_NEXT_VALUE (elt)));
+
+      while (!NILP (elt))
+       {
+         if (subtype != XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt)))
+           wrong_type_argument (intern ("D-Bus"), CAR_SAFE (elt));
+         elt = CDR_SAFE (XD_NEXT_VALUE (elt));
+       }
+
+      subsiglen = snprintf (signature, DBUS_MAXIMUM_SIGNATURE_LENGTH,
+                           "%c%s", dtype, subsig);
+      if (! (0 <= subsiglen && subsiglen < DBUS_MAXIMUM_SIGNATURE_LENGTH))
+       string_overflow ();
+      break;
+
+    case DBUS_TYPE_VARIANT:
+      /* Check that there is exactly one list element.  */
+      CHECK_CONS (object);
+
+      elt = XD_NEXT_VALUE (elt);
+      subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
+      xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
+
+      if (!NILP (CDR_SAFE (XD_NEXT_VALUE (elt))))
+       wrong_type_argument (intern ("D-Bus"),
+                            CAR_SAFE (CDR_SAFE (XD_NEXT_VALUE (elt))));
+
+      sprintf (signature, "%c", dtype);
+      break;
+
+    case DBUS_TYPE_STRUCT:
+      /* A struct list might contain any number of elements 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 (CAR_SAFE (elt));
+         xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
+         xd_signature_cat (signature, x);
+         elt = CDR_SAFE (XD_NEXT_VALUE (elt));
+       }
+      xd_signature_cat (signature, DBUS_STRUCT_END_CHAR_AS_STRING);
+      break;
+
+    case DBUS_TYPE_DICT_ENTRY:
+      /* Check that there are exactly two list elements, and the first
+        one is of basic type.  The dictionary entry itself must be an
+        element of an array.  */
+      CHECK_CONS (object);
+
+      /* Check the parent object type.  */
+      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 (CAR_SAFE (elt));
+      xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
+      xd_signature_cat (signature, x);
+
+      if (!XD_BASIC_DBUS_TYPE (subtype))
+       wrong_type_argument (intern ("D-Bus"), CAR_SAFE (XD_NEXT_VALUE (elt)));
+
+      /* Second element.  */
+      elt = CDR_SAFE (XD_NEXT_VALUE (elt));
+      subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
+      xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
+      xd_signature_cat (signature, x);
+
+      if (!NILP (CDR_SAFE (XD_NEXT_VALUE (elt))))
+       wrong_type_argument (intern ("D-Bus"),
+                            CAR_SAFE (CDR_SAFE (XD_NEXT_VALUE (elt))));
+
+      /* Closing signature.  */
+      xd_signature_cat (signature, DBUS_DICT_ENTRY_END_CHAR_AS_STRING);
+      break;
+
+    default:
+      wrong_type_argument (intern ("D-Bus"), object);
+    }
+
+  XD_DEBUG_MESSAGE ("%s", signature);
+}
+
+/* Convert X to a signed integer with bounds LO and HI.  */
+static intmax_t
+xd_extract_signed (Lisp_Object x, intmax_t lo, intmax_t hi)
+{
+  CHECK_NUMBER_OR_FLOAT (x);
+  if (INTEGERP (x))
+    {
+      if (lo <= XINT (x) && XINT (x) <= hi)
+       return XINT (x);
+    }
+  else
+    {
+      double d = XFLOAT_DATA (x);
+      if (lo <= d && d <= hi)
+       {
+         intmax_t n = d;
+         if (n == d)
+           return n;
+       }
+    }
+  if (xd_in_read_queued_messages)
+    Fthrow (Qdbus_error, Qnil);
+  else
+    args_out_of_range_3 (x,
+                        make_fixnum_or_float (lo),
+                        make_fixnum_or_float (hi));
+}
+
+/* Convert X to an unsigned integer with bounds 0 and HI.  */
+static uintmax_t
+xd_extract_unsigned (Lisp_Object x, uintmax_t hi)
+{
+  CHECK_NUMBER_OR_FLOAT (x);
+  if (INTEGERP (x))
+    {
+      if (0 <= XINT (x) && XINT (x) <= hi)
+       return XINT (x);
+    }
+  else
+    {
+      double d = XFLOAT_DATA (x);
+      if (0 <= d && d <= hi)
+       {
+         uintmax_t n = d;
+         if (n == d)
+           return n;
+       }
+    }
+  if (xd_in_read_queued_messages)
+    Fthrow (Qdbus_error, Qnil);
+  else
+    args_out_of_range_3 (x, make_number (0), make_fixnum_or_float (hi));
+}
+
+/* Append C value, extracted from Lisp OBJECT, to iteration ITER.
+   DTYPE must be a valid DBusType.  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.  */
+static void
+xd_append_arg (int dtype, Lisp_Object object, DBusMessageIter *iter)
+{
+  char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
+  DBusMessageIter subiter;
+
+  if (XD_BASIC_DBUS_TYPE (dtype))
+    switch (dtype)
+      {
+      case DBUS_TYPE_BYTE:
+       CHECK_NATNUM (object);
+       {
+         unsigned char val = XFASTINT (object) & 0xFF;
+         XD_DEBUG_MESSAGE ("%c %u", dtype, val);
+         if (!dbus_message_iter_append_basic (iter, dtype, &val))
+           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
+         return;
+       }
+
+      case DBUS_TYPE_BOOLEAN:
+       {
+         dbus_bool_t val = (NILP (object)) ? FALSE : TRUE;
+         XD_DEBUG_MESSAGE ("%c %s", dtype, (val == FALSE) ? "false" : "true");
+         if (!dbus_message_iter_append_basic (iter, dtype, &val))
+           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
+         return;
+       }
+
+      case DBUS_TYPE_INT16:
+       {
+         dbus_int16_t val =
+           xd_extract_signed (object,
+                              TYPE_MINIMUM (dbus_int16_t),
+                              TYPE_MAXIMUM (dbus_int16_t));
+         int pval = val;
+         XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
+         if (!dbus_message_iter_append_basic (iter, dtype, &val))
+           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
+         return;
+       }
+
+      case DBUS_TYPE_UINT16:
+       {
+         dbus_uint16_t val =
+           xd_extract_unsigned (object,
+                                TYPE_MAXIMUM (dbus_uint16_t));
+         unsigned int pval = val;
+         XD_DEBUG_MESSAGE ("%c %u", dtype, pval);
+         if (!dbus_message_iter_append_basic (iter, dtype, &val))
+           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
+         return;
+       }
+
+      case DBUS_TYPE_INT32:
+       {
+         dbus_int32_t val =
+           xd_extract_signed (object,
+                              TYPE_MINIMUM (dbus_int32_t),
+                              TYPE_MAXIMUM (dbus_int32_t));
+         int pval = val;
+         XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
+         if (!dbus_message_iter_append_basic (iter, dtype, &val))
+           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
+         return;
+       }
+
+      case DBUS_TYPE_UINT32:
+#ifdef DBUS_TYPE_UNIX_FD
+      case DBUS_TYPE_UNIX_FD:
+#endif
+       {
+         dbus_uint32_t val =
+           xd_extract_unsigned (object,
+                                TYPE_MAXIMUM (dbus_uint32_t));
+         unsigned int pval = val;
+         XD_DEBUG_MESSAGE ("%c %u", dtype, pval);
+         if (!dbus_message_iter_append_basic (iter, dtype, &val))
+           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
+         return;
+       }
+
+      case DBUS_TYPE_INT64:
+       {
+         dbus_int64_t val =
+           xd_extract_signed (object,
+                              TYPE_MINIMUM (dbus_int64_t),
+                              TYPE_MAXIMUM (dbus_int64_t));
+         printmax_t pval = val;
+         XD_DEBUG_MESSAGE ("%c %"pMd, dtype, pval);
+         if (!dbus_message_iter_append_basic (iter, dtype, &val))
+           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
+         return;
+       }
+
+      case DBUS_TYPE_UINT64:
+       {
+         dbus_uint64_t val =
+           xd_extract_unsigned (object,
+                                TYPE_MAXIMUM (dbus_uint64_t));
+         uprintmax_t pval = val;
+         XD_DEBUG_MESSAGE ("%c %"pMu, dtype, pval);
+         if (!dbus_message_iter_append_basic (iter, dtype, &val))
+           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
+         return;
+       }
+
+      case DBUS_TYPE_DOUBLE:
+       {
+         double val = extract_float (object);
+         XD_DEBUG_MESSAGE ("%c %f", dtype, val);
+         if (!dbus_message_iter_append_basic (iter, dtype, &val))
+           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
+         return;
+       }
+
+      case DBUS_TYPE_STRING:
+      case DBUS_TYPE_OBJECT_PATH:
+      case DBUS_TYPE_SIGNATURE:
+       CHECK_STRING (object);
+       {
+         /* We need to send a valid UTF-8 string.  We could encode `object'
+            but by not encoding it, we guarantee it's valid utf-8, even if
+            it contains eight-bit-bytes.  Of course, you can still send
+            manually-crafted junk by passing a unibyte string.  */
+         char *val = SSDATA (object);
+         XD_DEBUG_MESSAGE ("%c %s", dtype, val);
+         if (!dbus_message_iter_append_basic (iter, dtype, &val))
+           XD_SIGNAL2 (build_string ("Unable to append argument"), object);
+         return;
+       }
+      }
+
+  else /* Compound types.  */
+    {
+
+      /* 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 (CAR_SAFE (object))))
+       object = XD_NEXT_VALUE (object);
+
+      /* Open new subiteration.  */
+      switch (dtype)
+       {
+       case DBUS_TYPE_ARRAY:
+         /* An array has only elements of the same type.  So it is
+            sufficient to check the first element's signature
+            only.  */
+
+         if (NILP (object))
+           /* If the array is empty, DBUS_TYPE_STRING is the default
+              element type.  */
+           strcpy (signature, DBUS_TYPE_STRING_AS_STRING);
+
+         else
+           /* If the element type is DBUS_TYPE_SIGNATURE, and this is
+              the only element, the value of this element is used as
+              the array's element signature.  */
+           if ((XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object))
+                == DBUS_TYPE_SIGNATURE)
+               && STRINGP (CAR_SAFE (XD_NEXT_VALUE (object)))
+               && NILP (CDR_SAFE (XD_NEXT_VALUE (object))))
+             {
+               strcpy (signature, SSDATA (CAR_SAFE (XD_NEXT_VALUE (object))));
+               object = CDR_SAFE (XD_NEXT_VALUE (object));
+             }
+
+           else
+             xd_signature (signature,
+                           XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object)),
+                           dtype, CAR_SAFE (XD_NEXT_VALUE (object)));
+
+         XD_DEBUG_MESSAGE ("%c %s %s", dtype, signature,
+                           XD_OBJECT_TO_STRING (object));
+         if (!dbus_message_iter_open_container (iter, dtype,
+                                                signature, &subiter))
+           XD_SIGNAL3 (build_string ("Cannot open container"),
+                       make_number (dtype), build_string (signature));
+         break;
+
+       case DBUS_TYPE_VARIANT:
+         /* A variant has just one element.  */
+         xd_signature (signature, XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object)),
+                       dtype, CAR_SAFE (XD_NEXT_VALUE (object)));
+
+         XD_DEBUG_MESSAGE ("%c %s %s", dtype, signature,
+                           XD_OBJECT_TO_STRING (object));
+         if (!dbus_message_iter_open_container (iter, dtype,
+                                                signature, &subiter))
+           XD_SIGNAL3 (build_string ("Cannot open container"),
+                       make_number (dtype), build_string (signature));
+         break;
+
+       case DBUS_TYPE_STRUCT:
+       case DBUS_TYPE_DICT_ENTRY:
+         /* These containers do not require a signature.  */
+         XD_DEBUG_MESSAGE ("%c %s", dtype, XD_OBJECT_TO_STRING (object));
+         if (!dbus_message_iter_open_container (iter, dtype, NULL, &subiter))
+           XD_SIGNAL2 (build_string ("Cannot open container"),
+                       make_number (dtype));
+         break;
+       }
+
+      /* Loop over list elements.  */
+      while (!NILP (object))
+       {
+         dtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object));
+         object = XD_NEXT_VALUE (object);
+
+         xd_append_arg (dtype, CAR_SAFE (object), &subiter);
+
+         object = CDR_SAFE (object);
+       }
+
+      /* Close the subiteration.  */
+      if (!dbus_message_iter_close_container (iter, &subiter))
+       XD_SIGNAL2 (build_string ("Cannot close container"),
+                   make_number (dtype));
+    }
+}
+
+/* Retrieve C value from a DBusMessageIter structure ITER, and return
+   a converted Lisp object.  The type DTYPE of the argument of the
+   D-Bus message must be a valid DBusType.  Compound D-Bus types
+   result always in a Lisp list.  */
+static Lisp_Object
+xd_retrieve_arg (int dtype, DBusMessageIter *iter)
+{
+
+  switch (dtype)
+    {
+    case DBUS_TYPE_BYTE:
+      {
+       unsigned int val;
+       dbus_message_iter_get_basic (iter, &val);
+       val = val & 0xFF;
+       XD_DEBUG_MESSAGE ("%c %u", dtype, val);
+       return make_number (val);
+      }
+
+    case DBUS_TYPE_BOOLEAN:
+      {
+       dbus_bool_t val;
+       dbus_message_iter_get_basic (iter, &val);
+       XD_DEBUG_MESSAGE ("%c %s", dtype, (val == FALSE) ? "false" : "true");
+       return (val == FALSE) ? Qnil : Qt;
+      }
+
+    case DBUS_TYPE_INT16:
+      {
+       dbus_int16_t val;
+       int pval;
+       dbus_message_iter_get_basic (iter, &val);
+       pval = val;
+       XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
+       return make_number (val);
+      }
+
+    case DBUS_TYPE_UINT16:
+      {
+       dbus_uint16_t val;
+       int pval;
+       dbus_message_iter_get_basic (iter, &val);
+       pval = val;
+       XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
+       return make_number (val);
+      }
+
+    case DBUS_TYPE_INT32:
+      {
+       dbus_int32_t val;
+       int pval;
+       dbus_message_iter_get_basic (iter, &val);
+       pval = val;
+       XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
+       return make_fixnum_or_float (val);
+      }
+
+    case DBUS_TYPE_UINT32:
+#ifdef DBUS_TYPE_UNIX_FD
+    case DBUS_TYPE_UNIX_FD:
+#endif
+      {
+       dbus_uint32_t val;
+       unsigned int pval = val;
+       dbus_message_iter_get_basic (iter, &val);
+       pval = val;
+       XD_DEBUG_MESSAGE ("%c %u", dtype, pval);
+       return make_fixnum_or_float (val);
+      }
+
+    case DBUS_TYPE_INT64:
+      {
+       dbus_int64_t val;
+       printmax_t pval;
+       dbus_message_iter_get_basic (iter, &val);
+       pval = val;
+       XD_DEBUG_MESSAGE ("%c %"pMd, dtype, pval);
+       return make_fixnum_or_float (val);
+      }
+
+    case DBUS_TYPE_UINT64:
+      {
+       dbus_uint64_t val;
+       uprintmax_t pval;
+       dbus_message_iter_get_basic (iter, &val);
+       pval = val;
+       XD_DEBUG_MESSAGE ("%c %"pMd, dtype, pval);
+       return make_fixnum_or_float (val);
+      }
+
+    case DBUS_TYPE_DOUBLE:
+      {
+       double val;
+       dbus_message_iter_get_basic (iter, &val);
+       XD_DEBUG_MESSAGE ("%c %f", dtype, val);
+       return make_float (val);
+      }
+
+    case DBUS_TYPE_STRING:
+    case DBUS_TYPE_OBJECT_PATH:
+    case DBUS_TYPE_SIGNATURE:
+      {
+       char *val;
+       dbus_message_iter_get_basic (iter, &val);
+       XD_DEBUG_MESSAGE ("%c %s", dtype, val);
+       return build_string (val);
+      }
+
+    case DBUS_TYPE_ARRAY:
+    case DBUS_TYPE_VARIANT:
+    case DBUS_TYPE_STRUCT:
+    case DBUS_TYPE_DICT_ENTRY:
+      {
+       Lisp_Object result;
+       struct gcpro gcpro1;
+       DBusMessageIter subiter;
+       int subtype;
+       result = Qnil;
+       GCPRO1 (result);
+       dbus_message_iter_recurse (iter, &subiter);
+       while ((subtype = dbus_message_iter_get_arg_type (&subiter))
+              != DBUS_TYPE_INVALID)
+         {
+           result = Fcons (xd_retrieve_arg (subtype, &subiter), result);
+           dbus_message_iter_next (&subiter);
+         }
+       XD_DEBUG_MESSAGE ("%c %s", dtype, XD_OBJECT_TO_STRING (result));
+       RETURN_UNGCPRO (Fnreverse (result));
+      }
+
+    default:
+      XD_DEBUG_MESSAGE ("DBusType '%c' not supported", dtype);
+      return Qnil;
+    }
+}
+
+/* Return the number of references of the shared CONNECTION.  */
+static ptrdiff_t
+xd_get_connection_references (DBusConnection *connection)
+{
+  ptrdiff_t *refcount;
+
+  /* We cannot access the DBusConnection structure, it is not public.
+     But we know, that the reference counter is the first field in
+     that structure.  */
+  refcount = (void *) &connection;
+  refcount =  (void *) *refcount;
+  return *refcount;
+}
+
+/* Return D-Bus connection address.  BUS is either a Lisp symbol,
+   :system or :session, or a string denoting the bus address.  */
+static DBusConnection *
+xd_get_connection_address (Lisp_Object bus)
+{
+  DBusConnection *connection;
+  Lisp_Object val;
+
+  val = CDR_SAFE (Fassoc (bus, xd_registered_buses));
+  if (NILP (val))
+    XD_SIGNAL2 (build_string ("No connection to bus"), bus);
+  else
+    connection = (DBusConnection *) (intptr_t) XFASTINT (val);
+
+  if (!dbus_connection_get_is_connected (connection))
+    XD_SIGNAL2 (build_string ("No connection to bus"), bus);
+
+  return connection;
+}
+
+/* Return the file descriptor for WATCH, -1 if not found.  */
+static int
+xd_find_watch_fd (DBusWatch *watch)
+{
+#if HAVE_DBUS_WATCH_GET_UNIX_FD
+  /* TODO: Reverse these on Win32, which prefers the opposite.  */
+  int fd = dbus_watch_get_unix_fd (watch);
+  if (fd == -1)
+    fd = dbus_watch_get_socket (watch);
+#else
+  int fd = dbus_watch_get_fd (watch);
+#endif
+  return fd;
+}
+
+/* Prototype.  */
+static void
+xd_read_queued_messages (int fd, void *data, int for_read);
+
+/* Start monitoring WATCH for possible I/O.  */
+static dbus_bool_t
+xd_add_watch (DBusWatch *watch, void *data)
+{
+  unsigned int flags = dbus_watch_get_flags (watch);
+  int fd = xd_find_watch_fd (watch);
+
+  XD_DEBUG_MESSAGE ("fd %d, write %d, enabled %d",
+                   fd, flags & DBUS_WATCH_WRITABLE,
+                   dbus_watch_get_enabled (watch));
+
+  if (fd == -1)
+    return FALSE;
+
+  if (dbus_watch_get_enabled (watch))
+    {
+      if (flags & DBUS_WATCH_WRITABLE)
+        add_write_fd (fd, xd_read_queued_messages, data);
+      if (flags & DBUS_WATCH_READABLE)
+        add_read_fd (fd, xd_read_queued_messages, data);
+    }
+  return TRUE;
+}
+
+/* Stop monitoring WATCH for possible I/O.
+   DATA is the used bus, either a string or QCdbus_system_bus or
+   QCdbus_session_bus.  */
+static void
+xd_remove_watch (DBusWatch *watch, void *data)
+{
+  unsigned int flags = dbus_watch_get_flags (watch);
+  int fd = xd_find_watch_fd (watch);
+
+  XD_DEBUG_MESSAGE ("fd %d", fd);
+
+  if (fd == -1)
+    return;
+
+  /* Unset session environment.  */
+  if (XSYMBOL (QCdbus_session_bus) == data)
+    {
+      //      XD_DEBUG_MESSAGE ("unsetenv DBUS_SESSION_BUS_ADDRESS");
+      //      unsetenv ("DBUS_SESSION_BUS_ADDRESS");
+    }
+
+  if (flags & DBUS_WATCH_WRITABLE)
+    delete_write_fd (fd);
+  if (flags & DBUS_WATCH_READABLE)
+    delete_read_fd (fd);
+}
+
+/* Toggle monitoring WATCH for possible I/O.  */
+static void
+xd_toggle_watch (DBusWatch *watch, void *data)
+{
+  if (dbus_watch_get_enabled (watch))
+    xd_add_watch (watch, data);
+  else
+    xd_remove_watch (watch, data);
+}
+
+/* Close connection to D-Bus BUS.  */
+static void
+xd_close_bus (Lisp_Object bus)
+{
+  DBusConnection *connection;
+  Lisp_Object val;
+
+  /* Check whether we are connected.  */
+  val = Fassoc (bus, xd_registered_buses);
+  if (NILP (val))
+    return;
+
+  /* Retrieve bus address.  */
+  connection = xd_get_connection_address (bus);
+
+  /* Close connection, if there isn't another shared application.  */
+  if (xd_get_connection_references (connection) == 1)
+    {
+      XD_DEBUG_MESSAGE ("Close connection to bus %s",
+                       XD_OBJECT_TO_STRING (bus));
+      dbus_connection_close (connection);
+    }
+
+  /* Decrement reference count.  */
+  dbus_connection_unref (connection);
+
+  /* Remove bus from list of registered buses.  */
+  xd_registered_buses = Fdelete (val, xd_registered_buses);
+
+  /* Return.  */
+  return;
+}
+
+DEFUN ("dbus-init-bus", Fdbus_init_bus, Sdbus_init_bus, 1, 2, 0,
+       doc: /* Establish the connection to D-Bus BUS.
+
+BUS can be either the symbol `:system' or the symbol `:session', or it
+can be a string denoting the address of the corresponding bus.  For
+the system and session buses, this function is called when loading
+`dbus.el', there is no need to call it again.
+
+The function returns a number, which counts the connections this Emacs
+session has established to the BUS under the same unique name (see
+`dbus-get-unique-name').  It depends on the libraries Emacs is linked
+with, and on the environment Emacs is running.  For example, if Emacs
+is linked with the gtk toolkit, and it runs in a GTK-aware environment
+like Gnome, another connection might already be established.
+
+When PRIVATE is non-nil, a new connection is established instead of
+reusing an existing one.  It results in a new unique name at the bus.
+This can be used, if it is necessary to distinguish from another
+connection used in the same Emacs process, like the one established by
+GTK+.  It should be used with care for at least the `:system' and
+`:session' buses, because other Emacs Lisp packages might already use
+this connection to those buses.  */)
+  (Lisp_Object bus, Lisp_Object private)
+{
+  DBusConnection *connection;
+  DBusError derror;
+  Lisp_Object val;
+  ptrdiff_t refcount;
+
+  /* Check parameter.  */
+  XD_DBUS_VALIDATE_BUS_ADDRESS (bus);
+
+  /* Close bus if it is already open.  */
+  xd_close_bus (bus);
+
+  /* Initialize.  */
+  dbus_error_init (&derror);
+
+  /* Open the connection.  */
+  if (STRINGP (bus))
+    if (NILP (private))
+      connection = dbus_connection_open (SSDATA (bus), &derror);
+    else
+      connection = dbus_connection_open_private (SSDATA (bus), &derror);
+
+  else
+    if (NILP (private))
+      connection = dbus_bus_get (EQ (bus, QCdbus_system_bus)
+                                ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION,
+                                &derror);
+    else
+      connection = dbus_bus_get_private (EQ (bus, QCdbus_system_bus)
+                                        ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION,
+                                        &derror);
+
+  if (dbus_error_is_set (&derror))
+    XD_ERROR (derror);
+
+  if (connection == NULL)
+    XD_SIGNAL2 (build_string ("No connection to bus"), bus);
+
+  /* If it is not the system or session bus, we must register
+     ourselves.  Otherwise, we have called dbus_bus_get, which has
+     configured us to exit if the connection closes - we undo this
+     setting.  */
+  if (STRINGP (bus))
+    dbus_bus_register (connection, &derror);
+  else
+    dbus_connection_set_exit_on_disconnect (connection, FALSE);
+
+  if (dbus_error_is_set (&derror))
+    XD_ERROR (derror);
+
+  /* Add the watch functions.  We pass also the bus as data, in order
+     to distinguish between the buses in xd_remove_watch.  */
+  if (!dbus_connection_set_watch_functions (connection,
+                                           xd_add_watch,
+                                           xd_remove_watch,
+                                            xd_toggle_watch,
+                                           SYMBOLP (bus)
+                                           ? (void *) XSYMBOL (bus)
+                                           : (void *) XSTRING (bus),
+                                           NULL))
+    XD_SIGNAL1 (build_string ("Cannot add watch functions"));
+
+  /* Add bus to list of registered buses.  */
+  XSETFASTINT (val, (intptr_t) connection);
+  xd_registered_buses = Fcons (Fcons (bus, val), xd_registered_buses);
+
+  /* We do not want to abort.  */
+  putenv ((char *) "DBUS_FATAL_WARNINGS=0");
+
+  /* Cleanup.  */
+  dbus_error_free (&derror);
+
+  /* Return reference counter.  */
+  refcount = xd_get_connection_references (connection);
+  XD_DEBUG_MESSAGE ("Bus %s, Reference counter %"pD"d",
+                   XD_OBJECT_TO_STRING (bus), refcount);
+  return make_number (refcount);
+}
+
+DEFUN ("dbus-get-unique-name", Fdbus_get_unique_name, Sdbus_get_unique_name,
+       1, 1, 0,
+       doc: /* Return the unique name of Emacs registered at D-Bus BUS.  */)
+  (Lisp_Object bus)
+{
+  DBusConnection *connection;
+  const char *name;
+
+  /* Check parameter.  */
+  XD_DBUS_VALIDATE_BUS_ADDRESS (bus);
+
+  /* Retrieve bus address.  */
+  connection = xd_get_connection_address (bus);
+
+  /* Request the name.  */
+  name = dbus_bus_get_unique_name (connection);
+  if (name == NULL)
+    XD_SIGNAL1 (build_string ("No unique name available"));
+
+  /* Return.  */
+  return build_string (name);
+}
+
+DEFUN ("dbus-message-internal", Fdbus_message_internal, Sdbus_message_internal,
+       4, MANY, 0,
+       doc: /* Send a D-Bus message.
+This is an internal function, it shall not be used outside dbus.el.
+
+The following usages are expected:
+
+`dbus-call-method', `dbus-call-method-asynchronously':
+  \(dbus-message-internal
+    dbus-message-type-method-call BUS SERVICE PATH INTERFACE METHOD HANDLER
+    &optional :timeout TIMEOUT &rest ARGS)
+
+`dbus-send-signal':
+  \(dbus-message-internal
+    dbus-message-type-signal BUS SERVICE PATH INTERFACE SIGNAL &rest ARGS)
+
+`dbus-method-return-internal':
+  \(dbus-message-internal
+    dbus-message-type-method-return BUS SERVICE SERIAL &rest ARGS)
+
+`dbus-method-error-internal':
+  \(dbus-message-internal
+    dbus-message-type-error BUS SERVICE SERIAL &rest ARGS)
+
+usage: (dbus-message-internal &rest REST)  */)
+  (ptrdiff_t nargs, Lisp_Object *args)
+{
+  Lisp_Object message_type, bus, service, handler;
+  Lisp_Object path = Qnil;
+  Lisp_Object interface = Qnil;
+  Lisp_Object member = Qnil;
+  Lisp_Object result;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
+  DBusConnection *connection;
+  DBusMessage *dmessage;
+  DBusMessageIter iter;
+  int dtype;
+  int mtype;
+  dbus_uint32_t serial = 0;
+  unsigned int ui_serial;
+  int timeout = -1;
+  ptrdiff_t count;
+  char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
+
+  /* Initialize parameters.  */
+  message_type = args[0];
+  bus = args[1];
+  service = args[2];
+  handler = Qnil;
+
+  CHECK_NATNUM (message_type);
+  if (! (DBUS_MESSAGE_TYPE_INVALID < XFASTINT (message_type)
+        && XFASTINT (message_type) < DBUS_NUM_MESSAGE_TYPES))
+    XD_SIGNAL2 (build_string ("Invalid message type"), message_type);
+  mtype = XFASTINT (message_type);
+
+  if ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
+      || (mtype == DBUS_MESSAGE_TYPE_SIGNAL))
+    {
+      path = args[3];
+      interface = args[4];
+      member = args[5];
+      if (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
+       handler = args[6];
+      count = (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) ? 7 : 6;
+    }
+  else /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR  */
+    {
+      serial = xd_extract_unsigned (args[3], TYPE_MAXIMUM (dbus_uint32_t));
+      count = 4;
+    }
+
+  /* Check parameters.  */
+  XD_DBUS_VALIDATE_BUS_ADDRESS (bus);
+  XD_DBUS_VALIDATE_BUS_NAME (service);
+  if (nargs < count)
+    xsignal2 (Qwrong_number_of_arguments,
+             Qdbus_message_internal,
+             make_number (nargs));
+
+  if ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
+      || (mtype == DBUS_MESSAGE_TYPE_SIGNAL))
+    {
+      XD_DBUS_VALIDATE_PATH (path);
+      XD_DBUS_VALIDATE_INTERFACE (interface);
+      XD_DBUS_VALIDATE_MEMBER (member);
+      if (!NILP (handler) && (!FUNCTIONP (handler)))
+       wrong_type_argument (Qinvalid_function, handler);
+    }
+
+  /* Protect Lisp variables.  */
+  GCPRO6 (bus, service, path, interface, member, handler);
+
+  /* Trace parameters.  */
+  switch (mtype)
+    {
+    case DBUS_MESSAGE_TYPE_METHOD_CALL:
+      XD_DEBUG_MESSAGE ("%s %s %s %s %s %s %s",
+                       XD_MESSAGE_TYPE_TO_STRING (mtype),
+                       XD_OBJECT_TO_STRING (bus),
+                       XD_OBJECT_TO_STRING (service),
+                       XD_OBJECT_TO_STRING (path),
+                       XD_OBJECT_TO_STRING (interface),
+                       XD_OBJECT_TO_STRING (member),
+                       XD_OBJECT_TO_STRING (handler));
+      break;
+    case DBUS_MESSAGE_TYPE_SIGNAL:
+      XD_DEBUG_MESSAGE ("%s %s %s %s %s %s",
+                       XD_MESSAGE_TYPE_TO_STRING (mtype),
+                       XD_OBJECT_TO_STRING (bus),
+                       XD_OBJECT_TO_STRING (service),
+                       XD_OBJECT_TO_STRING (path),
+                       XD_OBJECT_TO_STRING (interface),
+                       XD_OBJECT_TO_STRING (member));
+      break;
+    default: /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR  */
+      ui_serial = serial;
+      XD_DEBUG_MESSAGE ("%s %s %s %u",
+                       XD_MESSAGE_TYPE_TO_STRING (mtype),
+                       XD_OBJECT_TO_STRING (bus),
+                       XD_OBJECT_TO_STRING (service),
+                       ui_serial);
+    }
+
+  /* Retrieve bus address.  */
+  connection = xd_get_connection_address (bus);
+
+  /* Create the D-Bus message.  */
+  dmessage = dbus_message_new (mtype);
+  if (dmessage == NULL)
+    {
+      UNGCPRO;
+      XD_SIGNAL1 (build_string ("Unable to create a new message"));
+    }
+
+  if (STRINGP (service))
+    {
+      if (mtype != DBUS_MESSAGE_TYPE_SIGNAL)
+       /* Set destination.  */
+       {
+         if (!dbus_message_set_destination (dmessage, SSDATA (service)))
+           {
+             UNGCPRO;
+             XD_SIGNAL2 (build_string ("Unable to set the destination"),
+                         service);
+           }
+       }
+
+      else
+       /* Set destination for unicast signals.  */
+       {
+         Lisp_Object uname;
+
+         /* If it is the same unique name as we are registered at the
+            bus or an unknown name, we regard it as broadcast message
+            due to backward compatibility.  */
+         if (dbus_bus_name_has_owner (connection, SSDATA (service), NULL))
+           uname = call2 (intern ("dbus-get-name-owner"), bus, service);
+         else
+           uname = Qnil;
+
+         if (STRINGP (uname)
+             && (strcmp (dbus_bus_get_unique_name (connection), SSDATA (uname))
+                 != 0)
+             && (!dbus_message_set_destination (dmessage, SSDATA (service))))
+           {
+             UNGCPRO;
+             XD_SIGNAL2 (build_string ("Unable to set signal destination"),
+                         service);
+           }
+       }
+    }
+
+  /* Set message parameters.  */
+  if ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
+      || (mtype == DBUS_MESSAGE_TYPE_SIGNAL))
+    {
+      if ((!dbus_message_set_path (dmessage, SSDATA (path)))
+         || (!dbus_message_set_interface (dmessage, SSDATA (interface)))
+         || (!dbus_message_set_member (dmessage, SSDATA (member))))
+       {
+         UNGCPRO;
+         XD_SIGNAL1 (build_string ("Unable to set the message parameter"));
+       }
+    }
+
+  else /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR  */
+    {
+      if (!dbus_message_set_reply_serial (dmessage, serial))
+       {
+         UNGCPRO;
+         XD_SIGNAL1 (build_string ("Unable to create a return message"));
+       }
+
+      if ((mtype == DBUS_MESSAGE_TYPE_ERROR)
+         && (!dbus_message_set_error_name (dmessage, DBUS_ERROR_FAILED)))
+       {
+         UNGCPRO;
+         XD_SIGNAL1 (build_string ("Unable to create a error message"));
+       }
+    }
+
+  /* Check for timeout parameter.  */
+  if ((count+2 <= nargs) && (EQ ((args[count]), QCdbus_timeout)))
+    {
+      CHECK_NATNUM (args[count+1]);
+      timeout = min (XFASTINT (args[count+1]), INT_MAX);
+      count = count+2;
+    }
+
+  /* Initialize parameter list of message.  */
+  dbus_message_iter_init_append (dmessage, &iter);
+
+  /* Append parameters to the message.  */
+  for (; count < nargs; ++count)
+    {
+      dtype = XD_OBJECT_TO_DBUS_TYPE (args[count]);
+      if (XD_DBUS_TYPE_P (args[count]))
+       {
+         XD_DEBUG_VALID_LISP_OBJECT_P (args[count]);
+         XD_DEBUG_VALID_LISP_OBJECT_P (args[count+1]);
+         XD_DEBUG_MESSAGE ("Parameter%"pD"d %s %s", count - 4,
+                           XD_OBJECT_TO_STRING (args[count]),
+                           XD_OBJECT_TO_STRING (args[count+1]));
+         ++count;
+       }
+      else
+       {
+         XD_DEBUG_VALID_LISP_OBJECT_P (args[count]);
+         XD_DEBUG_MESSAGE ("Parameter%"pD"d %s", count - 4,
+                           XD_OBJECT_TO_STRING (args[count]));
+       }
+
+      /* Check for valid signature.  We use DBUS_TYPE_INVALID as
+        indication that there is no parent type.  */
+      xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[count]);
+
+      xd_append_arg (dtype, args[count], &iter);
+    }
+
+  if (!NILP (handler))
+    {
+      /* Send the message.  The message is just added to the outgoing
+        message queue.  */
+      if (!dbus_connection_send_with_reply (connection, dmessage,
+                                           NULL, timeout))
+       {
+         UNGCPRO;
+         XD_SIGNAL1 (build_string ("Cannot send message"));
+       }
+
+      /* The result is the key in Vdbus_registered_objects_table.  */
+      serial = dbus_message_get_serial (dmessage);
+      result = list3 (QCdbus_registered_serial,
+                     bus, make_fixnum_or_float (serial));
+
+      /* Create a hash table entry.  */
+      Fputhash (result, handler, Vdbus_registered_objects_table);
+    }
+  else
+    {
+      /* Send the message.  The message is just added to the outgoing
+        message queue.  */
+      if (!dbus_connection_send (connection, dmessage, NULL))
+       {
+         UNGCPRO;
+         XD_SIGNAL1 (build_string ("Cannot send message"));
+       }
+
+      result = Qnil;
+    }
+
+  XD_DEBUG_MESSAGE ("Message sent: %s", XD_OBJECT_TO_STRING (result));
+
+  /* Cleanup.  */
+  dbus_message_unref (dmessage);
+
+  /* Return the result.  */
+  RETURN_UNGCPRO (result);
+}
+
+/* Read one queued incoming message of the D-Bus BUS.
+   BUS is either a Lisp symbol, :system or :session, or a string denoting
+   the bus address.  */
+static void
+xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
+{
+  Lisp_Object args, key, value;
+  struct gcpro gcpro1;
+  struct input_event event;
+  DBusMessage *dmessage;
+  DBusMessageIter iter;
+  int dtype;
+  int mtype;
+  dbus_uint32_t serial;
+  unsigned int ui_serial;
+  const char *uname, *path, *interface, *member;
+
+  dmessage = dbus_connection_pop_message (connection);
+
+  /* Return if there is no queued message.  */
+  if (dmessage == NULL)
+    return;
+
+  /* Collect the parameters.  */
+  args = Qnil;
+  GCPRO1 (args);
+
+  /* Loop over the resulting parameters.  Construct a list.  */
+  if (dbus_message_iter_init (dmessage, &iter))
+    {
+      while ((dtype = dbus_message_iter_get_arg_type (&iter))
+            != DBUS_TYPE_INVALID)
+       {
+         args = Fcons (xd_retrieve_arg (dtype, &iter), args);
+         dbus_message_iter_next (&iter);
+       }
+      /* The arguments are stored in reverse order.  Reorder them.  */
+      args = Fnreverse (args);
+    }
+
+  /* Read message type, message serial, unique name, object path,
+     interface and member from the message.  */
+  mtype = dbus_message_get_type (dmessage);
+  ui_serial = serial =
+    ((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)
+     || (mtype == DBUS_MESSAGE_TYPE_ERROR))
+    ? dbus_message_get_reply_serial (dmessage)
+    : dbus_message_get_serial (dmessage);
+  uname = dbus_message_get_sender (dmessage);
+  path = dbus_message_get_path (dmessage);
+  interface = dbus_message_get_interface (dmessage);
+  member = dbus_message_get_member (dmessage);
+
+  XD_DEBUG_MESSAGE ("Event received: %s %u %s %s %s %s %s",
+                   XD_MESSAGE_TYPE_TO_STRING (mtype),
+                   ui_serial, uname, path, interface, member,
+                   XD_OBJECT_TO_STRING (args));
+
+  if (mtype == DBUS_MESSAGE_TYPE_INVALID)
+    goto cleanup;
+
+  else if ((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)
+          || (mtype == DBUS_MESSAGE_TYPE_ERROR))
+    {
+      /* Search for a registered function of the message.  */
+      key = list3 (QCdbus_registered_serial, bus,
+                  make_fixnum_or_float (serial));
+      value = Fgethash (key, Vdbus_registered_objects_table, Qnil);
+
+      /* There shall be exactly one entry.  Construct an event.  */
+      if (NILP (value))
+       goto cleanup;
+
+      /* Remove the entry.  */
+      Fremhash (key, Vdbus_registered_objects_table);
+
+      /* Construct an event.  */
+      EVENT_INIT (event);
+      event.kind = DBUS_EVENT;
+      event.frame_or_window = Qnil;
+      event.arg = Fcons (value, args);
+    }
+
+  else /* DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_SIGNAL.  */
+    {
+      /* Vdbus_registered_objects_table requires non-nil interface and
+        member.  */
+      if ((interface == NULL) || (member == NULL))
+       goto cleanup;
+
+      /* Search for a registered function of the message.  */
+      key = list4 ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
+                  ? QCdbus_registered_method
+                  : QCdbus_registered_signal,
+                  bus, build_string (interface), build_string (member));
+      value = Fgethash (key, Vdbus_registered_objects_table, Qnil);
+
+      /* Loop over the registered functions.  Construct an event.  */
+      while (!NILP (value))
+       {
+         key = CAR_SAFE (value);
+         /* key has the structure (UNAME SERVICE PATH HANDLER).  */
+         if (((uname == NULL)
+              || (NILP (CAR_SAFE (key)))
+              || (strcmp (uname, SSDATA (CAR_SAFE (key))) == 0))
+             && ((path == NULL)
+                 || (NILP (CAR_SAFE (CDR_SAFE (CDR_SAFE (key)))))
+                 || (strcmp (path,
+                             SSDATA (CAR_SAFE (CDR_SAFE (CDR_SAFE (key)))))
+                     == 0))
+             && (!NILP (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key)))))))
+           {
+             EVENT_INIT (event);
+             event.kind = DBUS_EVENT;
+             event.frame_or_window = Qnil;
+             event.arg
+               = Fcons (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key)))), args);
+             break;
+           }
+         value = CDR_SAFE (value);
+       }
+
+      if (NILP (value))
+       goto cleanup;
+    }
+
+  /* Add type, serial, uname, path, interface and member to the event.  */
+  event.arg = Fcons ((member == NULL ? Qnil : build_string (member)),
+                    event.arg);
+  event.arg = Fcons ((interface == NULL ? Qnil : build_string (interface)),
+                    event.arg);
+  event.arg = Fcons ((path == NULL ? Qnil : build_string (path)),
+                    event.arg);
+  event.arg = Fcons ((uname == NULL ? Qnil : build_string (uname)),
+                    event.arg);
+  event.arg = Fcons (make_fixnum_or_float (serial), event.arg);
+  event.arg = Fcons (make_number (mtype), event.arg);
+
+  /* Add the bus symbol to the event.  */
+  event.arg = Fcons (bus, event.arg);
+
+  /* Store it into the input event queue.  */
+  kbd_buffer_store_event (&event);
+
+  XD_DEBUG_MESSAGE ("Event stored: %s", XD_OBJECT_TO_STRING (event.arg));
+
+  /* Cleanup.  */
+ cleanup:
+  dbus_message_unref (dmessage);
+
+  UNGCPRO;
+}
+
+/* Read queued incoming messages of the D-Bus BUS.
+   BUS is either a Lisp symbol, :system or :session, or a string denoting
+   the bus address.  */
+static Lisp_Object
+xd_read_message (Lisp_Object bus)
+{
+  /* Retrieve bus address.  */
+  DBusConnection *connection = xd_get_connection_address (bus);
+
+  /* Non blocking read of the next available message.  */
+  dbus_connection_read_write (connection, 0);
+
+  while (dbus_connection_get_dispatch_status (connection)
+         != DBUS_DISPATCH_COMPLETE)
+    xd_read_message_1 (connection, bus);
+  return Qnil;
+}
+
+/* Callback called when something is ready to read or write.  */
+static void
+xd_read_queued_messages (int fd, void *data, int for_read)
+{
+  Lisp_Object busp = xd_registered_buses;
+  Lisp_Object bus = Qnil;
+  Lisp_Object key;
+
+  /* Find bus related to fd.  */
+  if (data != NULL)
+    while (!NILP (busp))
+      {
+       key = CAR_SAFE (CAR_SAFE (busp));
+       if ((SYMBOLP (key) && XSYMBOL (key) == data)
+           || (STRINGP (key) && XSTRING (key) == data))
+         bus = key;
+       busp = CDR_SAFE (busp);
+      }
+
+  if (NILP (bus))
+    return;
+
+  /* We ignore all Lisp errors during the call.  */
+  xd_in_read_queued_messages = 1;
+  internal_catch (Qdbus_error, xd_read_message, bus);
+  xd_in_read_queued_messages = 0;
+}
+
+\f
+void
+syms_of_dbusbind (void)
+{
+
+  DEFSYM (Qdbus_init_bus, "dbus-init-bus");
+  defsubr (&Sdbus_init_bus);
+
+  DEFSYM (Qdbus_get_unique_name, "dbus-get-unique-name");
+  defsubr (&Sdbus_get_unique_name);
+
+  DEFSYM (Qdbus_message_internal, "dbus-message-internal");
+  defsubr (&Sdbus_message_internal);
+
+  DEFSYM (Qdbus_error, "dbus-error");
+  Fput (Qdbus_error, Qerror_conditions,
+       list2 (Qdbus_error, Qerror));
+  Fput (Qdbus_error, Qerror_message,
+       make_pure_c_string ("D-Bus error"));
+
+  DEFSYM (QCdbus_system_bus, ":system");
+  DEFSYM (QCdbus_session_bus, ":session");
+  DEFSYM (QCdbus_timeout, ":timeout");
+  DEFSYM (QCdbus_type_byte, ":byte");
+  DEFSYM (QCdbus_type_boolean, ":boolean");
+  DEFSYM (QCdbus_type_int16, ":int16");
+  DEFSYM (QCdbus_type_uint16, ":uint16");
+  DEFSYM (QCdbus_type_int32, ":int32");
+  DEFSYM (QCdbus_type_uint32, ":uint32");
+  DEFSYM (QCdbus_type_int64, ":int64");
+  DEFSYM (QCdbus_type_uint64, ":uint64");
+  DEFSYM (QCdbus_type_double, ":double");
+  DEFSYM (QCdbus_type_string, ":string");
+  DEFSYM (QCdbus_type_object_path, ":object-path");
+  DEFSYM (QCdbus_type_signature, ":signature");
+#ifdef DBUS_TYPE_UNIX_FD
+  DEFSYM (QCdbus_type_unix_fd, ":unix-fd");
+#endif
+  DEFSYM (QCdbus_type_array, ":array");
+  DEFSYM (QCdbus_type_variant, ":variant");
+  DEFSYM (QCdbus_type_struct, ":struct");
+  DEFSYM (QCdbus_type_dict_entry, ":dict-entry");
+  DEFSYM (QCdbus_registered_serial, ":serial");
+  DEFSYM (QCdbus_registered_method, ":method");
+  DEFSYM (QCdbus_registered_signal, ":signal");
+
+  DEFVAR_LISP ("dbus-compiled-version",
+              Vdbus_compiled_version,
+    doc: /* The version of D-Bus Emacs is compiled against.  */);
+#ifdef DBUS_VERSION_STRING
+  Vdbus_compiled_version = make_pure_c_string (DBUS_VERSION_STRING);
+#else
+  Vdbus_compiled_version = Qnil;
+#endif
+
+  DEFVAR_LISP ("dbus-runtime-version",
+              Vdbus_runtime_version,
+    doc: /* The version of D-Bus Emacs runs with.  */);
+  {
+#ifdef DBUS_VERSION
+    int major, minor, micro;
+    char s[sizeof ".." + 3 * INT_STRLEN_BOUND (int)];
+    dbus_get_version (&major, &minor, &micro);
+    sprintf (s, "%d.%d.%d", major, minor, micro);
+    Vdbus_runtime_version = build_string (s);
+#else
+    Vdbus_runtime_version = Qnil;
+#endif
+  }
+
+  DEFVAR_LISP ("dbus-message-type-invalid",
+              Vdbus_message_type_invalid,
+    doc: /* This value is never a valid message type.  */);
+  Vdbus_message_type_invalid = make_number (DBUS_MESSAGE_TYPE_INVALID);
+
+  DEFVAR_LISP ("dbus-message-type-method-call",
+              Vdbus_message_type_method_call,
+    doc: /* Message type of a method call message.  */);
+  Vdbus_message_type_method_call = make_number (DBUS_MESSAGE_TYPE_METHOD_CALL);
+
+  DEFVAR_LISP ("dbus-message-type-method-return",
+              Vdbus_message_type_method_return,
+    doc: /* Message type of a method return message.  */);
+  Vdbus_message_type_method_return
+    = make_number (DBUS_MESSAGE_TYPE_METHOD_RETURN);
+
+  DEFVAR_LISP ("dbus-message-type-error",
+              Vdbus_message_type_error,
+    doc: /* Message type of an error reply message.  */);
+  Vdbus_message_type_error = make_number (DBUS_MESSAGE_TYPE_ERROR);
+
+  DEFVAR_LISP ("dbus-message-type-signal",
+              Vdbus_message_type_signal,
+    doc: /* Message type of a signal message.  */);
+  Vdbus_message_type_signal = make_number (DBUS_MESSAGE_TYPE_SIGNAL);
+
+  DEFVAR_LISP ("dbus-registered-objects-table",
+              Vdbus_registered_objects_table,
+    doc: /* Hash table of registered functions for D-Bus.
+
+There are two different uses of the hash table: for accessing
+registered interfaces properties, targeted by signals or method calls,
+and for calling handlers in case of non-blocking method call returns.
+
+In the first case, the key in the hash table is the list (TYPE BUS
+INTERFACE MEMBER).  TYPE is one of the Lisp symbols `:method',
+`:signal' or `:property'.  BUS is either a Lisp symbol, `:system' or
+`:session', or a string denoting the bus address.  INTERFACE is a
+string which denotes a D-Bus interface, and MEMBER, also a string, is
+either a method, a signal or a property INTERFACE is offering.  All
+arguments but BUS must not be nil.
+
+The value in the hash table is a list of quadruple lists \((UNAME
+SERVICE PATH OBJECT [RULE]) ...).  SERVICE is the service name as
+registered, UNAME is the corresponding unique name.  In case of
+registered methods and properties, UNAME is nil.  PATH is the object
+path of the sending object.  All of them can be nil, which means a
+wildcard then.  OBJECT is either the handler to be called when a D-Bus
+message, which matches the key criteria, arrives (TYPE `:method' and
+`:signal'), or a cons cell containing the value of the property (TYPE
+`:property').
+
+For entries of type `:signal', there is also a fifth element RULE,
+which keeps the match string the signal is registered with.
+
+In the second case, the key in the hash table is the list (:serial BUS
+SERIAL).  BUS is either a Lisp symbol, `:system' or `:session', or a
+string denoting the bus address.  SERIAL is the serial number of the
+non-blocking method call, a reply is expected.  Both arguments must
+not be nil.  The value in the hash table is HANDLER, the function to
+be called when the D-Bus reply message arrives.  */);
+  {
+    Lisp_Object args[2];
+    args[0] = QCtest;
+    args[1] = Qequal;
+    Vdbus_registered_objects_table = Fmake_hash_table (2, args);
+  }
+
+  DEFVAR_LISP ("dbus-debug", Vdbus_debug,
+    doc: /* If non-nil, debug messages of D-Bus bindings are raised.  */);
+#ifdef DBUS_DEBUG
+  Vdbus_debug = Qt;
+  /* We can also set environment variable DBUS_VERBOSE=1 in order to
+     see more traces.  This requires libdbus-1 to be configured with
+     --enable-verbose-mode.  */
+#else
+  Vdbus_debug = Qnil;
+#endif
+
+  /* Initialize internal objects.  */
+  xd_registered_buses = Qnil;
+  staticpro (&xd_registered_buses);
+
+  Fprovide (intern_c_string ("dbusbind"), Qnil);
+
+}
+
+#endif /* HAVE_DBUS */