python-dogtail_searchShowingOnly.diff 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. Author: anonym <anonym@riseup.net>
  2. Date: Mon Apr 4 18:04:52 2016 +0200
  3. Add support for only searching among 'showing' nodes.
  4. Here 'showing' refers to pyatspi.STATE_SHOWING, i.e. whether a node is
  5. shown to the end-user or not. Quite often we are only interested in
  6. such nodes, at least when dogtail is used to interact with an
  7. application (e.g. clicking something that isn't there won't
  8. work). Most importantly, this greatly simplifies situations where the
  9. 'shown' element we are looking for is hard to exactly pinpoint since
  10. it lacks properties to distinguish it from some not 'shown' elements,
  11. which is quite common when nodes lack names.
  12. Therefore we add a `showingOnly` boolean flag to all Node search
  13. methods. The default will be to not do this, for backwards
  14. compatibility, but the default is configurable via a new
  15. `searchShowingOnly` config option.
  16. --- a/usr/lib/python2.7/dist-packages/dogtail/config.py
  17. +++ b/usr/lib/python2.7/dist-packages/dogtail/config.py
  18. @@ -60,6 +60,9 @@
  19. searchCutoffCount (int):
  20. Number of times to retry when a search fails.
  21. + searchShowingOnly (boolean):
  22. + Whether to only search among nodes that are currently being shown.
  23. +
  24. defaultDelay (float):
  25. Default time in seconds to sleep when delaying.
  26. @@ -136,6 +139,7 @@
  27. 'searchBackoffDuration': 0.5,
  28. 'searchWarningThreshold': 3,
  29. 'searchCutoffCount': 20,
  30. + 'searchShowingOnly': False,
  31. 'defaultDelay': 0.5,
  32. 'childrenLimit': 100,
  33. --- a/usr/lib/python2.7/dist-packages/dogtail/tree.py
  34. +++ b/usr/lib/python2.7/dist-packages/dogtail/tree.py
  35. @@ -855,12 +855,18 @@
  36. else:
  37. return False
  38. - def _fastFindChild(self, pred, recursive=True):
  39. + def _fastFindChild(self, pred, recursive=True, showingOnly=None):
  40. """
  41. Searches for an Accessible using methods from pyatspi.utils
  42. """
  43. if isinstance(pred, predicate.Predicate):
  44. pred = pred.satisfiedByNode
  45. + if showingOnly == None:
  46. + showingOnly = config.searchShowingOnly
  47. + if showingOnly:
  48. + orig_pred = pred
  49. + pred = lambda n: orig_pred(n) and \
  50. + n.getState().contains(pyatspi.STATE_SHOWING)
  51. if not recursive:
  52. cIter = iter(self)
  53. while True:
  54. @@ -873,7 +879,7 @@
  55. else:
  56. return pyatspi.utils.findDescendant(self, pred)
  57. - def findChild(self, pred, recursive=True, debugName=None, retry=True, requireResult=True):
  58. + def findChild(self, pred, recursive=True, debugName=None, retry=True, requireResult=True, showingOnly=None):
  59. """
  60. Search for a node satisyfing the predicate, returning a Node.
  61. @@ -905,7 +911,7 @@
  62. logger.log("searching for %s (attempt %i)" %
  63. (describeSearch(self, pred, recursive, debugName), numAttempts))
  64. - result = self._fastFindChild(pred.satisfiedByNode, recursive)
  65. + result = self._fastFindChild(pred.satisfiedByNode, recursive, showingOnly=showingOnly)
  66. if result:
  67. assert isinstance(result, Node)
  68. if debugName:
  69. @@ -924,7 +930,7 @@
  70. raise SearchError(describeSearch(self, pred, recursive, debugName))
  71. # The canonical "search for multiple" method:
  72. - def findChildren(self, pred, recursive=True, isLambda=False):
  73. + def findChildren(self, pred, recursive=True, isLambda=False, showingOnly=None):
  74. """
  75. Find all children/descendents satisfying the predicate.
  76. You can also use lambdas in place of pred that will enable search also against
  77. @@ -938,6 +944,12 @@
  78. else:
  79. assert isinstance(pred, predicate.Predicate)
  80. compare_func = pred.satisfiedByNode
  81. + if showingOnly == None:
  82. + showingOnly = config.searchShowingOnly
  83. + if showingOnly:
  84. + orig_compare_func = compare_func
  85. + compare_func = lambda n: orig_compare_func(n) and \
  86. + n.getState().contains(pyatspi.STATE_SHOWING)
  87. results = []
  88. numAttempts = 0
  89. @@ -960,7 +972,7 @@
  90. return results
  91. # The canonical "search above this node" method:
  92. - def findAncestor(self, pred):
  93. + def findAncestor(self, pred, showingOnly=None):
  94. """
  95. Search up the ancestry of this node, returning the first Node
  96. satisfying the predicate, or None.
  97. @@ -976,7 +988,7 @@
  98. return None
  99. # Various wrapper/helper search methods:
  100. - def child(self, name='', roleName='', description='', label='', recursive=True, retry=True, debugName=None):
  101. + def child(self, name='', roleName='', description='', label='', recursive=True, retry=True, debugName=None, showingOnly=None):
  102. """
  103. Finds a child satisying the given criteria.
  104. @@ -985,9 +997,9 @@
  105. also logs the search.
  106. """
  107. return self.findChild(predicate.GenericPredicate(name=name, roleName=roleName, description=description,
  108. - label=label), recursive=recursive, retry=retry, debugName=debugName)
  109. + label=label), recursive=recursive, retry=retry, debugName=debugName, showingOnly=showingOnly)
  110. - def isChild(self, name='', roleName='', description='', label='', recursive=True, retry=False, debugName=None):
  111. + def isChild(self, name='', roleName='', description='', label='', recursive=True, retry=False, debugName=None, showingOnly=None):
  112. """
  113. Determines whether a child satisying the given criteria exists.
  114. @@ -1002,12 +1014,12 @@
  115. self.findChild(
  116. predicate.GenericPredicate(
  117. name=name, roleName=roleName, description=description, label=label),
  118. - recursive=recursive, retry=retry, debugName=debugName)
  119. + recursive=recursive, retry=retry, debugName=debugName, showingOnly=showingOnly)
  120. except SearchError:
  121. found = False
  122. return found
  123. - def menu(self, menuName, recursive=True):
  124. + def menu(self, menuName, recursive=True, showingOnly=None):
  125. """
  126. Search below this node for a menu with the given name.
  127. @@ -1015,9 +1027,9 @@
  128. if no such child is found, and will eventually raise an exception. It
  129. also logs the search.
  130. """
  131. - return self.findChild(predicate.IsAMenuNamed(menuName=menuName), recursive)
  132. + return self.findChild(predicate.IsAMenuNamed(menuName=menuName), recursive, showingOnly=showingOnly)
  133. - def menuItem(self, menuItemName, recursive=True):
  134. + def menuItem(self, menuItemName, recursive=True, showingOnly=None):
  135. """
  136. Search below this node for a menu item with the given name.
  137. @@ -1025,9 +1037,9 @@
  138. if no such child is found, and will eventually raise an exception. It
  139. also logs the search.
  140. """
  141. - return self.findChild(predicate.IsAMenuItemNamed(menuItemName=menuItemName), recursive)
  142. + return self.findChild(predicate.IsAMenuItemNamed(menuItemName=menuItemName), recursive, showingOnly=showingOnly)
  143. - def textentry(self, textEntryName, recursive=True):
  144. + def textentry(self, textEntryName, recursive=True, showingOnly=None):
  145. """
  146. Search below this node for a text entry with the given name.
  147. @@ -1035,9 +1047,9 @@
  148. if no such child is found, and will eventually raise an exception. It
  149. also logs the search.
  150. """
  151. - return self.findChild(predicate.IsATextEntryNamed(textEntryName=textEntryName), recursive)
  152. + return self.findChild(predicate.IsATextEntryNamed(textEntryName=textEntryName), recursive, showingOnly=showingOnly)
  153. - def button(self, buttonName, recursive=True):
  154. + def button(self, buttonName, recursive=True, showingOnly=None):
  155. """
  156. Search below this node for a button with the given name.
  157. @@ -1045,9 +1057,9 @@
  158. if no such child is found, and will eventually raise an exception. It
  159. also logs the search.
  160. """
  161. - return self.findChild(predicate.IsAButtonNamed(buttonName=buttonName), recursive)
  162. + return self.findChild(predicate.IsAButtonNamed(buttonName=buttonName), recursive, showingOnly=showingOnly)
  163. - def childLabelled(self, labelText, recursive=True):
  164. + def childLabelled(self, labelText, recursive=True, showingOnly=None):
  165. """
  166. Search below this node for a child labelled with the given text.
  167. @@ -1055,9 +1067,9 @@
  168. if no such child is found, and will eventually raise an exception. It
  169. also logs the search.
  170. """
  171. - return self.findChild(predicate.IsLabelledAs(labelText), recursive)
  172. + return self.findChild(predicate.IsLabelledAs(labelText), recursive, showingOnly=showingOnly)
  173. - def childNamed(self, childName, recursive=True):
  174. + def childNamed(self, childName, recursive=True, showingOnly=None):
  175. """
  176. Search below this node for a child with the given name.
  177. @@ -1065,9 +1077,9 @@
  178. if no such child is found, and will eventually raise an exception. It
  179. also logs the search.
  180. """
  181. - return self.findChild(predicate.IsNamed(childName), recursive)
  182. + return self.findChild(predicate.IsNamed(childName), recursive, showingOnly=showingOnly)
  183. - def tab(self, tabName, recursive=True):
  184. + def tab(self, tabName, recursive=True, showingOnly=None):
  185. """
  186. Search below this node for a tab with the given name.
  187. @@ -1075,7 +1087,7 @@
  188. if no such child is found, and will eventually raise an exception. It
  189. also logs the search.
  190. """
  191. - return self.findChild(predicate.IsATabNamed(tabName=tabName), recursive)
  192. + return self.findChild(predicate.IsATabNamed(tabName=tabName), recursive, showingOnly=showingOnly)
  193. def getUserVisibleStrings(self):
  194. """
  195. @@ -1138,7 +1150,7 @@
  196. """
  197. Get all applications.
  198. """
  199. - return root.findChildren(predicate.GenericPredicate(roleName="application"), recursive=False)
  200. + return root.findChildren(predicate.GenericPredicate(roleName="application"), recursive=False, showingOnly=False)
  201. def application(self, appName, retry=True):
  202. """
  203. @@ -1149,11 +1161,11 @@
  204. if no such child is found, and will eventually raise an exception. It
  205. also logs the search.
  206. """
  207. - return root.findChild(predicate.IsAnApplicationNamed(appName), recursive=False, retry=retry)
  208. + return root.findChild(predicate.IsAnApplicationNamed(appName), recursive=False, retry=retry, showingOnly=False)
  209. class Application (Node):
  210. - def dialog(self, dialogName, recursive=False):
  211. + def dialog(self, dialogName, recursive=False, showingOnly=None):
  212. """
  213. Search below this node for a dialog with the given name,
  214. returning a Window instance.
  215. @@ -1164,9 +1176,9 @@
  216. FIXME: should this method activate the dialog?
  217. """
  218. - return self.findChild(predicate.IsADialogNamed(dialogName=dialogName), recursive)
  219. + return self.findChild(predicate.IsADialogNamed(dialogName=dialogName), recursive, showingOnly=showingOnly)
  220. - def window(self, windowName, recursive=False):
  221. + def window(self, windowName, recursive=False, showingOnly=None):
  222. """
  223. Search below this node for a window with the given name,
  224. returning a Window instance.
  225. @@ -1179,13 +1191,13 @@
  226. The window will be automatically activated (raised and focused
  227. by the window manager) if wnck bindings are available.
  228. """
  229. - result = self.findChild(predicate.IsAWindowNamed(windowName=windowName), recursive)
  230. + result = self.findChild(predicate.IsAWindowNamed(windowName=windowName), recursive, showingOnly=showingOnly)
  231. # FIXME: activate the WnckWindow ?
  232. # if gotWnck:
  233. # result.activate()
  234. return result
  235. - def getWnckApplication(self): # pragma: no cover
  236. + def getWnckApplication(self, showingOnly=None): # pragma: no cover
  237. """
  238. Get the wnck.Application instance for this application, or None
  239. @@ -1196,7 +1208,7 @@
  240. FIXME: untested
  241. """
  242. - window = self.child(roleName='frame')
  243. + window = self.child(roleName='frame', showingOnly=showingOnly)
  244. if window:
  245. wnckWindow = window.getWnckWindow()
  246. return wnckWindow.get_application()
  247. --
  248. 2.10.1