File: git-atspi2-init

package info (click to toggle)
brltty 5.6-10
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 25,116 kB
  • sloc: ansic: 117,871; sh: 6,590; java: 4,785; xml: 3,451; makefile: 1,973; tcl: 1,499; awk: 611; ml: 293; python: 250; lisp: 52
file content (114 lines) | stat: -rw-r--r-- 4,527 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
commit 6afc25d4c15a37c5adaadc3c9296dbe82fc0e106
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
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 */