summaryrefslogtreecommitdiffstats
path: root/config/chroot_local-patches/python-dogtail_searchShowingOnly.diff
blob: a5793410dc56e154bbb4886475cd17fd24326e4d (plain)
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
Author: anonym <anonym@riseup.net>
Date:   Mon Apr 4 18:04:52 2016 +0200

    Add support for only searching among 'showing' nodes.
    
    Here 'showing' refers to pyatspi.STATE_SHOWING, i.e. whether a node is
    shown to the end-user or not. Quite often we are only interested in
    such nodes, at least when dogtail is used to interact with an
    application (e.g. clicking something that isn't there won't
    work). Most importantly, this greatly simplifies situations where the
    'shown' element we are looking for is hard to exactly pinpoint since
    it lacks properties to distinguish it from some not 'shown' element.
    
    Therefore we add a `showingOnly` boolean flag to all search methods
    where it makes sense (e.g. it doesn't make sense for Application:s
    since they seem to always be considered not 'showing'). The default
    will be to not do this, for backwards-compatibility, but the default
    is configurable via a new `searchShowingOnly` config option.

--- a/usr/share/pyshared/dogtail/config.py
+++ b/usr/share/pyshared/dogtail/config.py
@@ -58,6 +58,9 @@ class _Config(object):
     searchCutoffCount (int):
     Number of times to retry when a search fails.
 
+    searchShowingOnly (boolean):
+    Whether to only search among nodes that are currently being shown.
+
     defaultDelay (float):
     Default time in seconds to sleep when delaying.
 
@@ -134,6 +137,7 @@ class _Config(object):
         'searchBackoffDuration': 0.5,
         'searchWarningThreshold': 3,
         'searchCutoffCount': 20,
+        'searchShowingOnly': False,
         'defaultDelay': 0.5,
         'childrenLimit': 100,
 
--- a/usr/share/pyshared/dogtail/tree.py
+++ b/usr/share/pyshared/dogtail/tree.py
@@ -819,12 +819,18 @@ class Node(object):
         else:
             return False
 
-    def _fastFindChild(self, pred, recursive=True):
+    def _fastFindChild(self, pred, recursive=True, showingOnly=None):
         """
         Searches for an Accessible using methods from pyatspi.utils
         """
         if isinstance(pred, predicate.Predicate):
             pred = pred.satisfiedByNode
+        if showingOnly == None:
+            showingOnly = config.searchShowingOnly
+        if showingOnly:
+            orig_pred = pred
+            pred = lambda n: orig_pred(n) and \
+                             n.getState().contains(pyatspi.STATE_SHOWING)
         if not recursive:
             cIter = iter(self)
             while True:
@@ -839,7 +845,7 @@ class Node(object):
             return pyatspi.utils.findDescendant(self, pred)
 
     def findChild(self, pred, recursive=True, debugName=None,
-                  retry=True, requireResult=True):
+                  retry=True, requireResult=True, showingOnly=None):
         """
         Search for a node satisyfing the predicate, returning a Node.
 
@@ -871,7 +877,7 @@ class Node(object):
                 logger.log("searching for %s (attempt %i)" %
                            (describeSearch(self, pred, recursive, debugName), numAttempts))
 
-            result = self._fastFindChild(pred.satisfiedByNode, recursive)
+            result = self._fastFindChild(pred.satisfiedByNode, recursive, showingOnly=showingOnly)
             if result:
                 assert isinstance(result, Node)
                 if debugName:
@@ -891,12 +897,12 @@ class Node(object):
             raise SearchError(describeSearch(self, pred, recursive, debugName))
 
     # The canonical "search for multiple" method:
-    def findChildren(self, pred, recursive=True, isLambda=False):
+    def findChildren(self, pred, recursive=True, isLambda=False, showingOnly=None):
         """
         Find all children/descendents satisfying the predicate.
         """
         if isLambda is True:
-            nodes = self.findChildren(predicate.GenericPredicate(), recursive=recursive)
+            nodes = self.findChildren(predicate.GenericPredicate(), recursive=recursive, showingOnly=showingOnly)
             result = []
             for node in nodes:
                 try:
@@ -907,6 +913,12 @@ class Node(object):
             return result
         if isinstance(pred, predicate.Predicate):
             pred = pred.satisfiedByNode
+        if showingOnly == None:
+            showingOnly = config.searchShowingOnly
+        if showingOnly:
+            orig_pred = pred
+            pred = lambda n: orig_pred(n) and \
+                             n.getState().contains(pyatspi.STATE_SHOWING)
         if not recursive:
             cIter = iter(self)
             result = []
@@ -929,7 +941,7 @@ class Node(object):
             return descendants
 
     # The canonical "search above this node" method:
-    def findAncestor(self, pred):
+    def findAncestor(self, pred, showingOnly=None):
         """
         Search up the ancestry of this node, returning the first Node
         satisfying the predicate, or None.
