[at-spi2-core/gi] Some work on event support; many bug fixes



commit 1299779d8ded027a7e277d5e64b76f88c4ba4da7
Author: Mike Gorse <mgorse novell com>
Date:   Fri Nov 5 18:10:56 2010 -0400

    Some work on event support; many bug fixes

 atspi/Makefile.am                                  |   12 +-
 atspi/atspi-accessible.c                           |   28 +-
 atspi/atspi-accessible.h                           |    1 +
 atspi/atspi-component.c                            |   49 ++-
 atspi/atspi-device-listener-private.h              |   35 ++
 .../{atspi-listener.c => atspi-device-listener.c}  |  150 ++----
 atspi/atspi-device-listener.h                      |   74 +++
 atspi/atspi-event-listener-private.h               |   35 ++
 atspi/atspi-event-listener.c                       |  620 ++++++++++++++++++++
 atspi/atspi-event-listener.h                       |   52 ++
 atspi/atspi-event-types.h                          |   16 +-
 atspi/atspi-listener.h                             |  137 -----
 atspi/atspi-misc-private.h                         |   11 +
 atspi/atspi-misc.c                                 |  154 +++++-
 atspi/atspi-private.h                              |    3 +-
 atspi/atspi-registry.c                             |   80 ++--
 atspi/atspi-registry.h                             |   16 +-
 atspi/atspi-stateset.c                             |  111 ++++-
 atspi/atspi-stateset.h                             |    4 +-
 atspi/atspi-types.h                                |    2 +-
 atspi/atspi.h                                      |    3 +-
 21 files changed, 1262 insertions(+), 331 deletions(-)
---
diff --git a/atspi/Makefile.am b/atspi/Makefile.am
index 6a2cc18..4d0989a 100644
--- a/atspi/Makefile.am
+++ b/atspi/Makefile.am
@@ -7,7 +7,8 @@ libatspi_la_CFLAGS = $(DBUS_GLIB_CFLAGS) \
                     -I$(top_srcdir)
 
 libatspi_la_LIBADD = $(DBUS_GLIB_LIBS) \
-		    $(top_builddir)/dbind/libdbind.la
+	$(X_LIBS) \
+	$(top_builddir)/dbind/libdbind.la
 
 libatspidir = $(includedir)/at-spi-1.0/atspi
 
@@ -21,9 +22,12 @@ libatspi_la_SOURCES =		\
 	atspi-component.h \
 	atspi-constants.h \
 	atspi-event-types.h \
-	atspi-listener.c \
-	atspi-listener.h \
-	atspi-listener-private.h \
+	atspi-device-listener.c \
+	atspi-device-listener.h \
+	atspi-device-listener-private.h \
+	atspi-event-listener.c \
+	atspi-event-listener.h \
+	atspi-event-listener-private.h \
 	atspi-misc.c \
 	atspi-misc.h \
 	atspi-misc-private.h \
diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c
index afdcf28..a5c9f32 100644
--- a/atspi/atspi-accessible.c
+++ b/atspi/atspi-accessible.c
@@ -177,6 +177,12 @@ gchar *
 atspi_accessible_get_name (AtspiAccessible *obj, GError **error)
 {
   g_return_val_if_fail (obj != NULL, NULL);
+  if (!obj->cached_properties & ATSPI_CACHE_NAME)
+  {
+    if (!_atspi_dbus_call (obj, atspi_interface_accessible, "GetName", NULL, "=>s", &obj->name))
+      return NULL;
+    obj->cached_properties |= ATSPI_CACHE_NAME;
+  }
   return g_strdup (obj->name);
 }
 
@@ -194,6 +200,12 @@ atspi_accessible_get_description (AtspiAccessible *obj, GError **error)
 {
   g_return_val_if_fail (obj != NULL, NULL);
 
+  if (!obj->cached_properties & ATSPI_CACHE_DESCRIPTION)
+  {
+    if (!_atspi_dbus_call (obj, atspi_interface_accessible, "GetDescription", NULL, "=>s", &obj->description))
+      return NULL;
+    obj->cached_properties |= ATSPI_CACHE_DESCRIPTION;
+  }
   return g_strdup (obj->description);
 }
 
@@ -255,6 +267,8 @@ atspi_accessible_get_child_at_index (AtspiAccessible *obj,
 
   /* TODO: ManagesDescendants */
   child = g_list_nth_data (obj->children, child_index);
+  if (!child)
+    return NULL;
   return g_object_ref (child);
 }
 
@@ -332,6 +346,15 @@ atspi_accessible_get_role (AtspiAccessible *obj, GError **error)
 {
   g_return_val_if_fail (obj != NULL, ATSPI_ROLE_INVALID);
 
+  if (!obj->cached_properties & ATSPI_CACHE_ROLE)
+  {
+    dbus_uint32_t role;
+    if (_atspi_dbus_call (obj, atspi_interface_accessible, "GetRole", NULL, "=>u", &role))
+    {
+      obj->cached_properties |= ATSPI_CACHE_ROLE;
+      obj->role = role;
+    }
+  }
   return obj->role;
 }
 
@@ -1232,10 +1255,7 @@ cspi_object_destroyed (AtspiAccessible *accessible)
   e.type = "object:state-change:defunct";
   e.source = accessible;
   e.detail1 = 1;
-#if 0
-  g_warning ("atspi: TODO: Finish events");
-  atspi_dispatch_event (&e);
-#endif
+  _atspi_send_event (&e);
 
     g_free (accessible->path);
 
diff --git a/atspi/atspi-accessible.h b/atspi/atspi-accessible.h
index 7ffa467..9722aee 100644
--- a/atspi/atspi-accessible.h
+++ b/atspi/atspi-accessible.h
@@ -53,6 +53,7 @@ struct _AtspiAccessible
   char *name;
   char *description;
   AtspiStateSet *states;
+  guint cached_properties;
 };
 
 typedef struct _AtspiAccessibleClass AtspiAccessibleClass;
diff --git a/atspi/atspi-component.c b/atspi/atspi-component.c
index d105f20..574bb4a 100644
--- a/atspi/atspi-component.c
+++ b/atspi/atspi-component.c
@@ -60,7 +60,7 @@ atspi_component_contains (AtspiComponent *obj,
 }
 
 /**
- * atspi_component_get_accessible_at_point:
+ * atspi_component_ref_accessible_at_point:
  * @obj: a pointer to the #AtspiComponent to query.
  * @x: a #gint specifying the x coordinate of the point in question.
  * @y: a #gint specifying the y coordinate of the point in question.
@@ -74,7 +74,7 @@ atspi_component_contains (AtspiComponent *obj,
  *         the point.
  **/
 AtspiAccessible *
-atspi_component_get_accessible_at_point (AtspiComponent *obj,
+atspi_component_ref_accessible_at_point (AtspiComponent *obj,
                                           gint x,
                                           gint y,
                                           AtspiCoordType ctype, GError **error)
@@ -105,7 +105,7 @@ atspi_component_get_accessible_at_point (AtspiComponent *obj,
  * Get the bounding box of the specified #AtspiComponent.
  *
  **/
-AtspiBoundingBox
+AtspiRect
 atspi_component_get_extents (AtspiComponent *obj,
                                 gint *x,
                                 gint *y,
@@ -114,7 +114,7 @@ atspi_component_get_extents (AtspiComponent *obj,
                                 AtspiCoordType ctype, GError **error)
 {
   dbus_int16_t d_ctype = ctype;
-  AtspiBoundingBox bbox;
+  AtspiRect bbox;
 
   g_return_if_fail (obj != NULL);
 
@@ -252,3 +252,44 @@ atspi_component_get_alpha    (AtspiComponent *obj, GError **error)
 
   return retval;
 }
+
+static void
+atspi_component_base_init (AtspiComponentIface *klass)
+{
+  static gboolean initialized = FALSE;
+
+  if (! initialized)
+    {
+      klass->contains = atspi_component_contains;
+      klass->ref_accessible_at_point = atspi_component_ref_accessible_at_point;
+  klass->get_extents = atspi_component_get_extents;
+      klass->get_position = atspi_component_get_position;
+      klass->get_size = atspi_component_get_size;
+      klass->get_layer = atspi_component_get_layer;
+      klass->get_mdi_z_order = atspi_component_get_mdi_z_order;
+      klass->grab_focus = atspi_component_grab_focus;
+      klass->get_alpha = atspi_component_get_alpha;
+
+      initialized = TRUE;
+    }
+}
+
+GType
+atspi_component_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type) {
+    static const GTypeInfo tinfo =
+    {
+      sizeof (AtspiComponentIface),
+      (GBaseInitFunc) atspi_component_base_init,
+      (GBaseFinalizeFunc) NULL,
+
+    };
+
+    type = g_type_register_static (G_TYPE_INTERFACE, "AtspiComponent", &tinfo, 0);
+
+  }
+  return type;
+}
diff --git a/atspi/atspi-device-listener-private.h b/atspi/atspi-device-listener-private.h
new file mode 100644
index 0000000..471ca7a
--- /dev/null
+++ b/atspi/atspi-device-listener-private.h
@@ -0,0 +1,35 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2002 Ximian, Inc.
+ *           2002 Sun Microsystems 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_DEVICE_LISTENER_PRIVATE_H_
+#define _ATSPI_DEVICE_LISTENER_PRIVATE_H_
+
+#include "atspi-device-listener.h"
+
+#include "dbus/dbus.h"
+
+DBusHandlerResult _atspi_dbus_handle_DeviceEvent (DBusConnection *bus, DBusMessage *message, void *data);
+
+gchar *_atspi_device_listener_get_path (AtspiDeviceListener *listener);
+#endif	/* _ATSPI_DEVICE_LISTENER_H_ */
diff --git a/atspi/atspi-listener.c b/atspi/atspi-device-listener.c
similarity index 70%
rename from atspi/atspi-listener.c
rename to atspi/atspi-device-listener.c
index 15492e7..31bb270 100644
--- a/atspi/atspi-listener.c
+++ b/atspi/atspi-device-listener.c
@@ -25,16 +25,10 @@
 
 typedef struct
 {
-  union
-    {
-      AtspiEventListenerCB     event;
-      AtspiDeviceListenerCB    device_event;
-      gpointer                      method;
-    } cb;
+  AtspiDeviceListenerCB    callback;
   gpointer user_data;
-} EventHandler;
+} DeviceEventHandler;
 
