summaryrefslogtreecommitdiffstats
path: root/config/chroot_local-patches/python-dogtail_searchShowingOnly.diff
blob: 6d21d41703c8418d6e2d89e1cf79ea3c79107114 (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
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/lib/python2.7/dist-packages/dogtail/config.py
+++ b/usr/lib/python2.7/dist-packages/dogtail/config.py
@@ -60,6 +60,9 @@
     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.
 
@@ -136,6 +139,7 @@
         'searchBackoffDuration': 0.5,
         'searchWarningThreshold': 3,
         'searchCutoffCount': 20,
+        'searchShowingOnly': False,
         'defaultDelay': 0.5,
         'childrenLimit': 100,
 
--- a/usr/lib/python2.7/dist-packages/dogtail/tree.py
+++ b/usr/lib/python2.7/dist-packages/dogtail/tree.py
@@ -855,12 +855,18 @@
         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:
@@ -873,7 +879,7 @@
         else:
             return pyatspi.utils.findDescendant(self, pred)
 
-    def findChild(self, pred, recursive=True, debugName=None, retry=True, requireResult=True):
+    def findChild(self, pred, recursive=True, debugName=None, retry=True, requireResult=True, showingOnly=None):
         """
         Search for a node satisyfing the predicate, returning a Node.
 
@@ -905,7 +911,7 @@
                 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:
@@ -924,7 +930,7 @@
             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.
         You can also use lambdas in place of pred that will enable search also against
@@ -938,6 +944,12 @@
         else:
             assert isinstance(pred, predicate.Predicate)
             compare_func = pred.satisfiedByNode
+        if showingOnly == None:
+            showingOnly = config.searchShowingOnly
+        if showingOnly:
+            orig_compare_func = compare_func
+            compare_func = lambda n: orig_compare_func(n) and \
+                                     n.getState().contains(pyatspi.STATE_SHOWING)
 
         results = []
         numAttempts = 0
@@ -960,7 +972,7 @@
         return results
 
     # 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.
@@ -976,7 +988,7 @@
         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.
 
@@ -985,9 +997,9 @@
         also logs the search.
         """
         return self.findChild(predicate.GenericPredicate(name=name, roleName=roleName, description=description,
-                              label=label), recursive=recursive, retry=retry, debugName=debugName)
+                              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.
 
@@ -1002,12 +1014,12 @@
             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.
 
@@ -1015,9 +1027,9 @@
         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.
 
@@ -1025,9 +1037,9 @@
         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.
 
@@ -1035,9 +1047,9 @@
         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.
 
@@ -1045,9 +1057,9 @@
         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.
 
@@ -1055,9 +1067,9 @@
         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.
 
@@ -1065,9 +1077,9 @@
         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.
 
@@ -1075,7 +1087,7 @@
         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):
         """
@@ -1138,7 +1150,7 @@
         """
         Get all applications.
         """
-        return root.findChildren(predicate.GenericPredicate(roleName="application"), recursive=False)
+        return root.findChildren(predicate.GenericPredicate(roleName="application"), recursive=False, showingOnly=False)
 
     def application(self, appName, retry=True):
         """
@@ -1149,11 +1161,11 @@
         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.
@@ -1164,9 +1176,9 @@
 
         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.
@@ -1179,13 +1191,13 @@
         The window will be automatically activated (raised and focused
         by the window manager) if wnck bindings are available.
         """
-        result = self.findChild(predicate.IsAWindowNamed(windowName=windowName), recursive)
+        result = self.findChild(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
 
@@ -1196,7 +1208,7 @@
 
         FIXME: untested
         """
-        window = self.child(roleName='frame')
+        window = self.child(roleName='frame', showingOnly=showingOnly)
         if window:
             wnckWindow = window.getWnckWindow()
             return wnckWindow.get_application()