@@ -945,7 +957,7 @@ class Node(object):
         return None
 
     # Various wrapper/helper search methods:
-    def child(self, name='', roleName='', description='', label='', recursive=True, retry=True, debugName=None):
+    def child(self, name='', roleName='', description='', label='', recursive=True, retry=True, debugName=None, showingOnly=None):
         """
         Finds a child satisying the given criteria.
 
@@ -953,9 +965,9 @@ class Node(object):
         if no such child is found, and will eventually raise an exception. It
         also logs the search.
         """
-        return self.findChild(predicate.GenericPredicate(name=name, roleName=roleName, description=description, label=label), recursive=recursive, retry=retry, debugName=debugName)
+        return self.findChild(predicate.GenericPredicate(name=name, roleName=roleName, description=description, label=label), recursive=recursive, retry=retry, debugName=debugName, showingOnly=showingOnly)
 
-    def isChild(self, name='', roleName='', description='', label='', recursive=True, retry=False, debugName=None):
+    def isChild(self, name='', roleName='', description='', label='', recursive=True, retry=False, debugName=None, showingOnly=None):
         """
         Determines whether a child satisying the given criteria exists.
 
@@ -970,12 +982,12 @@ class Node(object):
             self.findChild(
                 predicate.GenericPredicate(
                     name=name, roleName=roleName, description=description, label=label),
-                recursive=recursive, retry=retry, debugName=debugName)
+                recursive=recursive, retry=retry, debugName=debugName, showingOnly=showingOnly)
         except SearchError:
             found = False
         return found
 
-    def menu(self, menuName, recursive=True):
+    def menu(self, menuName, recursive=True, showingOnly=None):
         """
         Search below this node for a menu with the given name.
 
@@ -983,9 +995,9 @@ class Node(object):
         if no such child is found, and will eventually raise an exception. It
         also logs the search.
         """
-        return self.findChild(predicate.IsAMenuNamed(menuName=menuName), recursive)
+        return self.findChild(predicate.IsAMenuNamed(menuName=menuName), recursive, showingOnly=showingOnly)
 
-    def menuItem(self, menuItemName, recursive=True):
+    def menuItem(self, menuItemName, recursive=True, showingOnly=None):
         """
         Search below this node for a menu item with the given name.
 
@@ -993,9 +1005,9 @@ class Node(object):
         if no such child is found, and will eventually raise an exception. It
         also logs the search.
         """
-        return self.findChild(predicate.IsAMenuItemNamed(menuItemName=menuItemName), recursive)
+        return self.findChild(predicate.IsAMenuItemNamed(menuItemName=menuItemName), recursive, showingOnly=showingOnly)
 
-    def textentry(self, textEntryName, recursive=True):
+    def textentry(self, textEntryName, recursive=True, showingOnly=None):
         """
         Search below this node for a text entry with the given name.
 
@@ -1003,9 +1015,9 @@ class Node(object):
         if no such child is found, and will eventually raise an exception. It
         also logs the search.
         """
-        return self.findChild(predicate.IsATextEntryNamed(textEntryName=textEntryName), recursive)
+        return self.findChild(predicate.IsATextEntryNamed(textEntryName=textEntryName), recursive, showingOnly=showingOnly)
 
-    def button(self, buttonName, recursive=True):
+    def button(self, buttonName, recursive=True, showingOnly=None):
         """
         Search below this node for a button with the given name.
 
