[dasher] Add AT-SPI 2 support.
- From: Patrick Welche <pwelche src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dasher] Add AT-SPI 2 support.
- Date: Tue, 15 Jan 2013 16:18:40 +0000 (UTC)
commit e95c462e87378b0a9b9bfd46d0ba17040d89a38a
Author: Patrick Welche <prlw1 cam ac uk>
Date: Tue Jan 15 09:59:04 2013 +0000
Add AT-SPI 2 support.
Direct mode may now use the DBus based accessibility bus with GTK3
instead of using Xtst.
INSTALL.Linux | 32 ++--
Src/Gtk2/Makefile.am | 8 +
Src/Gtk2/dasher_editor_external.h | 11 +-
Src/Gtk2/dasher_editor_external_atspi.cpp | 242 +++++++++++++++++++++++++++++
Src/Gtk2/dasher_editor_external_cspi.cpp | 9 +-
Src/Gtk2/dasher_editor_private.h | 2 +
Src/Makefile.am | 3 +
Src/main.cc | 4 +-
configure.ac | 23 ++-
9 files changed, 298 insertions(+), 36 deletions(-)
---
diff --git a/INSTALL.Linux b/INSTALL.Linux
index 555518e..2d99f29 100644
--- a/INSTALL.Linux
+++ b/INSTALL.Linux
@@ -1,4 +1,4 @@
-Copyright (C) 2008 The Dasher Project
+Copyright (C) 2013 The Dasher Project
This file is free documentation; the Dasher Project gives unlimited
permission to copy, distribute and modify it.
@@ -11,17 +11,15 @@ etc.), which are described in the 'INSTALL' file. The following is
specific to building and installing Dasher on Linux. The Dasher
maintainer documentation is at http://live.gnome.org/Dasher.
-If you are building sources from the Subversion then you must first
-install all the packages required to build Dasher. On Debian based
-distributions the following can be used.
+If you are building sources from the Git repository then you must
+first install all the packages required to build Dasher. On Debian
+based distributions the following can be used.
packages="g++
- gnome-common
- gnome-doc-utils
- libatspi-dev
- libgconf2-dev
- libgtk2.0-dev
- libxtst-dev"
+ gnome-common
+ gnome-doc-utils
+ libatspi2.0-dev
+ libgtk-3-dev"
sudo apt-get install $packages
Then autogen:
@@ -35,14 +33,16 @@ following configure-time options are specific to Dasher (see section
Options
=======
- --without-gnome Disable features which require the GNOME core
- libraries (enabled by default).
+ --disable-speech Disable speech support (speech dispatcher and
+ GNOME speech).
- --with-speech Enable GNOME-Speech support (disabled by default).
+ --disable-a11y Disable support for GNOME 2 accessibility features
+ (enabled by default).
- --disable-a11y Disable support for GNOME accessibility features
- (enabled by default). You should probably specify
- this as well if you're using --without-gnome.
+ --disable-atspi Disable support for GNOME 3 accessibility features
+ (enabled by default). This flag is just useful
+ for debugging, as accessibility is now built-in
+ and doesn't bring in more dependencies.
The following options include code which is significantly out of
date and currently untested. It is likely that these options will not
diff --git a/Src/Gtk2/Makefile.am b/Src/Gtk2/Makefile.am
index 69aa1c3..626b034 100644
--- a/Src/Gtk2/Makefile.am
+++ b/Src/Gtk2/Makefile.am
@@ -82,6 +82,13 @@ libdashergtk_la_SOURCES = \
module_settings_window.cpp \
module_settings_window.h
+if USE_ATSPI
+libdashergtk_la_SOURCES += \
+ dasher_editor_external_atspi.cpp
+libdashergtk_la_CPPFLAGS = @ATSPI_CFLAGS@
+libdashergtk_la_LDFLAGS = @ATSPI_LIBS@
+libdashergtk_la_LIBADD = @ATSPI_LIBS@
+else
if USE_CSPI
libdashergtk_la_SOURCES += \
dasher_editor_external_cspi.cpp
@@ -92,5 +99,6 @@ else
libdashergtk_la_SOURCES += \
dasher_editor_external_xtest.cpp
endif
+endif
AM_CXXFLAGS = -I$(srcdir)/../DasherCore -DPROGDATA=\"$(pkgdatadir)\" $(GTKBUILD_CFLAGS)
diff --git a/Src/Gtk2/dasher_editor_external.h b/Src/Gtk2/dasher_editor_external.h
index 690dba6..719faf8 100644
--- a/Src/Gtk2/dasher_editor_external.h
+++ b/Src/Gtk2/dasher_editor_external.h
@@ -1,16 +1,13 @@
#ifndef DASHER_EDITOR_EXTERNAL_H
#define DASHER_EDITOR_EXTERNAL_H
-typedef struct _DasherEditor DasherEditor;
-struct _DasherEditor;
-typedef struct _GObject GObject;
-struct _GObject;
+#include "dasher_editor.h"
void dasher_editor_external_finalize(GObject*);
void dasher_editor_external_create_buffer(DasherEditor*); // for dasher_editor_external_initialise, and calls focus bits
-void dasher_editor_external_output(DasherEditor *pSelf, const gchar *szText, int iOffset);
+void dasher_editor_external_output(DasherEditor *pSelf, const char *szText, int iOffset);
void dasher_editor_external_delete(DasherEditor *pSelf, int iLength, int iOffset);
-const gchar * dasher_editor_external_get_context(DasherEditor *pSelf, int iOffset, int iLength);
-gint dasher_editor_external_get_offset(DasherEditor *pSelf);
+const char * dasher_editor_external_get_context(DasherEditor *pSelf, int iOffset, int iLength);
+int dasher_editor_external_get_offset(DasherEditor *pSelf);
#endif
diff --git a/Src/Gtk2/dasher_editor_external_atspi.cpp b/Src/Gtk2/dasher_editor_external_atspi.cpp
new file mode 100644
index 0000000..fbdd15b
--- /dev/null
+++ b/Src/Gtk2/dasher_editor_external_atspi.cpp
@@ -0,0 +1,242 @@
+#include <X11/keysym.h>
+
+#include <atspi/atspi.h>
+
+#include "dasher_editor_external.h"
+#include "dasher_editor_private.h"
+
+typedef struct _DasherEditorExternalPrivate DasherEditorExternalPrivate;
+
+struct _DasherEditorExternalPrivate {
+ AtspiEventListener *pFocusListener;
+ AtspiEventListener *pCaretListener;
+ AtspiText *pAccessibleText;
+};
+
+void dasher_editor_external_handle_focus(DasherEditor *pSelf, const AtspiEvent *pEvent);
+void dasher_editor_external_handle_caret(DasherEditor *pSelf, const AtspiEvent *pEvent);
+
+void focus_listener(const AtspiEvent *pEvent, void *pUserData);
+void caret_listener(const AtspiEvent *pEvent, void *pUserData);
+
+bool
+initSPI() {
+#ifdef DEBUG_ATSPI
+ int ret = atspi_init();
+ printf("atspi_init() returned %d\n", ret);
+ return (ret <= 1);
+#else
+ return (atspi_init() <= 1);
+#endif
+}
+
+void
+dasher_editor_external_finalize(GObject *pSelf) {
+ DasherEditorPrivate *pPrivate = DASHER_EDITOR_GET_PRIVATE(pSelf);
+ DasherEditorExternalPrivate *p = pPrivate->pExtPrivate;
+
+#ifdef DEBUG_ATSPI
+ printf("dasher_editor_external_finalize()\n");
+#endif
+
+ atspi_event_listener_deregister(p->pFocusListener, "focus:", NULL);
+ atspi_event_listener_deregister(p->pCaretListener, "object:text-caret-moved", NULL);
+
+ g_object_unref(p->pFocusListener);
+ g_object_unref(p->pCaretListener);
+
+ delete p;
+}
+
+void
+dasher_editor_external_create_buffer(DasherEditor *pSelf) {
+ DasherEditorPrivate *pPrivate = DASHER_EDITOR_GET_PRIVATE(pSelf);
+ DasherEditorExternalPrivate *p;
+
+#ifdef DEBUG_ATSPI
+ printf("dasher_editor_external_create_buffer()\n");
+#endif
+
+ if(!initSPI()) {
+ g_message("Could not initialise SPI - accessibility options disabled");
+ return;
+ }
+ p = new DasherEditorExternalPrivate;
+ p->pFocusListener = atspi_event_listener_new(focus_listener, pSelf, NULL);
+ p->pCaretListener = atspi_event_listener_new(caret_listener, pSelf, NULL);
+ p->pAccessibleText = NULL;
+ pPrivate->pExtPrivate = p;
+
+#ifdef DEBUG_ATSPI
+ printf("dasher_editor_external_create_buffer: pPrivate=%p, pExtPrivate=%p\n", pPrivate, p);
+#endif
+
+ atspi_event_listener_register(p->pFocusListener, "focus:", NULL);
+ atspi_event_listener_register(p->pCaretListener, "object:text-caret-moved", NULL);
+}
+
+void
+dasher_editor_external_output(DasherEditor *pSelf, const char *szText, int iOffset /* unused */) {
+ if (!initSPI()) return;
+
+ atspi_generate_keyboard_event(0, szText, ATSPI_KEY_STRING, NULL);
+}
+
+void
+dasher_editor_external_delete(DasherEditor *pSelf, int iLength, int iOffset) {
+ if (!initSPI()) return;
+
+ atspi_generate_keyboard_event(XK_BackSpace, NULL, ATSPI_KEY_SYM, NULL);
+}
+
+const char *
+dasher_editor_external_get_context(DasherEditor *pSelf, int iOffset, int iLength) {
+ DasherEditorPrivate *pPrivate = DASHER_EDITOR_GET_PRIVATE(pSelf);
+
+#ifdef DEBUG_ATSPI
+ printf("dasher_editor_external_get_context(pPrivate=%p)\n", pPrivate);
+#endif
+
+ DASHER_ASSERT(pPrivate->pExtPrivate != NULL);
+ AtspiText *textobj = pPrivate->pExtPrivate->pAccessibleText;
+
+ if (textobj)
+ return atspi_text_get_text(textobj, iOffset, iOffset + iLength, NULL);
+ else
+ return "";
+}
+
+int
+dasher_editor_external_get_offset(DasherEditor *pSelf) {
+ DasherEditorPrivate *pPrivate = DASHER_EDITOR_GET_PRIVATE(pSelf);
+
+#ifdef DEBUG_ATSPI
+ printf("dasher_editor_external_get_offset()\n");
+#endif
+
+ DASHER_ASSERT(pPrivate->pExtPrivate != NULL);
+ AtspiText *textobj = pPrivate->pExtPrivate->pAccessibleText;
+ AtspiRange *range;
+ int ret;
+
+ if (!textobj) {
+#ifdef DEBUG_ATSPI
+ printf("no textobj\n");
+#endif
+ return 0;
+ }
+
+ if (atspi_text_get_n_selections(textobj, NULL) == 0)
+ return atspi_text_get_caret_offset(textobj, NULL);
+
+ range = atspi_text_get_selection(textobj, 0, NULL);
+ ret = std::min(range->start_offset, range->end_offset);
+ g_free(range);
+
+ return ret;
+}
+
+void
+dasher_editor_external_handle_focus(DasherEditor *pSelf, const AtspiEvent *pEvent) {
+ DasherEditorPrivate *pPrivate = DASHER_EDITOR_GET_PRIVATE(pSelf);
+
+#ifdef DEBUG_ATSPI
+ printf("dasher_editor_external_handle_focus()\n");
+#endif
+
+ DASHER_ASSERT(pPrivate->pExtPrivate != NULL);
+ AtspiText *textobj = pPrivate->pExtPrivate->pAccessibleText;
+
+ if (textobj) {
+ g_object_unref(textobj);
+ textobj = NULL;
+ }
+
+ AtspiAccessible *acc = pEvent->source;
+ g_object_ref(acc);
+
+#ifdef DEBUG_ATSPI
+ printf("%s from %s, %s, %s\n",
+ pEvent->type,
+ atspi_accessible_get_name(acc, NULL),
+ atspi_accessible_get_role_name(acc, NULL),
+ atspi_accessible_get_description(acc, NULL));
+#endif
+
+ textobj = atspi_accessible_get_text(acc);
+ pPrivate->pExtPrivate->pAccessibleText = textobj;
+ if (textobj) {
+ g_object_ref(textobj);
+
+ //ACL: in old code, external_buffer emitted signal, for which the editor_external had
+ // registered a callback, which then emitted the same/corresponding signal from the
+ // editor_external; so by combining buffer into editor, seems we don't need any of that
+ // and can just emit the signal from the editor directly. However, the callback also said:
+ //TODO: plumb signal back into control
+ // ...if that makes any sense?
+
+ g_signal_emit_by_name(G_OBJECT(pSelf), "buffer_changed", G_OBJECT(pSelf), NULL, NULL);
+ }
+
+ g_object_unref(acc);
+}
+
+void
+dasher_editor_external_handle_caret(DasherEditor *pSelf, const AtspiEvent *pEvent) {
+ DasherEditorPrivate *pPrivate = DASHER_EDITOR_GET_PRIVATE(pSelf);
+
+#ifdef DEBUG_ATSPI
+ printf("dasher_editor_external_handle_caret()\n");
+#endif
+
+ DASHER_ASSERT(pPrivate->pExtPrivate != NULL);
+ AtspiText *textobj = pPrivate->pExtPrivate->pAccessibleText;
+
+ if (textobj) {
+ g_object_unref(textobj);
+ textobj = NULL;
+ }
+
+ AtspiAccessible *acc = pEvent->source;
+ g_object_ref(acc);
+
+#ifdef DEBUG_ATSPI
+ printf("%s from %s, %s, %s\n",
+ pEvent->type,
+ atspi_accessible_get_name(acc, NULL),
+ atspi_accessible_get_role_name(acc, NULL),
+ atspi_accessible_get_description(acc, NULL));
+#endif
+
+ textobj = atspi_accessible_get_text(acc);
+ pPrivate->pExtPrivate->pAccessibleText = textobj;
+ if (textobj) {
+ g_object_ref(textobj);
+
+ //ACL: in old code, external_buffer emitted signal, for which the editor_external had
+ // registered a callback, which then emitted the same/corresponding signal from the
+ // editor_external; so by combining buffer into editor, seems we don't need any of that
+ // and can just emit the signal from the editor directly. However, the callback also said:
+ //TODO: plumb signal back into control
+ // ...if that makes any sense?
+
+ g_signal_emit_by_name(G_OBJECT(pSelf), "context_changed", G_OBJECT(pSelf), NULL, NULL);
+ }
+#ifdef DEBUG_ATSPI
+ else {
+ printf("XXX Received text-caret-moved from source which doesn't implemenent AtspiText\n");
+ }
+#endif
+
+ g_object_unref(acc);
+}
+
+void
+focus_listener(const AtspiEvent *pEvent, void *pUserData) {
+ dasher_editor_external_handle_focus(DASHER_EDITOR(pUserData), pEvent);
+}
+
+void
+caret_listener(const AtspiEvent *pEvent, void *pUserData) {
+ dasher_editor_external_handle_caret(DASHER_EDITOR(pUserData), pEvent);
+}
diff --git a/Src/Gtk2/dasher_editor_external_cspi.cpp b/Src/Gtk2/dasher_editor_external_cspi.cpp
index 96554a4..6074c98 100644
--- a/Src/Gtk2/dasher_editor_external_cspi.cpp
+++ b/Src/Gtk2/dasher_editor_external_cspi.cpp
@@ -61,8 +61,7 @@ dasher_editor_external_create_buffer(DasherEditor *pSelf) {
pPrivate->pExtPrivate = new DasherEditorExternalPrivate;
pPrivate->pExtPrivate->pFocusListener = SPI_createAccessibleEventListener(focus_listener, pSelf);
pPrivate->pExtPrivate->pCaretListener = SPI_createAccessibleEventListener(caret_listener, pSelf);
-
- // TODO: Need to deregister these on destruction
+ pPrivate->pExtPrivate->pAccessibleText = NULL;
if(pPrivate->pExtPrivate->pFocusListener && pPrivate->pExtPrivate->pCaretListener) {
SPI_registerGlobalEventListener(pPrivate->pExtPrivate->pFocusListener, "focus:");
@@ -71,8 +70,6 @@ dasher_editor_external_create_buffer(DasherEditor *pSelf) {
g_message("Could not obtain an SPI listener");
}
}
-
- pPrivate->pExtPrivate->pAccessibleText = 0;
}
void
@@ -125,7 +122,7 @@ void dasher_editor_external_handle_focus(DasherEditor *pSelf, const AccessibleEv
if(pPrivate->pExtPrivate->pAccessibleText) {
AccessibleText_unref(pPrivate->pExtPrivate->pAccessibleText);
- pPrivate->pExtPrivate->pAccessibleText = 0;
+ pPrivate->pExtPrivate->pAccessibleText = NULL;
}
Accessible *accessible = pEvent->source;
@@ -164,7 +161,7 @@ void dasher_editor_external_handle_caret(DasherEditor *pSelf, const AccessibleEv
if(pPrivate->pExtPrivate->pAccessibleText) {
AccessibleText_unref(pPrivate->pExtPrivate->pAccessibleText);
- pPrivate->pExtPrivate->pAccessibleText = 0;
+ pPrivate->pExtPrivate->pAccessibleText = NULL;
}
Accessible *accessible = pEvent->source;
diff --git a/Src/Gtk2/dasher_editor_private.h b/Src/Gtk2/dasher_editor_private.h
index 1a1f424..9125940 100644
--- a/Src/Gtk2/dasher_editor_private.h
+++ b/Src/Gtk2/dasher_editor_private.h
@@ -1,6 +1,8 @@
#ifndef DASHER_EDITOR_PRIVATE_H
#define DASHER_EDITOR_PRIVATE_H
+#include <gtk/gtk.h>
+
// Forward declarations
typedef struct _DasherAppSettings DasherAppSettings;
struct _DasherAppSettings;
diff --git a/Src/Makefile.am b/Src/Makefile.am
index 9d7df91..d4835f9 100644
--- a/Src/Makefile.am
+++ b/Src/Makefile.am
@@ -22,6 +22,9 @@ AM_CXXFLAGS = \
-DPROGDATA=\"$(pkgdatadir)\" \
-DSYSCONFDIR=\"$(sysconfdir)\" \
-DPACKAGE_LOCALE_DIR=\"$(datadir)/locale\"
+if USE_CSPI
+AM_CXXFLAGS += @CSPI_CFLAGS@
+endif
dasher_LDADD = \
Common/libdashermisc.a \
diff --git a/Src/main.cc b/Src/main.cc
index 62e88d6..f53c0ae 100644
--- a/Src/main.cc
+++ b/Src/main.cc
@@ -18,7 +18,7 @@
#endif
// TODO: This shouldn't need to be here
-#if (defined GNOME_SPEECH || defined USE_CSPI)
+#if defined(GNOME_SPEECH) || defined(USE_CSPI)
#include <libbonobo.h>
#endif
@@ -201,7 +201,7 @@ int main(int argc, char *argv[]) {
osso_context = osso_initialize("dasher", PACKAGE_VERSION, TRUE, NULL);
#endif
-#if (defined GNOME_SPEECH || defined USE_CSPI)
+#if defined(GNOME_SPEECH) || defined(USE_CSPI)
if(!bonobo_is_initialized()) {
if(!bonobo_init(&argc, argv)) {
g_error("Can't initialize Bonobo...\n");
diff --git a/configure.ac b/configure.ac
index 56b8c87..59d6dc2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -98,7 +98,10 @@ AC_ARG_WITH([gpe],
AC_ARG_ENABLE([a11y],
[AS_HELP_STRING([--enable-a11y],
- [use cspi rather than Xtst for direct entry mode if found])])
+ [with Gtk2 use cspi rather than Xtst for direct entry mode if found (default is YES)])])
+AC_ARG_ENABLE([atspi],
+ [AS_HELP_STRING([--enable-atspi],
+ [with Gtk3 use atspi rather than Xtst for direct entry mode if found (default is YES)])])
AC_ARG_ENABLE([japanese],
AS_HELP_STRING([--enable-japanese],[build with support for Japanese Kanji entry (experimental -- default is NO)]),
@@ -323,10 +326,15 @@ AC_CHECK_LIB(expat, XML_Parse,,[
fi
])
+PKG_CHECK_MODULES([ATSPI],
+ [atspi-2],
+ [have_libatspi=yes],
+ [have_libatspi=no])
+
PKG_CHECK_MODULES([CSPI],
[bonobo-activation-2.0 libbonobo-2.0 ORBit-2.0 cspi-1.0 atk],
- [have_libcspi=yes],
- [have_libcspi=no])
+ [have_libcspi=yes],
+ [have_libcspi=no])
AS_IF( [test x$no_x = xyes],
[AC_MSG_WARN([X development libraries not found])],
@@ -337,7 +345,11 @@ AC_CHECK_LIB([Xtst], [XTestFakeKeyEvent],
[have_libxtst=no],
[$X_LIBS])
-AS_IF( [test $have_libcspi = yes -a x$enable_a11y != xno],
+AS_IF( [test $have_libatspi = yes -a x$enable_atspi != xno],
+ [connect_using=libatspi],
+ [test $have_libatspi = no -a x$enable_atspi = xyes],
+ [AC_MSG_ERROR([atspi 2 requested but not found])],
+ [test $have_libcspi = yes -a x$enable_a11y != xno],
[connect_using=libcspi
AC_DEFINE([USE_CSPI], 1, [Use the libcspi for direct mode])],
[test $have_libcspi = no -a x$enable_a11y = xyes],
@@ -347,7 +359,8 @@ AS_IF( [test $have_libcspi = yes -a x$enable_a11y != xno],
X_LIBS="$X_LIBS -lXtst"],
[AC_MSG_ERROR([No method to send characters into another application found])])
-AM_CONDITIONAL(USE_CSPI, test $connect_using = libcspi)
+AM_CONDITIONAL(USE_CSPI, test $connect_using = libcspi)
+AM_CONDITIONAL(USE_ATSPI, test $connect_using = libatspi)
if test x"$WITHJAPANESE" = xtrue; then
AC_DEFINE([JAPANESE], 1, [Japanese support enabled])
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]