[at-spi2-core/gi] Some work on event support; many bug fixes
- From: Mike Gorse <mgorse src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [at-spi2-core/gi] Some work on event support; many bug fixes
- Date: Sat, 6 Nov 2010 11:09:27 +0000 (UTC)
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]