Add droute.c, droute.h, dbus.c, dbus.h, bitarray.h
authorMike Gorse <mgorse@boston.site>
Mon, 21 Apr 2008 12:09:41 +0000 (08:09 -0400)
committerMike Gorse <mgorse@boston.site>
Mon, 21 Apr 2008 12:09:41 +0000 (08:09 -0400)
libspi/bitarray.h [new file with mode: 0644]
libspi/dbus.c [new file with mode: 0644]
libspi/dbus.h [new file with mode: 0644]
libspi/droute.c [new file with mode: 0644]
libspi/droute.h [new file with mode: 0644]

diff --git a/libspi/bitarray.h b/libspi/bitarray.h
new file mode 100644 (file)
index 0000000..e93dbef
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _BITARRAY_H
+#define _BITARRAY_H
+
+#include "dbus/dbus.h"
+#include "glib.h"
+
+#define BITARRAY_SEQ_TERM 0xffffffff
+
+#define BITARRAY_SET(p, n) ((p)[n/32] |= (1<<(n)))
+
+gint bitarray_to_seq(dbus_uint32_t *array, gint array_size, gint **out);
+dbus_uint32_t bitarray_from_seq(gint *seq, dbus_uint32_t **out);
+#endif /* _BITARRAY_H */
diff --git a/libspi/dbus.c b/libspi/dbus.c
new file mode 100644 (file)
index 0000000..090a721
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "accessible.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "dbus.h"
+
+static GHashTable *path2ptr;
+static guint objindex;
+
+static void
+deregister_object (gpointer obj)
+{
+  g_hash_table_remove (path2ptr, obj);
+}
+
+static guint
+register_object (AtkObject * obj)
+{
+  if (!path2ptr)
+    {
+      path2ptr = g_hash_table_new (g_int_hash, g_int_equal);
+      if (!path2ptr)
+       return ++objindex;
+    }
+  while (g_hash_table_lookup (path2ptr, (gpointer)++ objindex))
+    {
+      /* g_object_get_data returning 0 means no data, so handle wrap-around */
+      if (objindex == 0)
+       objindex++;
+    }
+  g_hash_table_insert (path2ptr, (gpointer) objindex, obj);
+  g_object_set_data_full (G_OBJECT (obj), "dbus-id", (gpointer) objindex,
+                         deregister_object);
+  return objindex;
+}
+
+AtkObject *
+spi_dbus_get_object (const char *path)
+{
+  guint index;
+  void *data;
+
+  g_assert (path);
+  index = atoi (path);
+  data = g_hash_table_lookup (path2ptr, (gpointer) index);
+  if (data)
+    return ATK_OBJECT (data);
+  return NULL;
+}
+
+char *
+spi_dbus_get_path (AtkObject * obj)
+{
+  guint index = (guint) g_object_get_data (G_OBJECT (obj), "dbus-id");
+  if (!index)
+    index = register_object (obj);
+  return g_strdup_printf ("/org/freedesktop/atspi/accessible/%d", index);
+}
+
+DBusMessage *
+spi_dbus_general_error (DBusMessage * message)
+{
+  return dbus_message_new_error (message,
+                                "org.freedesktop.accessibility.GeneralError",
+                                "General error");
+}
+
+/* Reply with the given object and dereference it if unref is TRUE */
+DBusMessage *
+spi_dbus_return_object (DBusMessage * message, AtkObject * obj, int unref)
+{
+  DBusMessage *reply;
+  const char *path = spi_dbus_get_path (obj);
+  if (unref)
+    g_object_unref (obj);
+  if (!path)
+    {
+      /* Should we have a more specific error for this? */
+      return spi_dbus_general_error (message);
+    }
+  reply = dbus_message_new_method_return (message);
+  if (reply)
+    {
+      dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, path,
+                               DBUS_TYPE_INVALID);
+    }
+  return reply;
+}
+
+DBusMessage *
+spi_dbus_return_rect (DBusMessage * message, gint ix, gint iy, gint iwidth,
+                     gint iheight)
+{
+  DBusMessage *reply;
+  dbus_uint32_t x, y, width, height;
+
+  x = ix;
+  y = iy;
+  width = iwidth;
+  height = iheight;
+  reply = dbus_message_new_method_return (message);
+  if (reply)
+    {
+      DBusMessageIter iter, sub;
+      dbus_message_iter_init_append (reply, &iter);
+      if (!dbus_message_iter_open_container
+         (&iter, DBUS_TYPE_STRUCT, NULL, &sub))
+       goto oom;
+      dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &x);
+      dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &y);
+      dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &width);
+      dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &height);
+      if (!dbus_message_iter_close_container (&iter, &sub))
+       goto oom;
+    }
+  return reply;
+oom:
+  /* todo: return an error */
+  return reply;
+}
+
+dbus_bool_t
+spi_dbus_return_v_object (DBusMessageIter * iter, AtkObject * obj, int unref)
+{
+  const char *path = spi_dbus_get_path (obj);
+  if (unref)
+    g_object_unref (obj);
+  if (!path)
+    return FALSE;
+  return droute_return_v_object (iter, path);
+}
+
+
+void
+spi_dbus_initialize (DRouteData * data)
+{
+  spi_initialize_accessible (data);
+  spi_initialize_action(data);
+  spi_initialize_component (data);
+  spi_initialize_document (data);
+  spi_initialize_editabletext (data);
+  spi_initialize_hyperlink (data);
+  spi_initialize_hypertext (data);
+  spi_initialize_image (data);
+  spi_initialize_selection (data);
+  spi_initialize_table (data);
+  spi_initialize_text (data);
+  spi_initialize_value (data);
+}
+
+static GString *
+spi_get_tree (AtkObject * obj, GString * str, DRouteData * data)
+{
+  int role;
+  const char *name;
+  gchar *path;
+  GSList *l;
+  gint childcount;
+  gint i;
+
+  if (!obj)
+    return NULL;
+  role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));;
+  name = atk_object_get_name (obj);
+  if (!name)
+    name = "";
+  path = spi_dbus_get_path (obj);
+  g_string_append_printf (str,
+                         "<object path=\"%s\" name=\"%s\" role=\"%d\">\n",
+                         path, name, role);
+  for (l = data->interfaces; l; l = g_slist_next (l))
+    {
+      DRouteInterface *iface_def = (DRouteInterface *) l->data;
+      void *datum = NULL;
+      if (iface_def->get_datum)
+       datum = (*iface_def->get_datum) (path, data->user_data);
+      if (datum)
+       {
+         g_string_append_printf (str, "<interface name=\"%s\"/>\n",
+                                 iface_def->name);
+         if (iface_def->free_datum)
+           (*iface_def->free_datum) (datum);
+       }
+    }
+  childcount = atk_object_get_n_accessible_children (obj);
+  for (i = 0; i < childcount; i++)
+    {
+      AtkObject *child = atk_object_ref_accessible_child (obj, i);
+      str = spi_get_tree (child, str, data);
+      g_object_unref (child);
+    }
+  str = g_string_append (str, "</object>\n");
+  return str;
+}
diff --git a/libspi/dbus.h b/libspi/dbus.h
new file mode 100644 (file)
index 0000000..135fcb2
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ATSPI_DBUS_H
+#define _ATSPI_DBUS_H
+
+#include <dbus/dbus.h>
+#include <atk/atk.h>
+#include <stdio.h>
+
+#include "droute.h"
+
+AtkObject *spi_dbus_get_object(const char *path);
+
+char *spi_dbus_get_path(AtkObject *obj);
+DBusMessage *spi_dbus_general_error(DBusMessage *message);
+DBusMessage *spi_dbus_return_rect(DBusMessage *message, gint ix, gint iy, gint iwidth, gint iheight);
+DBusMessage *spi_dbus_return_object(DBusMessage *message, AtkObject *obj, int unref);
+dbus_bool_t spi_dbus_return_v_object(DBusMessageIter *iter, AtkObject *obj, int unref);
+
+#define SPI_DBUS_RETURN_ERROR(m, e) dbus_message_new_error(m, (e)->name, (e)->message)
+
+void spi_dbus_initialize(DRouteData *data);
+
+#endif /* _ATSPI_DBUS_H */
diff --git a/libspi/droute.c b/libspi/droute.c
new file mode 100644 (file)
index 0000000..514bfa6
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "droute.h"
+#include <stdlib.h>
+#include <string.h>
+
+static DRouteInterface *
+find_iface (DRouteData * data, const char *name)
+{
+  GSList *l;
+
+  for (l = data->interfaces; l; l = g_slist_next (l))
+    {
+      DRouteInterface *iface = (DRouteInterface *) l->data;
+      if (iface && iface->name && !strcmp (iface->name, name))
+       return iface;
+    }
+  return NULL;
+}
+
+static DBusHandlerResult
+prop_get_all (DBusConnection * bus, DBusMessage * message, DRouteData * data)
+{
+  DRouteInterface *iface_def;
+  DRouteProperty *prop;
+  DBusError error;
+  const char *iface;
+  const char *path = dbus_message_get_path (message);
+  DBusMessage *reply;
+  DBusMessageIter iter, iter_dict, iter_dict_entry;
+
+  dbus_error_init (&error);
+  if (!dbus_message_get_args
+      (message, &error, DBUS_TYPE_STRING, &iface, DBUS_TYPE_INVALID))
+    {
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+  reply = dbus_message_new_method_return (message);
+  /* tbd: replace tbd with todo? */
+  if (!reply)
+    goto oom;
+  dbus_message_iter_init_append (reply, &iter);
+  if (!dbus_message_iter_open_container
+      (&iter, DBUS_TYPE_ARRAY, "{sv}", &iter_dict))
+    goto oom;
+  iface_def = find_iface (data, iface);
+  if (!iface_def)
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  if (iface_def->properties)
+    for (prop = iface_def->properties; prop->name; prop++)
+      {
+       if (!prop->get)
+         continue;
+       if (!dbus_message_iter_open_container
+           (&iter_dict, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict_entry))
+         goto oom;
+       dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING,
+                                       &prop->name);
+       (*prop->get) (path, &iter_dict_entry, data->user_data);
+       if (!dbus_message_iter_close_container (&iter_dict, &iter_dict_entry))
+         goto oom;
+      }
+  if (!dbus_message_iter_close_container (&iter, &iter_dict))
+    goto oom;
+  dbus_connection_send (bus, reply, NULL);
+  dbus_message_unref (reply);
+  return DBUS_HANDLER_RESULT_HANDLED;
+oom:
+  /* tbd: return a standard out-of-memory error */
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult
+prop (DBusConnection * bus, DBusMessage * message, DRouteData * data)
+{
+  const char *mode = dbus_message_get_member (message);
+  const char *iface, *member;
+  const char *path = dbus_message_get_path (message);
+  int set;
+  DBusMessage *reply;
+  DBusMessageIter iter;
+  DRouteInterface *iface_def;
+  DRouteProperty *prop = NULL;
+
+  if (!strcmp (mode, "Set"))
+    set = 1;
+  else if (!strcmp (mode, "Get"))
+    set = 0;
+  else
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  reply = dbus_message_new_method_return (message);
+  dbus_message_iter_init ((set ? reply : message), &iter);
+  dbus_message_iter_get_basic (&iter, &iface);
+  dbus_message_iter_next (&iter);
+  dbus_message_iter_get_basic (&iter, &member);
+  iface_def = find_iface (data, iface);
+  if (!iface_def)
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  if (iface_def->properties)
+    for (prop = iface_def->properties;
+        prop->name && strcmp (prop->name, member); prop++)
+      if (!prop || !prop->name)
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  if (set)
+    {
+      if (!prop->set)
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+      (*prop->set) (path, &iter, data->user_data);
+    }
+  else
+    {
+      if (!prop->get)
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+      (*prop->get) (path, &iter, data->user_data);
+    }
+  dbus_connection_send (bus, reply, NULL);
+  dbus_message_unref (message);
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+introspect (DBusConnection * bus, DBusMessage * message, DRouteData * data)
+{
+  const char *path = dbus_message_get_path (message);
+  GString *xml;
+  DRouteInterface *iface_def;
+  DRouteMethod *method;
+  DRouteProperty *property;
+  char *str;
+  DBusMessage *reply;
+  GSList *l;
+
+  if (strcmp (dbus_message_get_member (message), "Introspect"))
+    {
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+  xml = g_string_new (NULL);
+  /* below code stolen from dbus-glib */
+  g_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
+
+  /* We are introspectable, though I guess that was pretty obvious */
+  g_string_append_printf (xml, "  <interface name=\"%s\">\n",
+                         DBUS_INTERFACE_INTROSPECTABLE);
+  g_string_append (xml, "    <method name=\"Introspect\">\n");
+  g_string_append_printf (xml,
+                         "      <arg name=\"data\" direction=\"out\" type=\"%s\"/>\n",
+                         DBUS_TYPE_STRING_AS_STRING);
+  g_string_append (xml, "    </method>\n");
+  g_string_append (xml, "  </interface>\n");
+
+  /* We support get/set/getall properties */
+  g_string_append_printf (xml, "  <interface name=\"%s\">\n",
+                         DBUS_INTERFACE_PROPERTIES);
+  g_string_append (xml, "    <method name=\"Get\">\n");
+  g_string_append_printf (xml,
+                         "      <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n",
+                         DBUS_TYPE_STRING_AS_STRING);
+  g_string_append_printf (xml,
+                         "      <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n",
+                         DBUS_TYPE_STRING_AS_STRING);
+  g_string_append_printf (xml,
+                         "      <arg name=\"value\" direction=\"out\" type=\"%s\"/>\n",
+                         DBUS_TYPE_VARIANT_AS_STRING);
+  g_string_append (xml, "    </method>\n");
+  g_string_append (xml, "    <method name=\"Set\">\n");
+  g_string_append_printf (xml,
+                         "      <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n",
+                         DBUS_TYPE_STRING_AS_STRING);
+  g_string_append_printf (xml,
+                         "      <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n",
+                         DBUS_TYPE_STRING_AS_STRING);
+  g_string_append_printf (xml,
+                         "      <arg name=\"value\" direction=\"in\" type=\"%s\"/>\n",
+                         DBUS_TYPE_VARIANT_AS_STRING);
+  g_string_append (xml, "    </method>\n");
+  g_string_append (xml, "    <method name=\"GetAll\">\n");
+  g_string_append_printf (xml,
+                         "      <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n",
+                         DBUS_TYPE_STRING_AS_STRING);
+  g_string_append_printf (xml,
+                         "      <arg name=\"props\" direction=\"out\" type=\"%s\"/>\n",
+                         DBUS_TYPE_ARRAY_AS_STRING
+                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                         DBUS_TYPE_STRING_AS_STRING
+                         DBUS_TYPE_VARIANT_AS_STRING
+                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING);
+
+  g_string_append (xml, "    </method>\n");
+  g_string_append (xml, "  </interface>\n");
+  g_string_append_printf (xml, "<node name=\"%s\">\n", path);
+  /* end of stolen code */
+
+  for (l = data->interfaces; l; l = g_slist_next (l))
+    {
+      iface_def = (DRouteInterface *) l->data;
+      if (!(*iface_def->get_datum) (path, data->user_data))
+       continue;
+      g_string_append_printf (xml, "<interface name=\"%s\">\n",
+                             iface_def->name);
+      if (iface_def->methods)
+       for (method = iface_def->methods; method->name; method++)
+         {
+           const char *p = method->arg_desc;
+           g_string_append_printf (xml, "<%s name=\"%s\">\n",
+                                   (method->type ==
+                                    DROUTE_METHOD ? "method" : "signal"),
+                                   method->name);
+           g_string_append (xml, "<arg type=\"");
+           g_string_append_len (xml, p, strcspn (p, ",:"));
+           p += strcspn (p, ",");
+           if (*p == ',')
+             p++;
+           g_string_append (xml, "\" name=\"");
+           g_string_append_len (xml, p, strcspn (p, ",:"));
+           p += strcspn (p, ",");
+           if (*p == ',')
+             p++;
+           g_string_append_printf (xml, "\" direction=\"%s\"/>\n",
+                                   (*p == 'o' ? "out" : "in"));
+           p += strcspn (p, ":");
+           if (*p == ':')
+             p++;
+         }
+      if (iface_def->properties)
+       for (property = iface_def->properties; property->name; property++)
+         {
+           if (!property->get && !property->set)
+             continue;
+           g_string_append_printf (xml,
+                                   "<property name=\"%s\" type=\"%s\" access=\"%s%s\"/>\n",
+                                   property->name, property->type,
+                                   (property->get ? "read" : ""),
+                                   (property->set ? "write" : ""));
+         }
+    }
+  (*data->introspect_children) (path, xml, data->user_data);
+  str = g_string_free (xml, FALSE);
+  reply = dbus_message_new_method_return (message);
+  if (reply)
+    {
+      dbus_message_append_args (reply, DBUS_TYPE_STRING, &str,
+                               DBUS_TYPE_INVALID);
+    }
+  g_free (str);
+  dbus_connection_send (bus, reply, NULL);
+  dbus_message_unref (reply);
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult
+droute_message (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+  DRouteData *data = (DRouteData *) user_data;
+  DRouteInterface *iface_def;
+  DRouteMethod *method;
+  const char *iface = dbus_message_get_interface (message);
+  const char *member = dbus_message_get_member (message);
+  int type;
+  DBusError error;
+  DBusMessage *reply;
+
+  dbus_error_init (&error);
+  if (!member)
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  if (iface && !strcmp (iface, "org.freedesktop.dbus.Properties"))
+    {
+      if (!strcmp (member, "GetAll"))
+       return prop_get_all (bus, message, data);
+      return prop (bus, message, data);
+    }
+  else if (iface && !strcmp (iface, "org.freedesktop.dbus.Introspectable"))
+    {
+      return introspect (bus, message, data);
+    }
+  else
+    {
+      int message_type = dbus_message_get_type (message);
+      switch (message_type)
+       {
+       case DBUS_MESSAGE_TYPE_METHOD_CALL:
+         type = DROUTE_METHOD;
+         break;
+       case DBUS_MESSAGE_TYPE_SIGNAL:
+         type = DROUTE_SIGNAL;
+         break;
+       default:
+         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+       }
+    }
+  if (iface)
+    {
+      iface_def = find_iface (data, iface);
+      if (!iface_def)
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+      if (iface_def->methods)
+       for (method = iface_def->methods; method->func; method++)
+         {
+           if (method->type == type && !strcmp (method->name, member))
+             {
+               reply =
+                 (*method->func) (bus, message,
+                                  (method->wants_droute_data ? data : data->
+                                   user_data));
+               if (reply)
+                 {
+                   dbus_connection_send (bus, reply, NULL);
+                   dbus_message_unref (reply);
+                 }
+               return DBUS_HANDLER_RESULT_HANDLED;
+             }
+         }
+    }
+  else
+    {
+      GSList *l;
+      if (type == DBUS_MESSAGE_TYPE_SIGNAL)
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+      for (l = data->interfaces; l; l = g_slist_next (l))
+       {
+         iface_def = (DRouteInterface *) l->data;
+         if (iface_def->methods)
+           for (method = iface_def->methods; method->func; method++)
+             {
+               if (method->type == type && !strcmp (method->name, member))
+                 {
+                   reply = (*method->func) (bus, message, data->user_data);
+                   if (reply)
+                     {
+                       dbus_connection_send (bus, reply, NULL);
+                       dbus_message_unref (reply);
+                     }
+                   return DBUS_HANDLER_RESULT_HANDLED;
+                 }
+             }
+       }
+    }
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+dbus_bool_t
+droute_return_v_int32 (DBusMessageIter * iter, dbus_int32_t val)
+{
+  DBusMessageIter sub;
+
+  if (!dbus_message_iter_open_container
+      (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_INT32_AS_STRING, &sub))
+    {
+      return FALSE;
+    }
+  dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &val);
+  dbus_message_iter_close_container (iter, &sub);
+  return TRUE;
+}
+
+dbus_bool_t
+droute_return_v_double (DBusMessageIter * iter, double val)
+{
+  DBusMessageIter sub;
+
+  if (!dbus_message_iter_open_container
+      (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_DOUBLE_AS_STRING, &sub))
+    {
+      return FALSE;
+    }
+  dbus_message_iter_append_basic (&sub, DBUS_TYPE_DOUBLE, &val);
+  dbus_message_iter_close_container (iter, &sub);
+  return TRUE;
+}
+
+/* Return a string in a variant
+ * will return an empty string if passed a NULL value */
+dbus_bool_t
+droute_return_v_string (DBusMessageIter * iter, const char *val)
+{
+  DBusMessageIter sub;
+
+  if (!val)
+    val = "";
+  if (!dbus_message_iter_open_container
+      (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &sub))
+    {
+      return FALSE;
+    }
+  dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING, &val);
+  dbus_message_iter_close_container (iter, &sub);
+  return TRUE;
+}
+
+dbus_int32_t
+droute_get_v_int32 (DBusMessageIter * iter)
+{
+  DBusMessageIter sub;
+  dbus_int32_t rv;
+
+  // TODO- ensure we have the correct type
+  dbus_message_iter_recurse (iter, &sub);
+  dbus_message_iter_get_basic (&sub, &rv);
+  return rv;
+}
+
+const char *
+droute_get_v_string (DBusMessageIter * iter)
+{
+  DBusMessageIter sub;
+  char *rv;
+
+  // TODO- ensure we have the correct type
+  dbus_message_iter_recurse (iter, &sub);
+  dbus_message_iter_get_basic (&sub, &rv);
+  return rv;
+}
+
+dbus_bool_t
+droute_return_v_object (DBusMessageIter * iter, const char *path)
+{
+  DBusMessageIter sub;
+
+  if (!dbus_message_iter_open_container
+      (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_OBJECT_PATH_AS_STRING, &sub))
+    {
+      return FALSE;
+    }
+  dbus_message_iter_append_basic (&sub, DBUS_TYPE_OBJECT_PATH, &path);
+  dbus_message_iter_close_container (iter, &sub);
+  return TRUE;
+}
+
+dbus_bool_t
+droute_add_interface (DRouteData * data, const char *name,
+                     DRouteMethod * methods, DRouteProperty * properties,
+                     DRouteGetDatumFunction get_datum,
+                     DRouteFreeDatumFunction free_datum)
+{
+  DRouteInterface *iface =
+    (DRouteInterface *) malloc (sizeof (DRouteInterface));
+  GSList *new_list;
+
+  if (!iface)
+    return FALSE;
+  iface->name = strdup (name);
+  if (!iface->name)
+    {
+      free (iface);
+      return FALSE;
+    }
+  iface->methods = methods;
+  iface->properties = properties;
+  iface->get_datum = get_datum;
+  iface->free_datum = free_datum;
+  new_list = g_slist_append (data->interfaces, iface);
+  if (!new_list)
+    {
+      free (iface->name);
+      free (iface);
+      return FALSE;
+    }
+  data->interfaces = new_list;
+  return TRUE;
+}
diff --git a/libspi/droute.h b/libspi/droute.h
new file mode 100644 (file)
index 0000000..0cdfe96
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef _DROUTE_H
+#define _DROUTE_H
+
+#include <dbus/dbus.h>
+#include "glib.h"      /* needed for GString */
+
+#define DROUTE_METHOD   0
+#define DROUTE_SIGNAL   1
+
+typedef DBusMessage *(*DRouteFunction)(DBusConnection *, DBusMessage *, void *);
+typedef dbus_bool_t (*DRoutePropertyFunction)(const char *, DBusMessageIter *, void *);
+typedef char *(*DRoutePropertyStrFunction)(void *);
+
+typedef struct _DRouteMethod DRouteMethod;
+struct _DRouteMethod
+{
+  /* DROUTE_(METHOD|SIGNAL) */
+  int type;
+  DRouteFunction func;
+  const char *name;
+  /* arg_desc contains argument information used for introspection.
+   * It is a colon-delimited string of type,name,dir values */
+  const char *arg_desc;
+  dbus_bool_t wants_droute_data;
+};
+
+typedef struct _DRouteProperty DRouteProperty;
+struct _DRouteProperty
+{
+  DRoutePropertyFunction get;
+  DRoutePropertyStrFunction get_str;
+  DRoutePropertyFunction set;
+  DRoutePropertyStrFunction set_str;
+  const char *name;
+  const char *type;
+};
+
+  typedef void *(*DRouteGetDatumFunction)(const char *, void *);
+  typedef void (*DRouteFreeDatumFunction)(void *);
+
+typedef struct _DRouteInterface DRouteInterface;
+struct _DRouteInterface
+{
+  DRouteMethod *methods;
+  DRouteProperty *properties;
+  DRouteGetDatumFunction get_datum;
+  DRouteFreeDatumFunction free_datum;
+  char *name;
+};
+
+typedef struct _DRouteData DRouteData;
+struct _DRouteData
+{
+  GSList *interfaces;
+  char (*introspect_children)(const char *, GString *, void *);
+  void *user_data;
+};
+
+DBusHandlerResult droute_message(DBusConnection *bus, DBusMessage *message, void *user_data);
+
+dbus_bool_t droute_return_v_int32(DBusMessageIter *iter, dbus_int32_t val);
+dbus_bool_t droute_return_v_double(DBusMessageIter *iter, double val);
+dbus_bool_t droute_return_v_string(DBusMessageIter *iter, const char *val);
+dbus_int32_t droute_get_v_int32(DBusMessageIter *iter);
+const char *droute_get_v_string(DBusMessageIter *iter);
+dbus_bool_t droute_return_v_object(DBusMessageIter *iter, const char *path);
+
+dbus_bool_t droute_add_interface(DRouteData *data, const char *name, DRouteMethod *methods, DRouteProperty *properties, DRouteGetDatumFunction get_datum, DRouteFreeDatumFunction free_datum);
+#endif /* _DROUTE_H */