-GObjectClass *event_parent_class;
 GObjectClass *device_parent_class;
 
 static guint32 _e_id = 0;
@@ -43,28 +37,28 @@ static guint32 _e_id = 0;
  * Misc. helpers.
  */
 
-static EventHandler *
-atspi_event_handler_new (gpointer method, gpointer user_data)
+static DeviceEventHandler *
+device_event_handler_new (AtspiDeviceListenerCB callback, gpointer user_data)
 {
-  EventHandler *eh = g_new0 (EventHandler, 1);
+  DeviceEventHandler *eh = g_new0 (DeviceEventHandler, 1);
 
-  eh->cb.method = method;
+  eh->callback = callback;
   eh->user_data = user_data;
 
   return eh;
 }
 
 static GList *
-event_list_remove_by_cb (GList *list, gpointer callback)
+event_list_remove_by_cb (GList *list, AtspiDeviceListenerCB callback)
 {
   GList *l, *next;
 	
   for (l = list; l; l = next)
     {
-      EventHandler *eh = l->data;
+      DeviceEventHandler *eh = l->data;
       next = l->next;
 
-      if (eh->cb.method == callback)
+      if (eh->callback == callback)
       {
         list = g_list_delete_link (list, l);
 	g_free (eh);
@@ -78,24 +72,6 @@ event_list_remove_by_cb (GList *list, gpointer callback)
  * Standard event dispatcher
  */
 
-G_DEFINE_TYPE (AtspiEventListener, atspi_event_listener,
-			  G_TYPE_OBJECT)
-
-static void
-atspi_event_dispatch (AtspiEventListener    *listener,
-	    const AtspiEvent *event)
-{
-  GList *l;
-  
-  /* FIXME: re-entrancy hazard on this list */
-  for (l = listener->callbacks; l; l = l->next)
-    {
-      EventHandler *eh = l->data;
-      /* cast hides our private stuff from client handlers */
-      eh->cb.event (event, eh->user_data);
-    }
-}
-
 static guint listener_id = 0;
 static GList *device_listeners = NULL;
 
@@ -118,68 +94,6 @@ remove_listener (GObject *obj, gpointer data)
   device_listeners = g_list_remove (device_listeners, obj);
 }
 
-static void
-atspi_event_listener_init (AtspiEventListener *listener)
-{
-}
-
-static void
-atspi_event_listener_finalize (GObject *object)
-{
-  AtspiEventListener *listener = (AtspiEventListener *) object;
-  GList *l;
-  
-  for (l = listener->callbacks; l; l = l->next)
-    {
-      g_free (l->data);
-    }
-  
-  g_list_free (listener->callbacks);
-
-  event_parent_class->finalize (object);
-}
-
-static void
-atspi_event_listener_class_init (AtspiEventListenerClass *klass)
-{
-  GObjectClass *object_class = (GObjectClass *) klass;
-
-  event_parent_class = g_type_class_peek_parent (klass);
-  object_class->finalize = atspi_event_listener_finalize;
-
-  klass->event = atspi_event_dispatch;
-}
-
-AtspiEventListener *
-atspi_event_listener_new (void)
-{
-  AtspiEventListener *listener;
-
-  listener = g_object_new (atspi_event_listener_get_type (), NULL);
-
-  return listener;
-}
-
-void
-atspi_event_listener_add_cb (AtspiEventListener  *listener,
-			    AtspiEventListenerCB callback,
-			    void                     *user_data)
-{
-  g_return_if_fail (ATSPI_IS_EVENT_LISTENER (listener));
-
-  listener->callbacks = g_list_prepend (listener->callbacks,
-					atspi_event_handler_new ((void *) callback, user_data));
-}
-
-void
-atspi_event_listener_remove_cb (AtspiEventListener  *listener,
-			       AtspiEventListenerCB callback)
-{
-  g_return_if_fail (ATSPI_IS_EVENT_LISTENER (listener));
-
-  listener->callbacks = event_list_remove_by_cb (listener->callbacks, (void *) callback);
-}
-
 /* 
  * Device event handler
  */
@@ -194,9 +108,9 @@ atspi_device_event_dispatch (AtspiDeviceListener               *listener,
   /* FIXME: re-enterancy hazard on this list */
   for (l = listener->callbacks; l; l = l->next)
     {
-      EventHandler *eh = l->data;
+      DeviceEventHandler *eh = l->data;
 
-      if ((handled = eh->cb.device_event (&anevent, eh->user_data)))
+      if ((handled = eh->callback (&anevent, eh->user_data)))
         {
 	  break;
 	}
@@ -248,27 +162,61 @@ atspi_device_listener_class_init (AtspiDeviceListenerClass *klass)
 G_DEFINE_TYPE (AtspiDeviceListener, atspi_device_listener,
 			  G_TYPE_OBJECT)
 
+/**
+ * atspi_device_listener_new:
+ * @callback: (scope call): an #AtspiDeviceListenerCB callback function,
+ *            or NULL.
+ * @user_data: (closure): a pointer to data which will be passed to the
+ * callback when invoked.
+ *
+ * Create a new #AtspiDeviceListener with a specified callback function.
+ *
+ * Returns: a pointer to a newly-created #AtspiDeviceListener.
+ *
+ **/
 AtspiDeviceListener *
-atspi_device_listener_new (void)
+atspi_device_listener_new (AtspiDeviceListenerCB callback)
 {
   AtspiDeviceListener *listener = g_object_new (atspi_device_listener_get_type (), NULL);
 
   return listener;
 }
 
+/**
+ * atspi_device_listener_add_callback:
+ * @listener: the #AtspiDeviceListener instance to modify.
+ * @callback: (scope call): an #AtspiDeviceListenerCB function pointer.
+ * @user_data: (closure): a pointer to data which will be passed to the
+ *             callback when invoked.
+ *
+ * Add an in-process callback function to an existing #AtspiDeviceListener.
+ *
+ * Returns: #TRUE if successful, otherwise #FALSE.
+ *
+ **/
 void
-atspi_device_listener_add_cb (AtspiDeviceListener  *listener,
+atspi_device_listener_add_callback (AtspiDeviceListener  *listener,
 			     AtspiDeviceListenerCB callback,
 			     void                      *user_data)
 {
   g_return_if_fail (ATSPI_IS_DEVICE_LISTENER (listener));
 
   listener->callbacks = g_list_prepend (listener->callbacks,
-					atspi_event_handler_new ((void *)callback, user_data));
+					device_event_handler_new ((void *)callback, user_data));
 }
 
+/**
+ * atspi_device_listener_remove_callback:
+ * @listener: the #AtspiDeviceListener instance to modify.
+ * @callback: (scope call): an #AtspiDeviceListenerCB function pointer.
+ *
+ * Remove an in-process callback function from an existing #AtspiDeviceListener.
+ *
+ * Returns: #TRUE if successful, otherwise #FALSE.
+ *
+ **/
 void
-atspi_device_listener_remove_cb (AtspiDeviceListener  *listener,
+atspi_device_listener_remove_callback (AtspiDeviceListener  *listener,
 				AtspiDeviceListenerCB callback)
 {
   g_return_if_fail (ATSPI_IS_DEVICE_LISTENER (listener));
diff --git a/atspi/atspi-device-listener.h b/atspi/atspi-device-listener.h
new file mode 100644
index 0000000..113ca00
--- /dev/null
+++ b/atspi/atspi-device-listener.h
@@ -0,0 +1,74 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2002 Ximian, Inc.
+ *           2002 Sun Microsystems 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_DEVICE_LISTENER_H_
+#define _ATSPI_DEVICE_LISTENER_H_
+
+#include "glib-object.h"
+
+#include "atspi-event-types.h"
+
+/**
+ * AtspiDeviceListenerCB:
+ * @stroke: The #AtspiDeviceEvent for which notification is being received.
+ * @user_data: Data which is passed to the client each time this callback is notified.
+ *
+ * A callback function prototype via which clients receive device event notifications.
+ *
+ * Returns: %TRUE if the client wishes to consume/preempt the event, preventing it from being
+ * relayed to the currently focussed application, %FALSE if the event delivery should proceed as normal.
+ **/
+typedef gboolean (*AtspiDeviceListenerCB)    (const AtspiDeviceEvent *stroke,
+						     void                      *user_data);
+
+#define ATSPI_TYPE_DEVICE_LISTENER                        (atspi_device_listener_get_type ())
+#define ATSPI_DEVICE_LISTENER(obj)                        (G_TYPE_CHECK_INSTANCE_CAST ((obj), ATSPI_TYPE_DEVICE_LISTENER, AtspiDeviceListener))
+#define ATSPI_DEVICE_LISTENER_CLASS(klass)                (G_TYPE_CHECK_CLASS_CAST ((klass), ATSPI_TYPE_DEVICE_LISTENER, AtspiDeviceListenerClass))
+#define ATSPI_IS_DEVICE_LISTENER(obj)                     (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ATSPI_TYPE_DEVICE_LISTENER))
+#define ATSPI_IS_DEVICE_LISTENER_CLASS(klass)             (G_TYPE_CHECK_CLASS_TYPE ((klass), ATSPI_TYPE_DEVICE_LISTENER))
+#define ATSPI_DEVICE_LISTENER_GET_CLASS(obj)              (G_TYPE_INSTANCE_GET_CLASS ((obj), ATSPI_TYPE_DEVICE_LISTENER, AtspiDeviceListenerClass))
+
+typedef struct _AtspiDeviceListener AtspiDeviceListener;
+struct _AtspiDeviceListener
+{
+  GObject parent;
+  guint id;
+  GList *callbacks;
+};
+
+typedef struct _AtspiDeviceListenerClass AtspiDeviceListenerClass;
+struct _AtspiDeviceListenerClass
+{
+  GObjectClass parent_class;
+  gboolean (*device_event) (AtspiDeviceListener *, const AtspiDeviceEvent *);
+};
+
+GType atspi_device_listener_get_type (void);
+
+AtspiDeviceListener *atspi_device_listener_new (AtspiDeviceListenerCB callback);
+
+void atspi_device_listener_add_callback (AtspiDeviceListener  *listener, AtspiDeviceListenerCB callback, void                      *user_data);
+
+void atspi_device_listener_remove_callback (AtspiDeviceListener  *listener, AtspiDeviceListenerCB callback);
+#endif	/* _ATSPI_DEVICE_LISTENER_H_ */
diff --git a/atspi/atspi-event-listener-private.h b/atspi/atspi-event-listener-private.h
new file mode 100644
index 0000000..98fa867
--- /dev/null
+++ b/atspi/atspi-event-listener-private.h
@@ -0,0 +1,35 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2002 Ximian, Inc.
+ *           2002 Sun Microsystems 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_EVENT_LISTENER_PRIVATE_H_
+#define _ATSPI_EVENT_LISTENER_PRIVATE_H_
+
+#include "atspi-event-listener.h"
+
+#include "dbus/dbus.h"
+
+DBusHandlerResult _atspi_dbus_handle_Event (DBusConnection *bus, DBusMessage *message, void *data);
+
+void _atspi_send_event (AtspiEvent *e);
+#endif	/* _ATSPI_EVENT_LISTENER_H_ */
diff --git a/atspi/atspi-event-listener.c b/atspi/atspi-event-listener.c
new file mode 100644
index 0000000..5c834a7
--- /dev/null
+++ b/atspi/atspi-event-listener.c
@@ -0,0 +1,620 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2002 Ximian Inc.
+ * Copyright 2002 Sun Microsystems, 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 "atspi-private.h"
+#include <string.h>
+
+typedef struct
+{
+  AtspiEventListenerCB callback;
+  void *user_data;
+  char *category;
+  char *name;
+  char *detail;
+} EventListenerEntry;
+
+/*
+ * Misc. helpers.
+ */
+
+/*
+ * Standard event dispatcher
+ */
+
+static guint listener_id = 0;
+static GList *event_listeners = NULL;
+
+static gchar *
+convert_name_from_dbus (const char *name)
+{
+  gchar *ret = g_malloc (g_utf8_strlen (name, -1) * 2 + 1);
+  const char *p = name;
+  gchar *q = ret;
+
+  if (!ret)
+    return NULL;
+
+  while (*p)
+  {
+    if (isupper (*p))
+    {
+      if (q > ret)
+        *q++ = '-';
+      *q++ = tolower (*p++);
+    }
+    else
+      *q++ = *p++;
+  }
+  *q = '\0';
+  return ret;
+}
+
+static void
+cache_process_children_changed (AtspiEvent *event)
+{
+  if (event->v_type != EVENT_DATA_OBJECT ||
+      !event->source->children ||
+      atspi_state_set_contains (event->source->states, ATSPI_STATE_MANAGES_DESCENDANTS))
+    return;
+
+  if (!strncmp (event->type, "object:children-changed:add", 27))
+  {
+    GList *new_list = g_list_insert (event->source->children, g_object_ref (event->v.accessible), event->detail1);
+    if (new_list)
+      event->source->children = new_list;
+  }
+  else if (g_list_find (event->source->children, event->v.accessible))
+  {
+    event->source->children = g_list_remove (event->source->children, event->v.accessible);
+  }
+}
+
+static void
+cache_process_property_change (AtspiEvent *event)
+{
+  if (!strcmp (event->type, "object:property-change:accessible-parent"))
+  {
+    if (event->source->accessible_parent)
+      g_object_unref (event->source->accessible_parent);
+    if (event->v_type == EVENT_DATA_OBJECT)
+    {
+      event->source->accessible_parent = g_object_ref (event->v.accessible);
+      event->source->cached_properties |= ATSPI_CACHE_PARENT;
+    }
+    else
+    {
+      event->source->accessible_parent = NULL;
+      event->source->cached_properties &= ~ATSPI_CACHE_PARENT;
+    }
+  }
+  else if (!strcmp (event->type, "object:property-change:accessible-name"))
+  {
+    if (event->source->name)
+      g_free (event->source->name);
+    if (event->v_type == EVENT_DATA_STRING)
+    {
+      event->source->name = g_strdup (event->v.text);
+      event->source->cached_properties |= ATSPI_CACHE_NAME;
+    }
+    else
+    {
+      event->source->name = NULL;
+      event->source->cached_properties &= ~ATSPI_CACHE_NAME;
+    }
+  }
+  else if (!strcmp (event->type, "object:property-change:accessible-description"))
+  {
+    if (event->source->description)
+      g_free (event->source->description);
+    if (event->v_type == EVENT_DATA_STRING)
+    {
+      event->source->description = g_strdup (event->v.text);
+      event->source->cached_properties |= ATSPI_CACHE_DESCRIPTION;
+    }
+    else
+    {
+      event->source->description = NULL;
+      event->source->cached_properties &= ~ATSPI_CACHE_DESCRIPTION;
+    }
+  }
+}
+
+static void
+cache_process_state_changed (AtspiEvent *event)
+{
+  atspi_state_set_set_by_name (event->source->states, event->type + 21, event->detail1);
+}
+
+static dbus_bool_t
+demarshal_rect (DBusMessageIter *iter, AtspiRect *rect)
+{
+  dbus_int32_t x, y, width, height;
+  DBusMessageIter iter_struct;
+
+  dbus_message_iter_recurse (iter, &iter_struct);
+  if (dbus_message_iter_get_arg_type (&iter_struct) != DBUS_TYPE_INT32) return FALSE;
+  dbus_message_iter_get_basic (&iter_struct, &x);
+  dbus_message_iter_next (&iter_struct);
+  if (dbus_message_iter_get_arg_type (&iter_struct) != DBUS_TYPE_INT32) return FALSE;
+  dbus_message_iter_get_basic (&iter_struct, &y);
+  dbus_message_iter_next (&iter_struct);
+  if (dbus_message_iter_get_arg_type (&iter_struct) != DBUS_TYPE_INT32) return FALSE;
+  dbus_message_iter_get_basic (&iter_struct, &width);
+  dbus_message_iter_next (&iter_struct);
+  if (dbus_message_iter_get_arg_type (&iter_struct) != DBUS_TYPE_INT32) return FALSE;
+  dbus_message_iter_get_basic (&iter_struct, &height);
+  rect->x = x;
+  rect->y = y;
+  rect->width = width;
+  rect->height = height;
+  return TRUE;
+}
+
+static gchar *
+strdup_and_adjust_for_dbus (const char *s)
+{
+  gchar *d = g_strdup (s);
+  gchar *p;
+
+  if (!d)
+    return NULL;
+
+  for (p = d; *p; p++)
+  {
+    if (*p == '-')
+    {
+      memmove (p, p + 1, g_utf8_strlen (p, -1));
+      *p = toupper (*p);
+    }
+    else if (*p == ':')
+    {
+      p [1] = toupper (p [1]);
+    }
+  }
+
+  d [0] = toupper (d [0]);
+  return d;
+}
+
+static gboolean
+convert_event_type_to_dbus (const char *eventType, char **categoryp, char **namep, char **detailp, char **matchrule)
+{
+  gchar *tmp = strdup_and_adjust_for_dbus (eventType);
+  char *category = NULL, *name = NULL, *detail = NULL;
+  char *saveptr = NULL;
+  char *p;
+
+  if (tmp == NULL) return FALSE;
+  category = strtok_r (tmp, ":", &saveptr);
+  if (category) category = g_strdup (category);
+  if (!category) goto oom;
+  name = strtok_r (NULL, ":", &saveptr);
+  if (name)
+  {
+    name = g_strdup (name);
+    if (!name) goto oom;
+    detail = strtok_r (NULL, ":", &saveptr);
+    if (detail) detail = g_strdup (detail);
+  }
+  if (matchrule)
+  {
+    *matchrule = g_strdup_printf ("type='signal',interface='org.a11y.atspi.Event.%s'", category);
+    if (!*matchrule) goto oom;
+    if (name && name [0])
+    {
+      gchar *new_str = g_strconcat (*matchrule, ",member='", name, "'", NULL);
+      if (new_str)
+      {
+        g_free (*matchrule);
+        *matchrule = new_str;
+      }
+    }
+    if (detail && detail [0])
+    {
+      gchar *new_str = g_strconcat (*matchrule, ",arg0='", detail, "'", NULL);
+      if (new_str)
+      {
+        g_free (*matchrule);
+        *matchrule = new_str;
+      }
+    }
+  }
+  if (categoryp) *categoryp = category;
+  else g_free (category);
+  if (namep) *namep = name;
+  else if (name) g_free (name);
+  if (detailp) *detailp = detail;
+  else if (detail) g_free (detail);
+  g_free (tmp);
+  return TRUE;
+oom:
+  if (tmp) g_free (tmp);
+  if (category) g_free (category);
+  if (name) g_free (name);
+  if (detail) g_free (detail);
+  return FALSE;
+}
+
+static void
+listener_entry_free (EventListenerEntry *e)
+{
+  g_free (e->category);
+  g_free (e->name);
+  if (e->detail) g_free (e->detail);
+  g_free (e);
+}
+
+/**
+ * atspi_event_listener_register:
+ * @callback: (scope call): the #AtspiEventListenerCB to be registered against
+ *            an event type.
+ * @user_data: (closure): User data to be passed to the callback.
+ * @event_type: a character string indicating the type of events for which
+ *            notification is requested.  Format is
+ *            EventClass:major_type:minor_type:detail
+ *            where all subfields other than EventClass are optional.
+ *            EventClasses include "object", "window", "mouse",
+ *            and toolkit events (e.g. "Gtk", "AWT").
+ *            Examples: "focus:", "Gtk:GtkWidget:button_press_event".
+ *
+ * Legal object event types:
+ *
+ *    (property change events)
+ *
+ *            object:property-change
+ *            object:property-change:accessible-name
+ *            object:property-change:accessible-description
+ *            object:property-change:accessible-parent
+ *            object:property-change:accessible-value
+ *            object:property-change:accessible-role
+ *            object:property-change:accessible-table-caption
+ *            object:property-change:accessible-table-column-description
+ *            object:property-change:accessible-table-column-header
+ *            object:property-change:accessible-table-row-description
+ *            object:property-change:accessible-table-row-header
+ *            object:property-change:accessible-table-summary
+ *
+ *    (other object events)
+ *
+ *            object:state-changed 
+ *            object:children-changed
+ *            object:visible-data-changed
+ *            object:selection-changed
+ *            object:text-selection-changed
+ *            object:text-changed
+ *            object:text-caret-moved
+ *            object:row-inserted
+ *            object:row-reordered
+ *            object:row-deleted
+ *            object:column-inserted
+ *            object:column-reordered
+ *            object:column-deleted
+ *            object:model-changed
+ *            object:active-descendant-changed
+ *
+ *  (window events)
+ *
+ *            window:minimize
+ *            window:maximize
+ *            window:restore
+ *            window:close
+ *            window:create
+ *            window:reparent
+ *            window:desktop-create
+ *            window:desktop-destroy
+ *            window:activate
+ *            window:deactivate
+ *            window:raise
+ *            window:lower
+ *            window:move
+ *            window:resize
+ *            window:shade
+ *            window:unshade
+ *            window:restyle
+ *
+ *  (other events)
+ *
+ *            focus:
+ *            mouse:abs
+ *            mouse:rel
+ *            mouse:b1p
+ *            mouse:b1r
+ *            mouse:b2p
+ *            mouse:b2r
+ *            mouse:b3p
+ *            mouse:b3r
+ *
+ * NOTE: this string may be UTF-8, but should not contain byte value 56
+ *            (ascii ':'), except as a delimiter, since non-UTF-8 string
+ *            delimiting functions are used internally.
+ *            In general, listening to
+ *            toolkit-specific events is not recommended.
+ *
+ * Add an in-process callback function to an existing AtspiEventListener.
+ *
+ * Returns: #TRUE if successful, otherwise #FALSE.
+ **/
+gboolean
+atspi_event_listener_register (AtspiEventListenerCB callback,
+				 void *user_data,
+				 const gchar              *event_type)
+{
+  EventListenerEntry *e;
+  char *matchrule;
+  DBusError error;
+  GList *new_list;
+  DBusMessage *message, *reply;
+
+  if (!callback)
+    {
+      return FALSE;
+    }
+
+  e = g_new (EventListenerEntry, 1);
+  if (!e) return FALSE;
+  e->callback = callback;
+  e->user_data = user_data;
+  if (!convert_event_type_to_dbus (event_type, &e->category, &e->name, &e->detail, &matchrule))
+  {
+    g_free (e);
+    return FALSE;
+  }
+  new_list = g_list_prepend (event_listeners, e);
+  if (!new_list)
+  {
+    listener_entry_free (e);
+    return FALSE;
+  }
+  event_listeners = new_list;
+  dbus_error_init (&error);
+  dbus_bus_add_match (_atspi_bus(), matchrule, &error);
+  if (error.message)
+  {
+    g_warning ("Atspi: Adding match: %s", error.message);
+  }
+
+  dbus_error_init (&error);
+  message = dbus_message_new_method_call (atspi_bus_registry,
+	atspi_path_registry,
+	atspi_interface_registry,
+	"RegisterEvent");
+  if (!message)
+    return;
+  dbus_message_append_args (message, DBUS_TYPE_STRING, &event_type, DBUS_TYPE_INVALID);
+  reply = _atspi_dbus_send_with_reply_and_block (message);
+  dbus_message_unref (reply);
+
+  return TRUE;
+}
+
+static gboolean
+is_superset (const gchar *super, const gchar *sub)
+{
+  if (!super || !super [0])
+    return TRUE;
+  return (strcmp (super, sub) == 0);
+}
+
+/**
+ * atspi_event_listener_deregister:
+ * @callback: (scope call): the #AtspiEventListenerCB registered against an
+ *            event type.
+ * @user_data: (closure): User data that was passed in for this callback.
+ * @event_type: a string specifying the event type for which this
+ *             listener is to be deregistered.
+ *
+ * deregisters an #AtspiEventListenerCB from the registry, for a specific
+ *             event type.
+ *
+ * Returns: #TRUE if successful, otherwise #FALSE.
+ **/
+gboolean
+atspi_event_listener_deregister (AtspiEventListenerCB callback,
+				   void *user_data,
+				   const gchar              *event_type)
+{
+  char *category, *name, *detail, *matchrule;
+  GList *l;
+
+  if (!convert_event_type_to_dbus (event_type, &category, &name, &detail, &matchrule))
+  {
+    return FALSE;
+  }
+  if (!callback)
+    {
+      return FALSE;
+    }
+
+  for (l = event_listeners; l;)
+  {
+    EventListenerEntry *e = l->data;
+    if (e->callback == callback &&
+        e->user_data == user_data &&
+        is_superset (category, e->category) &&
+        is_superset (name, e->name) &&
+        is_superset (detail, e->detail))
+    {
+      DBusError error;
+      DBusMessage *message, *reply;
+      l = g_list_remove (l, e);
+      dbus_error_init (&error);
+      dbus_bus_remove_match (_atspi_bus(), matchrule, &error);
+      dbus_error_init (&error);
+      message = dbus_message_new_method_call (atspi_bus_registry,
+	    atspi_path_registry,
+	    atspi_interface_registry,
+	    "RegisterEvent");
+      if (!message)
+      return;
+      dbus_message_append_args (message, DBUS_TYPE_STRING, &event_type, DBUS_TYPE_INVALID);
+      reply = _atspi_dbus_send_with_reply_and_block (message);
+      dbus_message_unref (reply);
+
+      listener_entry_free (e);
+    }
+    else l = g_list_next (l);
+  }
+  g_free (category);
+  g_free (name);
+  if (detail) g_free (detail);
+  g_free (matchrule);
+  return TRUE;
+}
+
+void
+_atspi_send_event (AtspiEvent *e)
+{
+  char *category, *name, *detail;
+  GList *l;
+
+  if (!convert_event_type_to_dbus (e->type, &category, &name, &detail, NULL))
+  {
+    g_warning ("Atspi: Couldn't parse event: %s\n", e->type);
+    return;
+  }
+  for (l = event_listeners; l; l = g_list_next (l))
+  {
+    EventListenerEntry *entry = l->data;
+    if (!strcmp (category, entry->category) &&
+        (entry->name == NULL || !strcmp (name, entry->name)) &&
+        (entry->detail == NULL || !strcmp (detail, entry->detail)))
+    {
+        entry->callback (entry->user_data, e);
+    }
+  }
+  if (detail) g_free (detail);
+  g_free (name);
+  g_free (category);
+}
+
+DBusHandlerResult
+atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data)
+{
+  char *detail = NULL;
+  const char *category = dbus_message_get_interface (message);
+  const char *member = dbus_message_get_member (message);
+  gchar *name;
+  gchar *converted_type;
+  DBusMessageIter iter, iter_variant;
+  dbus_message_iter_init (message, &iter);
+  AtspiEvent e;
+  dbus_int32_t detail1, detail2;
+  char *p;
+
+  if (category)
+  {
+    category = g_utf8_strrchr (category, -1, '.');
+    if (category == NULL)
+    {
+      // TODO: Error
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+    category++;
+  }
+  g_return_val_if_fail (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+  dbus_message_iter_get_basic (&iter, &detail);
+  dbus_message_iter_next (&iter);
+  /* TODO: Return error indicating invalid arguments  in next line */
+  g_return_val_if_fail (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_INT32, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+  dbus_message_iter_get_basic (&iter, &detail1);
+  e.detail1 = detail1;
+  dbus_message_iter_next (&iter);
+  g_return_val_if_fail (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_INT32, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+  dbus_message_iter_get_basic (&iter, &detail2);
+  e.detail2 = detail2;
+  dbus_message_iter_next (&iter);
+
+  converted_type = convert_name_from_dbus (category);
+  name = convert_name_from_dbus (member);
+  detail = convert_name_from_dbus (detail);
+
+  if (strcasecmp  (category, name) != 0)
+  {
+    p = g_strconcat (converted_type, ":", name, NULL);
+    if (p)
+    {
+      g_free (converted_type);
+      converted_type = p;
+    }
+  }
+  if (detail[0] != '\0')
+  {
+    p = g_strconcat (converted_type, ":", detail, NULL);
+    if (p)
+    {
+      g_free (converted_type);
+      converted_type = p;
+    }
+  }
+  e.type = converted_type;
+  e.source = _atspi_ref_accessible (dbus_message_get_sender(message), dbus_message_get_path(message));
+  dbus_message_iter_recurse (&iter, &iter_variant);
+  switch (dbus_message_iter_get_arg_type (&iter_variant))
+  {
+    case DBUS_TYPE_STRUCT:
+    {
+      if (demarshal_rect (&iter_variant, &e.v.rect))
+      {
+	e.v_type = EVENT_DATA_RECT;
+      }
+      else
+      {
+        e.v_type = EVENT_DATA_OBJECT;
+        e.v.accessible = _atspi_dbus_return_accessible_from_iter (&iter_variant);
+      }
+      break;
+    }
+    case DBUS_TYPE_STRING:
+    {
+      dbus_message_iter_get_basic (&iter_variant, &p);
+      e.v_type = EVENT_DATA_STRING;
+      e.v.text = g_strdup (p);
+      break;
+    }
+  default:
+    break;
+  }
+  _atspi_send_event (&e);
+
+  if (!strcmp (e.type, "children-changed"))
+  {
+    cache_process_children_changed (&e);
+  }
+  else if (!strcmp (e.type, "property-change"))
+  {
+    cache_process_property_change (&e);
+  }
+  else if (!strcmp (e.type, "state-changed"))
+  {
+    cache_process_state_changed (&e);
+  }
+
+  g_free (converted_type);
+  g_free (name);
+  g_free (detail);
+  g_object_unref (e.source);
+  if (e.v_type == EVENT_DATA_OBJECT)
+    g_object_unref (e.v.accessible);
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
diff --git a/atspi/atspi-event-listener.h b/atspi/atspi-event-listener.h
new file mode 100644
index 0000000..228dbcc
--- /dev/null
+++ b/atspi/atspi-event-listener.h
@@ -0,0 +1,52 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2002 Ximian, Inc.
+ *           2002 Sun Microsystems 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_EVENT_LISTENER_H_
+#define _ATSPI_EVENT_LISTENER_H_
+
+#include "glib-object.h"
+
+#include "atspi-event-types.h"
+
+/**
+ * AtspiEventListenerCB:
+ * @event: The event for which notification is sent.
+ * @user_data: User data which is passed to the callback each time a notification takes place.
+ *
+ * A function prototype for callbacks via which clients are notified of AT-SPI events.
+ * 
+ **/
+typedef void       (*AtspiEventListenerCB)     (const AtspiEvent     *event,
+						     void                      *user_data);
+
+gboolean
+atspi_event_listener_register (AtspiEventListenerCB callback,
+				 void *user_data,
+				 const gchar              *event_type);
+
+gboolean
+atspi_event_listener_deregister (AtspiEventListenerCB callback,
+				   void *user_data,
+				   const gchar              *event_type);
+#endif	/* _ATSPI_EVENT_LISTENER_H_ */
diff --git a/atspi/atspi-event-types.h b/atspi/atspi-event-types.h
index 154ba1b..8f88931 100644
--- a/atspi/atspi-event-types.h
+++ b/atspi/atspi-event-types.h
@@ -27,6 +27,7 @@
 #include <glib.h>
 
 #include "atspi-accessible.h"
+#include "atspi-component.h"	/* for AtspiRect */
 
 typedef guint AtspiControllerEventMask;
 
@@ -65,6 +66,13 @@ struct _AtspiKeyDefinition
   gint unused;
 };
 
+typedef enum
+{
+  EVENT_DATA_STRING,
+  EVENT_DATA_OBJECT,
+  EVENT_DATA_RECT
+} EVENT_DATA_TYPE;
+
 typedef struct _AtspiEvent AtspiEvent;
 struct _AtspiEvent
 {
@@ -72,7 +80,13 @@ struct _AtspiEvent
   AtspiAccessible  *source;
   gint         detail1;
   gint         detail2;
-  GVariant *any;
+  union
+  {
+    gchar *text;
+    AtspiAccessible *accessible;
+    AtspiRect rect;
+  } v;
+  EVENT_DATA_TYPE v_type;
 };
 
 typedef void AtspiKeystrokeListener;
diff --git a/atspi/atspi-misc-private.h b/atspi/atspi-misc-private.h
index 9db49be..c65ee5d 100644
--- a/atspi/atspi-misc-private.h
+++ b/atspi/atspi-misc-private.h
@@ -33,6 +33,13 @@
 
 #include "dbind/dbind.h"
 
+#define ATSPI_CACHE_PARENT      0x0001
+#define ATSPI_CACHE_CHILDREN    0x0002
+#define ATSPI_CACHE_NAME        0x0004
+#define ATSPI_CACHE_DESCRIPTION 0x0008
+#define ATSPI_CACHE_STATES      0x0010
+#define ATSPI_CACHE_ROLE        0x0010
+
 typedef struct _AtspiReference AtspiReference;
 struct _AtspiReference
 {
@@ -62,6 +69,7 @@ struct _AtspiReference
 #define ATSPI_DBUS_INTERFACE_EDITABLE_TEXT "org.a11y.atspi.EditableText"
 #define ATSPI_DBUS_INTERFACE_EVENT_KEYBOARD "org.a11y.atspi.Event.Keyboard"
 #define ATSPI_DBUS_INTERFACE_EVENT_MOUSE "org.a11y.atspi.Event.Mouse"
+#define ATSPI_DBUS_INTERFACE_EVENT_OBJECT "org.a11y.atspi.Event.Object"
 #define ATSPI_DBUS_INTERFACE_HYPERLINK "org.a11y.atspi.Hyperlink"
 #define ATSPI_DBUS_INTERFACE_HYPERTEXT "org.a11y.atspi.Hypertext"
 #define ATSPI_DBUS_INTERFACE_IMAGE "org.a11y.atspi.Image"
@@ -104,6 +112,9 @@ AtspiAccessible * _atspi_ref_accessible (const char *app, const char *path);
 AtspiAccessible *
 _atspi_dbus_return_accessible_from_message (DBusMessage *message);
 
+AtspiAccessible *
+_atspi_dbus_return_accessible_from_iter (DBusMessageIter *iter);
+
 AtspiAccessible * _atspi_ref_related_accessible (AtspiAccessible *obj, const AtspiReference *ref);
 
 dbus_bool_t _atspi_dbus_call (AtspiAccessible *obj, const char *interface, const char *method, GError **error, const char *type, ...);
diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c
index efdb84f..a36c402 100644
--- a/atspi/atspi-misc.c
+++ b/atspi/atspi-misc.c
@@ -28,6 +28,8 @@
  */
 
 #include "atspi-private.h"
+#include "X11/Xlib.h"
+#include <stdio.h>
 
 static DBusConnection *bus = NULL;
 static GHashTable *apps = NULL;
@@ -47,6 +49,7 @@ const char *atspi_interface_dec = ATSPI_DBUS_INTERFACE_DEC;
 const char *atspi_interface_device_event_listener = ATSPI_DBUS_INTERFACE_DEVICE_EVENT_LISTENER;
 const char *atspi_interface_document = ATSPI_DBUS_INTERFACE_DOCUMENT;
 const char *atspi_interface_editable_text = ATSPI_DBUS_INTERFACE_EDITABLE_TEXT;
+const char *atspi_interface_event_object = ATSPI_DBUS_INTERFACE_EVENT_OBJECT;
 const char *atspi_interface_hyperlink = ATSPI_DBUS_INTERFACE_HYPERLINK;
 const char *atspi_interface_hypertext = ATSPI_DBUS_INTERFACE_HYPERTEXT;
 const char *atspi_interface_image = ATSPI_DBUS_INTERFACE_IMAGE;
@@ -267,10 +270,7 @@ send_children_changed (AtspiAccessible *parent, AtspiAccessible *child, gboolean
   e.type = (add? "object:children-changed:add": "object:children-changed:remove");
   e.source = parent;
   e.detail1 = g_list_index (parent->children, child);
-#if 0
-  g_warning ("atspi: TODO: Finish events");
-  atspi_dispatch_event (&e);
-#endif
+  _atspi_send_event (&e);
 }
 
 static void
@@ -309,7 +309,7 @@ remove_app_from_desktop (AtspiAccessible *a, const char *bus_name)
 
 static AtspiAccessible *desktop;
 
-static void
+void
 get_reference_from_iter (DBusMessageIter *iter, const char **app_name, const char **path)
 {
   DBusMessageIter iter_struct;
@@ -399,13 +399,13 @@ add_accessible_from_iter (DBusMessageIter *iter)
   if (count != 2)
   {
     g_warning ("at-spi: expected 2 values in states array; got %d\n", count);
-    accessible->states = atspi_state_set_new (0);
+    accessible->states = atspi_state_set_new (accessible, 0);
   }
   else
   {
     guint64 val = ((guint64)states [1]) << 32;
     val += states [0];
-    accessible->states = atspi_state_set_new (val);
+    accessible->states = atspi_state_set_new (accessible, val);
   }
   dbus_message_iter_next (&iter_struct);
 
@@ -511,15 +511,13 @@ AtspiAccessible *
 _atspi_dbus_return_accessible_from_message (DBusMessage *message)
 {
   DBusMessageIter iter;
-  const char *app_name, *path;
   AtspiAccessible *retval = NULL;
   const char *signature = dbus_message_get_signature (message);
    
   if (!strcmp (signature, "(so)"))
   {
     dbus_message_iter_init (message, &iter);
-    get_reference_from_iter (&iter, &app_name, &path);
-    retval = _atspi_ref_accessible (app_name, path);
+    retval =  _atspi_dbus_return_accessible_from_iter (&iter);
   }
   else
   {
@@ -529,6 +527,15 @@ _atspi_dbus_return_accessible_from_message (DBusMessage *message)
   return retval;
 }
 
+AtspiAccessible *
+_atspi_dbus_return_accessible_from_iter (DBusMessageIter *iter)
+{
+  const char *app_name, *path;
+
+  get_reference_from_iter (iter, &app_name, &path);
+  return ref_accessible (app_name, path);
+}
+
 /* TODO: Remove this function. We should not need it anymore.
  * If we do, it's a bug.
  */
@@ -539,7 +546,7 @@ _atspi_ref_related_accessible (AtspiAccessible *obj, const AtspiReference *ref)
   return ref_accessible (app, obj->path);
 }
 
-const char *cache_signal_type = "((so)(so)a(so)assusau)";
+const char *cache_signal_type = "((so)(so)(so)a(so)assusau)";
 
 static DBusHandlerResult
 handle_add_accessible (DBusConnection *bus, DBusMessage *message, void *user_data)
@@ -569,10 +576,9 @@ atspi_dbus_filter (DBusConnection *bus, DBusMessage *message, void *data)
   char *bus_name;
 
   if (type == DBUS_MESSAGE_TYPE_SIGNAL &&
-      !strncmp (interface, "org.a11y.atspi.Event.", 28))
+      !strncmp (interface, "org.a11y.atspi.Event.", 21))
   {
-    g_warning ("atspi: TODO: event");
-    //return handle_event (bus, message, data);
+    return atspi_dbus_handle_event (bus, message, data);
   }
   if (dbus_message_is_method_call (message, atspi_interface_device_event_listener, "notifyEvent"))
   {
@@ -602,6 +608,108 @@ static const char *signal_interfaces[] =
   NULL
 };
 
+/*
+ * Returns a 'canonicalized' value for DISPLAY,
+ * with the screen number stripped off if present.
+ *
+ * TODO: Avoid having duplicate functions for this here and in at-spi2-atk
+ */
+static const gchar *
+spi_display_name (void)
+{
+  static const char *canonical_display_name = NULL;
+  if (!canonical_display_name)
+    {
+      const gchar *display_env = g_getenv ("AT_SPI_DISPLAY");
+      if (!display_env)
+        {
+          display_env = g_getenv ("DISPLAY");
+          if (!display_env || !display_env[0])
+            canonical_display_name = ":0";
+          else
+            {
+              gchar *display_p, *screen_p;
+              canonical_display_name = g_strdup (display_env);
+              display_p = strrchr (canonical_display_name, ':');
+              screen_p = strrchr (canonical_display_name, '.');
+              if (screen_p && display_p && (screen_p > display_p))
+                {
+                  *screen_p = '\0';
+                }
+            }
+        }
+      else
+        {
+          canonical_display_name = display_env;
+        }
+    }
+  return canonical_display_name;
+}
+
+/* TODO: Avoid having duplicate functions for this here and in at-spi2-atk */
+static DBusConnection *
+get_accessibility_bus ()
+{
+  Atom AT_SPI_BUS;
+  Atom actual_type;
+  Display *bridge_display;
+  int actual_format;
+  unsigned char *data = NULL;
+  unsigned long nitems;
+  unsigned long leftover;
+
+  DBusConnection *bus = NULL;
+  DBusError error;
+
+  bridge_display = XOpenDisplay (spi_display_name ());
+  if (!bridge_display)
+    {
+      g_warning ("AT_SPI: Could not get the display\n");
+      return NULL;
+    }
+
+  AT_SPI_BUS = XInternAtom (bridge_display, "AT_SPI_BUS", False);
+  XGetWindowProperty (bridge_display,
+                      XDefaultRootWindow (bridge_display),
+                      AT_SPI_BUS, 0L,
+                      (long) BUFSIZ, False,
+                      (Atom) 31, &actual_type, &actual_format,
+                      &nitems, &leftover, &data);
+
+  dbus_error_init (&error);
+
+  if (data == NULL)
+    {
+      g_warning
+        ("AT-SPI: Accessibility bus not found - Using session bus.\n");
+      bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
+      if (!bus)
+        {
+          g_warning ("AT-SPI: Couldn't connect to bus: %s\n", error.message);
+          return NULL;
+        }
+    }
+  else
+    {
+      bus = dbus_connection_open (data, &error);
+      if (!bus)
+        {
+          g_warning ("AT-SPI: Couldn't connect to bus: %s\n", error.message);
+          return NULL;
+        }
+      else
+        {
+          if (!dbus_bus_register (bus, &error))
+            {
+              g_warning ("AT-SPI: Couldn't register with bus: %s\n", error.message);
+              return NULL;
+            }
+        }
+    }
+
+  return bus;
+}
+
 /**
  * atspi_init:
  *
@@ -626,10 +734,9 @@ atspi_init (void)
   g_type_init ();
 
   get_live_refs();
-  g_atexit (cleanup);
 
   dbus_error_init (&error);
-  bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
+  bus = get_accessibility_bus ();
   if (!bus)
   {
     g_error ("Couldn't get session bus");
@@ -645,12 +752,15 @@ atspi_init (void)
   match = g_strdup_printf ("type='signal',interface='%s',member='RemoveAccessible'", atspi_interface_cache);
   dbus_bus_add_match (bus, match, &error);
   g_free (match);
-  for (i = 0; signal_interfaces[i]; i++)
-  {
-    match = g_strdup_printf ("type='signal',interface='%s'", signal_interfaces[i]);
-    dbus_bus_add_match (bus, match, &error);
-    g_free (match);
-  }
+  match = g_strdup_printf ("type='signal',interface='%s',member='ChildrenChanged'", atspi_interface_event_object);
+  dbus_bus_add_match (bus, match, &error);
+  g_free (match);
+  match = g_strdup_printf ("type='signal',interface='%s',member='PropertyChange'", atspi_interface_event_object);
+  dbus_bus_add_match (bus, match, &error);
+  g_free (match);
+  match = g_strdup_printf ("type='signal',interface='%s',member='StateChanged'", atspi_interface_event_object);
+  dbus_bus_add_match (bus, match, &error);
+  g_free (match);
   return 0;
 }
 
diff --git a/atspi/atspi-private.h b/atspi/atspi-private.h
index fe06c1f..bab5349 100644
--- a/atspi/atspi-private.h
+++ b/atspi/atspi-private.h
@@ -25,7 +25,8 @@
 #ifndef _ATSPI_PRIVATE_H_
 #define _ATSPI_PRIVATE_H_
 
-#include "atspi-listener-private.h"
+#include "atspi-device-listener-private.h"
+#include "atspi-event-listener-private.h"
 #include "atspi-misc-private.h"
 
 #include "atspi.h"
diff --git a/atspi/atspi-registry.c b/atspi/atspi-registry.c
index 3bf5b60..15263e1 100644
--- a/atspi/atspi-registry.c
+++ b/atspi/atspi-registry.c
@@ -95,19 +95,20 @@ atspi_get_desktop_list ()
  * atspi_register_accessible_keystroke_listener:
  * @listener:  a pointer to the #AccessibleKeystrokeListener for which
  *             keystroke events are requested.
- * @keys:      a pointer to the #AccessibleKeySet indicating which
- *             keystroke events are requested, or #ATSPI_KEYSET_ALL_KEYS
+ * @keys: (type: AtspiKeyDefinition): a pointer to the
+ *        #AccessibleKeyDefinition array indicating which keystroke events are requested, or #ATSPI_KEYSET_ALL_KEYS
  *             to indicate that all keycodes and keyvals for the specified
  *             modifier set are to be included.
- * @modmask:   an #AccessibleKeyMaskType mask indicating which
+ * @modmask:   an #AtspiKeyMaskType mask indicating which
  *             key event modifiers must be set in combination with @keys,
  *             events will only be reported for key events for which all
  *             modifiers in @modmask are set.  If you wish to listen for
  *             events with multiple modifier combinations you must call
- *             registerAccessibleKeystrokeListener() once for each combination.
- * @eventmask: an #AccessibleKeyMaskType mask indicating which
+ *             register_accessible_keystroke_listener() once for each
+ *             combination.
+ * @eventmask: an #AtspiKeyMaskType mask indicating which
  *             types of key events are requested (#ATSPI_KEY_PRESSED, etc.).
- * @sync_type: a #AccessibleKeyListenerSyncType parameter indicating
+ * @sync_type: a #AtspiKeyListenerSyncType parameter indicating
  *             the behavior of the notification/listener transaction.
  *             
  * Register a listener for keystroke events, either pre-emptively for
@@ -121,17 +122,17 @@ atspi_get_desktop_list ()
  * Returns: #TRUE if successful, otherwise #FALSE.
  **/
 gboolean
-atspi_register_accessible_keystroke_listener (AtspiKeystrokeListener  *listener,
-					 AtspiKeySet             *keys,
+atspi_register_accessible_keystroke_listener (AtspiDeviceListener  *listener,
+					 GArray             *key_set,
 					 AtspiKeyMaskType         modmask,
-					 AtspiKeyEventMask        eventmask,
+					 AtspiKeyEventMask        event_types,
 					 AtspiKeyListenerSyncType sync_type, GError **error)
 {
+  GArray *d_key_set;
   gchar *path = _atspi_device_listener_get_path (listener);
   gint                                i;
-  GArray *key_set;
-  dbus_uint32_t key_events = 0;
-  AtspiControllerEventMask   controller_event_mask;
+  dbus_uint32_t d_modmask = modmask;
+  dbus_uint32_t d_event_types = event_types;
   AtspiEventListenerMode     listener_mode;
   gboolean                          retval = FALSE;
   DBusError d_error;
@@ -142,42 +143,31 @@ atspi_register_accessible_keystroke_listener (AtspiKeystrokeListener  *listener,
     }
 
   /* copy the keyval filter values from the C api into the DBind KeySet */
-  if (keys)
+  if (key_set)
     {
-      key_set = g_array_sized_new (FALSE, TRUE, sizeof (AtspiKeyDefinition), keys->len);
-      key_set->len = keys->len;
-      for (i = 0; i < keys->len; ++i)
+      d_key_set = g_array_sized_new (FALSE, TRUE, sizeof (AtspiKeyDefinition), key_set->len);
+      d_key_set->len = key_set->len;
+      for (i = 0; i < key_set->len; ++i)
         {
 	  AtspiKeyDefinition *kd =  ((AtspiKeyDefinition *) key_set->data) + i;
-          kd->keycode = keys->keycodes[i];
-	  kd->keysym = keys->keysyms[i];
-	  if (keys->keystrings && keys->keystrings[i])
+	  AtspiKeyDefinition *d_kd =  ((AtspiKeyDefinition *) d_key_set->data) + i;
+          d_kd->keycode = kd->keycode;
+	  d_kd->keysym = kd->keysym;
+	  if (kd->keystring)
 	    {
-	      kd->keystring = keys->keystrings[i];
+	      d_kd->keystring = kd->keystring;
 	    } 
           else 
             {
-	      kd->keystring = "";
+	      d_kd->keystring = "";
 	    }
         }
     }
   else
     {
-      key_set = g_array_sized_new (FALSE, TRUE, sizeof (AtspiKeyDefinition), 0);
+      d_key_set = g_array_sized_new (FALSE, TRUE, sizeof (AtspiKeyDefinition), 0);
     }
 	
-  /* copy the event filter values from the C api into the DBus key_events */
-  if (eventmask & ATSPI_KEY_PRESSED)
-    {
-      key_events |= (1 << ATSPI_KEY_PRESSED_EVENT);
-    }
-  if (eventmask & ATSPI_KEY_RELEASED)
-    {
-      key_events |= (1 << ATSPI_KEY_RELEASED_EVENT);
-    }
-  
-  controller_event_mask = (dbus_uint32_t) modmask;
-
   listener_mode.synchronous =
 	  (dbus_bool_t) ((sync_type & ATSPI_KEYLISTENER_SYNCHRONOUS)!=0);
   listener_mode.preemptive =
@@ -186,7 +176,7 @@ atspi_register_accessible_keystroke_listener (AtspiKeystrokeListener  *listener,
 	  (dbus_bool_t) ((sync_type & ATSPI_KEYLISTENER_ALL_WINDOWS)!=0);
 
     dbus_error_init (&d_error);
-    dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry, atspi_path_dec, atspi_interface_dec, "RegisterKeystrokeListener", &d_error, "oa(iisi)uu(bbb)=>b", path, key_set, controller_event_mask, key_events, &listener_mode, &retval);
+    dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry, atspi_path_dec, atspi_interface_dec, "RegisterKeystrokeListener", &d_error, "oa(iisi)uu(bbb)=>b", path, d_key_set, d_modmask, d_event_types, &listener_mode, &retval);
 
   g_array_free (key_set, TRUE);
   g_free (path);
@@ -207,13 +197,13 @@ atspi_register_accessible_keystroke_listener (AtspiKeystrokeListener  *listener,
  * Returns: #TRUE if successful, otherwise #FALSE.
  **/
 gboolean
-atspi_deregister_accessible_keystroke_listener (AtspiKeystrokeListener *listener,
-					   AtspiKeyMaskType        modmask, GError **error)
+atspi_deregister_accessible_keystroke_listener (AtspiDeviceListener *listener,
+					   AtspiKeyMaskType        modmask, AtspiKeyEventMask event_types, GError **error)
 {
   gchar *path = _atspi_device_listener_get_path (listener);
-  AtspiControllerEventMask   controller_event_mask;
   GArray *key_set;
-  dbus_uint32_t key_events = 0;
+  dbus_uint32_t d_modmask = modmask;
+  dbus_uint32_t d_event_types = event_types;
   DBusError d_error;
 
   dbus_error_init (&d_error);
@@ -222,10 +212,8 @@ atspi_deregister_accessible_keystroke_listener (AtspiKeystrokeListener *listener
       return FALSE;
     }
 
-  controller_event_mask = (dbus_uint32_t) modmask;
-
       key_set = g_array_sized_new (FALSE, TRUE, sizeof (AtspiKeyDefinition), 0);
-    dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry, atspi_path_dec, atspi_interface_dec, "DeregisterKeystrokeListener", &d_error, "oa(iisi)uu", path, &key_set, key_events, controller_event_mask);
+    dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry, atspi_path_dec, atspi_interface_dec, "DeregisterKeystrokeListener", &d_error, "oa(iisi)uu", path, &key_set, d_modmask, d_event_types);
   g_free (path);
   return TRUE;
 }
@@ -234,7 +222,7 @@ atspi_deregister_accessible_keystroke_listener (AtspiKeystrokeListener *listener
  * atspi_register_device_event_listener:
  * @listener:  a pointer to the #AtspiDeviceListener which requests
  *             the events.
- * @eventmask: an #AtspiDeviceEventMask mask indicating which
+ * @event_types: an #AtspiDeviceEventMask mask indicating which
  *             types of key events are requested (#ATSPI_KEY_PRESSED, etc.).
  * @filter: Unused parameter.
  *             
@@ -244,11 +232,11 @@ atspi_deregister_accessible_keystroke_listener (AtspiKeystrokeListener *listener
  **/
 gboolean
 atspi_register_device_event_listener (AtspiDeviceListener  *listener,
-				 AtspiDeviceEventMask  event_mask,
+				 AtspiDeviceEventMask  event_types,
 				 void                      *filter, GError **error)
 {
   gboolean                          retval = FALSE;
-  dbus_uint32_t d_event_mask = event_mask;
+  dbus_uint32_t d_event_types = event_types;
   gint                                i;
   gchar *path = _atspi_device_listener_get_path (listener);
   DBusError d_error;
@@ -259,7 +247,7 @@ atspi_register_device_event_listener (AtspiDeviceListener  *listener,
       return retval;
     }
 
-    dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry, atspi_path_dec, atspi_interface_dec, "RegisterDeviceEventListener", &d_error, "ou=>b", path, d_event_mask, &retval);
+    dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry, atspi_path_dec, atspi_interface_dec, "RegisterDeviceEventListener", &d_error, "ou=>b", path, d_event_types, &retval);
   g_free (path);
   return retval;
 }
diff --git a/atspi/atspi-registry.h b/atspi/atspi-registry.h
index 4fa64e9..f9894cd 100644
--- a/atspi/atspi-registry.h
+++ b/atspi/atspi-registry.h
@@ -27,7 +27,7 @@
 
 #include "atspi-accessible.h"
 #include "atspi-event-types.h"
-#include "atspi-listener.h"
+#include "atspi-device-listener.h"
 
 gint atspi_get_desktop_count ();
 
@@ -36,19 +36,21 @@ AtspiAccessible* atspi_get_desktop (gint i);
 GArray *atspi_get_desktop_list ();
 
 gboolean
-atspi_register_accessible_keystroke_listener (AtspiKeystrokeListener  *listener,
-					 AtspiKeySet             *keys,
+atspi_register_accessible_keystroke_listener (AtspiDeviceListener  *listener,
+					 GArray *key_set,
 					 AtspiKeyMaskType         modmask,
-					 AtspiKeyEventMask        event_mask,
+					 AtspiKeyEventMask        event_types,
 					 AtspiKeyListenerSyncType sync_type, GError **error);
 
 gboolean
-atspi_deregister_accessible_keystroke_listener (AtspiKeystrokeListener *listener,
-					   AtspiKeyMaskType        modmask, GError **error);
+atspi_deregister_accessible_keystroke_listener (AtspiDeviceListener *listener,
+					        AtspiKeyMaskType         modmask,
+					        AtspiKeyEventMask        event_types,
+					        GError **error);
 
 gboolean
 atspi_register_device_event_listener (AtspiDeviceListener  *listener,
-				 AtspiDeviceEventMask  eventmask,
+				 AtspiDeviceEventMask  event_types,
 				 void                      *filter, GError **error);
 
 gboolean
diff --git a/atspi/atspi-stateset.c b/atspi/atspi-stateset.c
index 74d45c3..0da98b0 100644
--- a/atspi/atspi-stateset.c
+++ b/atspi/atspi-stateset.c
@@ -4,6 +4,52 @@ static void atspi_state_set_class_init (AtspiStateSetClass *klass);
 
 G_DEFINE_TYPE (AtspiStateSet, atspi_state_set, G_TYPE_OBJECT)
 
+static const char *state_names [] =
+{
+  "invalid",
+  "active",
+  "armed",
+  "busy",
+  "checked",
+  "collapsed",
+  "defunct",
+  "editable",
+  "enabled",
+  "expandable",
+  "expanded",
+  "focusable",
+  "focused",
+  "has-tool-tip",
+  "horizontal",
+  "iconified",
+  "modal",
+  "multi-line",
+  "multiselectable",
+  "opaque",
+  "pressed",
+  "resizable",
+  "selectable",
+  "selected",
+  "sensitive",
+  "showing",
+  "singleLine",
+  "stale",
+  "transient",
+  "vertical",
+  "visible",
+  "manages-descendants",
+  "indeterminate",
+  "required",
+  "truncated",
+  "animated",
+  "invalid-entry",
+  "supports-autocompletion",
+  "selectable-text",
+  "is-default",
+  "visited",
+  NULL
+};
+
 static void
 atspi_state_set_init (AtspiStateSet *set)
 {
@@ -16,13 +62,76 @@ atspi_state_set_class_init (AtspiStateSetClass* klass)
 }
 
 AtspiStateSet *
-atspi_state_set_new (gint64 states)
+atspi_state_set_new (AtspiAccessible *accessible, gint64 states)
 {
   AtspiStateSet *set;
   
   set = g_object_new (ATSPI_TYPE_STATE_SET, NULL);
   g_return_val_if_fail (set != NULL, NULL);
 
+  set->accessible = accessible;
   set->states = states;
   return set;
 }
+
+void atspi_state_set_set_by_name (AtspiStateSet *set, const gchar *name, gboolean enabled)
+{
+  gint i = 0;
+
+  if (!(set->accessible->cached_properties & ATSPI_CACHE_STATES))
+    return;
+
+  /* TODO: This could perhaps be optimized */
+  for (i = 0; state_names [i]; i++)
+  {
+    if (!strcmp (state_names [i], name))
+    {
+      if (enabled)
+        set->states |= (1 << i);
+      else
+        set->states &= ~(1 << i);
+      return;
+    }
+  }
+  g_warning ("at-spi: Attempt to set unknown state '%s'", name);
+}
+
+static void
+refresh_states (AtspiStateSet *set)
+{
+  GArray *state_array;
+  dbus_uint32_t *states;
+
+  if ((set->accessible->cached_properties & ATSPI_CACHE_STATES))
+    return;
+
+  if (!_atspi_dbus_call (set->accessible, atspi_interface_accessible, "GetState", NULL, "=>au", &state_array))
+    return;
+
+  states = (dbus_uint32_t *) state_array->data;
+
+  set->states = ((gint64)states [1]) << 32;
+  set->states += states [0];
+  g_array_free (state_array, TRUE);
+}
+
+/**
+ * atspi_state_set_contains:
+ * @set: a pointer to the #AtspiStateSet object on which to operate.
+ * @state: an #AtspiStateType for which the specified #AtspiStateSet
+ *       will be queried.
+ *
+ * Determine whether a given #AtspiStateSet includes a given state; that is,
+ *       whether @state is true for the stateset in question.
+ *
+ * Returns: #TRUE if @state is true/included in the given #AtspiStateSet,
+ *          otherwise #FALSE.
+ *
+ **/
+gboolean
+atspi_state_set_contains (AtspiStateSet *set,
+			     AtspiStateType state)
+{
+  refresh_states (set);
+  return (set->states & (1 << state)) ? TRUE : FALSE;
+}
diff --git a/atspi/atspi-stateset.h b/atspi/atspi-stateset.h
index 44690b5..6b674e4 100644
--- a/atspi/atspi-stateset.h
+++ b/atspi/atspi-stateset.h
@@ -12,6 +12,7 @@ typedef struct _AtspiStateSet AtspiStateSet;
 struct _AtspiStateSet
 {
   GObject parent;
+  struct _AtspiAccessible *accessible;
   gint64 states;
 };
 
@@ -24,6 +25,7 @@ struct _AtspiStateSetClass
 GType atspi_state_set_get_type (void);
 
 AtspiStateSet *
-atspi_state_set_new (gint64 states);
+atspi_state_set_new (struct _AtspiAccessible *accessible, gint64 states);
 
+gboolean atspi_state_set_contains (AtspiStateSet *set, AtspiStateType state);
 #endif	/* _ATSPI_STATE_SET_H_ */
diff --git a/atspi/atspi-types.h b/atspi/atspi-types.h
index 3387824..fba3adb 100644
--- a/atspi/atspi-types.h
+++ b/atspi/atspi-types.h
@@ -31,7 +31,7 @@
 
 typedef struct _AtspiAccessible AtspiAction;
 typedef struct _AtspiAccessible AtspiCollection;
-typedef struct _AtspiAccessible AtspiComponent;
+typedef struct _AtspiComponent AtspiComponent;
 typedef struct _AtspiAccessible AtspiDocument;
 typedef struct _AtspiAccessible AtspiEditableText;
 typedef struct _AtspiAccessible AtspiHypertext;
diff --git a/atspi/atspi.h b/atspi/atspi.h
index 9bb5da2..a6119a8 100644
--- a/atspi/atspi.h
+++ b/atspi/atspi.h
@@ -30,7 +30,8 @@
 #include "atspi-types.h"
 #include "atspi-accessible.h"
 #include "atspi-component.h"
-#include "atspi-listener.h"
+#include "atspi-device-listener.h"
+#include "atspi-event-listener.h"
 #include "atspi-misc.h"
 #include "atspi-registry.h"
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]