From 0e8f4ce7cf2f17e26880da3096a0fd56e310640e Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Fri, 6 Apr 2018 13:16:01 +0200 Subject: [PATCH] Cherry-pick at-spi2 initialization fix --- debian/changelog | 1 + debian/patches/git-atspi2-init | 114 +++++++++++++++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 116 insertions(+) create mode 100644 debian/patches/git-atspi2-init diff --git a/debian/changelog b/debian/changelog index 98a77169..572ba981 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ brltty (5.6-4) UNRELEASED; urgency=medium * Cherry-pick python brlapi close fix, to avoid orca accumulating brlapi connections. + * Cherry-pick at-spi2 initialization fix. -- Samuel Thibault Tue, 03 Apr 2018 17:38:28 +0200 diff --git a/debian/patches/git-atspi2-init b/debian/patches/git-atspi2-init new file mode 100644 index 00000000..a368f009 --- /dev/null +++ b/debian/patches/git-atspi2-init @@ -0,0 +1,114 @@ +commit 6afc25d4c15a37c5adaadc3c9296dbe82fc0e106 +Author: Samuel Thibault +Date: Fri Apr 6 11:22:58 2018 +0200 + + atspi2: Fix looking for currently active widget + + The current code was actually not working at all because the initial + sender is SPI2_DBUS_INTERFACE_REG with path SPI2_DBUS_PATH_ROOT, and its + children are applications with SPI2_DBUS_PATH_ROOT too, so when deciding + to recurse, we need to check for both the path and the sender, not only + the path, which may be the same for two sender and make use believe than + we have a loop right from the beginning between SPI2_DBUS_INTERFACE_REG + and applications. + + It is however noticeable that some applications do not actually always + expose their widgets as tree, but sometimes as a clique! We thus need to + take care not only of direct loops, but also loops to further ancestors, + and just stop recursing completely in that case, to avoid an exponential + number of lookups. + +diff --git a/Drivers/Screen/AtSpi2/screen.c b/Drivers/Screen/AtSpi2/screen.c +index c550b9d58..e9d770057 100644 +--- a/Drivers/Screen/AtSpi2/screen.c ++++ b/Drivers/Screen/AtSpi2/screen.c +@@ -693,8 +693,17 @@ static int reinitTerm(const char *sender, const char *path) { + } + + /* Try to find an active object among children of the given object */ +-static int findTerm(const char *sender, const char *path, int active, int depth); +-static int recurseFindTerm(const char *sender, const char *path, int active, int depth) { ++ ++/* We need to take care of bogus applications which have children loops, so we ++ * need to compare newly found children with the list of ancestors */ ++struct pathList { ++ const char *sender; ++ const char *path; ++ struct pathList *prev; ++ int loop; ++}; ++static int findTerm(const char *sender, const char *path, int active, int depth, struct pathList *list); ++static int recurseFindTerm(const char *sender, const char *path, int active, int depth, struct pathList *list) { + DBusMessage *msg, *reply; + DBusMessageIter iter, iter_array, iter_struct; + int res = 0; +@@ -717,19 +726,42 @@ static int recurseFindTerm(const char *sender, const char *path, int active, int + while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) + { + const char *childsender, *childpath; ++ struct pathList *cur; ++ + dbus_message_iter_recurse (&iter_array, &iter_struct); + dbus_message_iter_get_basic (&iter_struct, &childsender); + dbus_message_iter_next (&iter_struct); + dbus_message_iter_get_basic (&iter_struct, &childpath); +- /* Make sure that the child is not the same as the parent, to avoid recursing indefinitely. */ +- if (strcmp(path, childpath)) ++ ++ /* Make sure that the child is not the same as an ancestor, to avoid ++ * recursing indefinitely. */ ++ for (cur = list; cur; cur = cur->prev) ++ if (!strcmp(childsender, cur->sender) && !strcmp(childpath, cur->path)) ++ { ++ /* Loop detected, avoid continuing looking at this part of the tree ++ which is not actually a tree! */ ++ cur->loop = 1; ++ break; ++ } ++ if (! cur) + { +- if (findTerm(childsender, childpath, active, depth)) ++ struct pathList me = { ++ .sender = sender, ++ .path = path, ++ .prev = list, ++ }; ++ if (findTerm(childsender, childpath, active, depth, &me)) + { + res = 1; + goto out; + } ++ if (me.loop) { ++ /* There is a loop up to us. Avoid continuing looking here which may ++ * entail an exponential number of lookups. */ ++ break; ++ } + } ++ + dbus_message_iter_next (&iter_array); + } + +@@ -739,7 +771,7 @@ out: + } + + /* Test whether this object is active, and if not recurse in its children */ +-static int findTerm(const char *sender, const char *path, int active, int depth) { ++static int findTerm(const char *sender, const char *path, int active, int depth, struct pathList *list) { + dbus_uint32_t *states = getState(sender, path); + + if (!states) +@@ -760,12 +792,12 @@ static int findTerm(const char *sender, const char *path, int active, int depth) + } + + free(states); +- return recurseFindTerm(sender, path, active, depth+1); ++ return recurseFindTerm(sender, path, active, depth+1, list); + } + + /* Find out currently focused terminal, starting from registry */ + static void initTerm(void) { +- recurseFindTerm(SPI2_DBUS_INTERFACE_REG, SPI2_DBUS_PATH_ROOT, 0, 0); ++ recurseFindTerm(SPI2_DBUS_INTERFACE_REG, SPI2_DBUS_PATH_ROOT, 0, 0, NULL); + } + + /* Handle incoming events */ diff --git a/debian/patches/series b/debian/patches/series index 4a29f06f..b0e40ff7 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -4,3 +4,4 @@ 50-constants.patch disable-synth-callback.patch git-pythonclose +git-atspi2-init -- GitLab