@@ -1013,9 +1025,9 @@ class Node(object):
         if no such child is found, and will eventually raise an exception. It
         also logs the search.
         """
-        return self.findChild(predicate.IsAButtonNamed(buttonName=buttonName), recursive)
+        return self.findChild(predicate.IsAButtonNamed(buttonName=buttonName), recursive, showingOnly=showingOnly)
 
-    def childLabelled(self, labelText, recursive=True):
+    def childLabelled(self, labelText, recursive=True, showingOnly=None):
         """
         Search below this node for a child labelled with the given text.
 
@@ -1023,9 +1035,9 @@ class Node(object):
         if no such child is found, and will eventually raise an exception. It
         also logs the search.
         """
-        return self.findChild(predicate.IsLabelledAs(labelText), recursive)
+        return self.findChild(predicate.IsLabelledAs(labelText), recursive, showingOnly=showingOnly)
 
-    def childNamed(self, childName, recursive=True):
+    def childNamed(self, childName, recursive=True, showingOnly=None):
         """
         Search below this node for a child with the given name.
 
@@ -1033,9 +1045,9 @@ class Node(object):
         if no such child is found, and will eventually raise an exception. It
         also logs the search.
         """
-        return self.findChild(predicate.IsNamed(childName), recursive)
+        return self.findChild(predicate.IsNamed(childName), recursive, showingOnly=showingOnly)
 
-    def tab(self, tabName, recursive=True):
+    def tab(self, tabName, recursive=True, showingOnly=None):
         """
         Search below this node for a tab with the given name.
 
@@ -1043,7 +1055,7 @@ class Node(object):
         if no such child is found, and will eventually raise an exception. It
         also logs the search.
         """
-        return self.findChild(predicate.IsATabNamed(tabName=tabName), recursive)
+        return self.findChild(predicate.IsATabNamed(tabName=tabName), recursive, showingOnly=showingOnly)
 
     def getUserVisibleStrings(self):
         """
@@ -1109,7 +1121,7 @@ class Root (Node):
         Get all applications.
         """
         return root.findChildren(predicate.GenericPredicate(
-            roleName="application"), recursive=False)
+            roleName="application"), recursive=False, showingOnly=False)
 
     def application(self, appName, retry=True):
         """
@@ -1120,12 +1132,12 @@ class Root (Node):
         if no such child is found, and will eventually raise an exception. It
         also logs the search.
         """
-        return root.findChild(predicate.IsAnApplicationNamed(appName), recursive=False, retry=retry)
+        return root.findChild(predicate.IsAnApplicationNamed(appName), recursive=False, retry=retry, showingOnly=False)
 
 
 class Application (Node):
 
-    def dialog(self, dialogName, recursive=False):
+    def dialog(self, dialogName, recursive=False, showingOnly=None):
         """
         Search below this node for a dialog with the given name,
         returning a Window instance.
@@ -1136,9 +1148,9 @@ class Application (Node):
 
         FIXME: should this method activate the dialog?
         """
-        return self.findChild(predicate.IsADialogNamed(dialogName=dialogName), recursive)
+        return self.findChild(predicate.IsADialogNamed(dialogName=dialogName), recursive, showingOnly=showingOnly)
 
-    def window(self, windowName, recursive=False):
+    def window(self, windowName, recursive=False, showingOnly=None):
         """
         Search below this node for a window with the given name,
         returning a Window instance.
@@ -1152,13 +1164,13 @@ class Application (Node):
         by the window manager) if wnck bindings are available.
         """
         result = self.findChild(
-            predicate.IsAWindowNamed(windowName=windowName), recursive)
+            predicate.IsAWindowNamed(windowName=windowName), recursive, showingOnly=showingOnly)
         # FIXME: activate the WnckWindow ?
         # if gotWnck:
         #       result.activate()
         return result
 
-    def getWnckApplication(self):  # pragma: no cover
+    def getWnckApplication(self, showingOnly=None):  # pragma: no cover
         """
         Get the wnck.Application instance for this application, or None
 
@@ -1169,7 +1181,7 @@ class Application (Node):
 
         FIXME: untested
         """
-        window = self.child(roleName='frame')
+        window = self.child(roleName='frame', showingOnly=showingOnly)
         if window:
             wnckWindow = window.getWnckWindow()
             return wnckWindow.get_application()