__init__.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. # PyGetWindow
  2. # A cross-platform module to find information about the windows on the screen.
  3. # Work in progress
  4. # Useful info:
  5. # https://stackoverflow.com/questions/373020/finding-the-current-active-window-in-mac-os-x-using-python
  6. # https://stackoverflow.com/questions/7142342/get-window-position-size-with-python
  7. # win32 api and ctypes on Windows
  8. # cocoa api and pyobjc on Mac
  9. # Xlib on linux
  10. # Possible Future Features:
  11. # get/click menu (win32: GetMenuItemCount, GetMenuItemInfo, GetMenuItemID, GetMenu, GetMenuItemRect)
  12. __version__ = "0.0.9"
  13. import sys, collections, pyrect
  14. class PyGetWindowException(Exception):
  15. """
  16. Base class for exceptions raised when PyGetWindow functions
  17. encounter a problem. If PyGetWindow raises an exception that isn't
  18. this class, that indicates a bug in the module.
  19. """
  20. pass
  21. def pointInRect(x, y, left, top, width, height):
  22. """Returns ``True`` if the ``(x, y)`` point is within the box described
  23. by ``(left, top, width, height)``."""
  24. return left < x < left + width and top < y < top + height
  25. # NOTE: `Rect` is a named tuple for use in Python, while structs.RECT represents
  26. # the win32 RECT struct. PyRect's Rect class is used for handling changing
  27. # geometry of rectangular areas.
  28. Rect = collections.namedtuple("Rect", "left top right bottom")
  29. Point = collections.namedtuple("Point", "x y")
  30. Size = collections.namedtuple("Size", "width height")
  31. class BaseWindow:
  32. def __init__(self):
  33. pass
  34. def _setupRectProperties(self):
  35. def _onRead(attrName):
  36. r = self._getWindowRect()
  37. self._rect._left = r.left # Setting _left directly to skip the onRead.
  38. self._rect._top = r.top # Setting _top directly to skip the onRead.
  39. self._rect._width = r.right - r.left # Setting _width directly to skip the onRead.
  40. self._rect._height = r.bottom - r.top # Setting _height directly to skip the onRead.
  41. def _onChange(oldBox, newBox):
  42. self.moveTo(newBox.left, newBox.top)
  43. self.resizeTo(newBox.width, newBox.height)
  44. r = self._getWindowRect()
  45. self._rect = pyrect.Rect(r.left, r.top, r.right - r.left, r.bottom - r.top, onChange=_onChange, onRead=_onRead)
  46. def _getWindowRect(self):
  47. raise NotImplementedError
  48. def __str__(self):
  49. r = self._getWindowRect()
  50. width = r.right - r.left
  51. height = r.bottom - r.top
  52. return '<%s left="%s", top="%s", width="%s", height="%s", title="%s">' % (
  53. self.__class__.__qualname__,
  54. r.left,
  55. r.top,
  56. width,
  57. height,
  58. self.title,
  59. )
  60. def close(self):
  61. """Closes this window. This may trigger "Are you sure you want to
  62. quit?" dialogs or other actions that prevent the window from
  63. actually closing. This is identical to clicking the X button on the
  64. window."""
  65. raise NotImplementedError
  66. def minimize(self):
  67. """Minimizes this window."""
  68. raise NotImplementedError
  69. def maximize(self):
  70. """Maximizes this window."""
  71. raise NotImplementedError
  72. def restore(self):
  73. """If maximized or minimized, restores the window to it's normal size."""
  74. raise NotImplementedError
  75. def activate(self):
  76. """Activate this window and make it the foreground window."""
  77. raise NotImplementedError
  78. def resizeRel(self, widthOffset, heightOffset):
  79. """Resizes the window relative to its current size."""
  80. raise NotImplementedError
  81. def resizeTo(self, newWidth, newHeight):
  82. """Resizes the window to a new width and height."""
  83. raise NotImplementedError
  84. def moveRel(self, xOffset, yOffset):
  85. """Moves the window relative to its current position."""
  86. raise NotImplementedError
  87. def moveTo(self, newLeft, newTop):
  88. """Moves the window to new coordinates on the screen."""
  89. raise NotImplementedError
  90. @property
  91. def isMinimized(self):
  92. """Returns True if the window is currently minimized."""
  93. raise NotImplementedError
  94. @property
  95. def isMaximized(self):
  96. """Returns True if the window is currently maximized."""
  97. raise NotImplementedError
  98. @property
  99. def isActive(self):
  100. """Returns True if the window is currently the active, foreground window."""
  101. raise NotImplementedError
  102. @property
  103. def title(self):
  104. """Returns the window title as a string."""
  105. raise NotImplementedError
  106. @property
  107. def visible(self):
  108. raise NotImplementedError
  109. # Wrappers for pyrect.Rect object's properties:
  110. @property
  111. def left(self):
  112. return self._rect.left
  113. @left.setter
  114. def left(self, value):
  115. # import pdb; pdb.set_trace()
  116. self._rect.left # Run rect's onRead to update the Rect object.
  117. self._rect.left = value
  118. @property
  119. def right(self):
  120. return self._rect.right
  121. @right.setter
  122. def right(self, value):
  123. self._rect.right # Run rect's onRead to update the Rect object.
  124. self._rect.right = value
  125. @property
  126. def top(self):
  127. return self._rect.top
  128. @top.setter
  129. def top(self, value):
  130. self._rect.top # Run rect's onRead to update the Rect object.
  131. self._rect.top = value
  132. @property
  133. def bottom(self):
  134. return self._rect.bottom
  135. @bottom.setter
  136. def bottom(self, value):
  137. self._rect.bottom # Run rect's onRead to update the Rect object.
  138. self._rect.bottom = value
  139. @property
  140. def topleft(self):
  141. return self._rect.topleft
  142. @topleft.setter
  143. def topleft(self, value):
  144. self._rect.topleft # Run rect's onRead to update the Rect object.
  145. self._rect.topleft = value
  146. @property
  147. def topright(self):
  148. return self._rect.topright
  149. @topright.setter
  150. def topright(self, value):
  151. self._rect.topright # Run rect's onRead to update the Rect object.
  152. self._rect.topright = value
  153. @property
  154. def bottomleft(self):
  155. return self._rect.bottomleft
  156. @bottomleft.setter
  157. def bottomleft(self, value):
  158. self._rect.bottomleft # Run rect's onRead to update the Rect object.
  159. self._rect.bottomleft = value
  160. @property
  161. def bottomright(self):
  162. return self._rect.bottomright
  163. @bottomright.setter
  164. def bottomright(self, value):
  165. self._rect.bottomright # Run rect's onRead to update the Rect object.
  166. self._rect.bottomright = value
  167. @property
  168. def midleft(self):
  169. return self._rect.midleft
  170. @midleft.setter
  171. def midleft(self, value):
  172. self._rect.midleft # Run rect's onRead to update the Rect object.
  173. self._rect.midleft = value
  174. @property
  175. def midright(self):
  176. return self._rect.midright
  177. @midright.setter
  178. def midright(self, value):
  179. self._rect.midright # Run rect's onRead to update the Rect object.
  180. self._rect.midright = value
  181. @property
  182. def midtop(self):
  183. return self._rect.midtop
  184. @midtop.setter
  185. def midtop(self, value):
  186. self._rect.midtop # Run rect's onRead to update the Rect object.
  187. self._rect.midtop = value
  188. @property
  189. def midbottom(self):
  190. return self._rect.midbottom
  191. @midbottom.setter
  192. def midbottom(self, value):
  193. self._rect.midbottom # Run rect's onRead to update the Rect object.
  194. self._rect.midbottom = value
  195. @property
  196. def center(self):
  197. return self._rect.center
  198. @center.setter
  199. def center(self, value):
  200. self._rect.center # Run rect's onRead to update the Rect object.
  201. self._rect.center = value
  202. @property
  203. def centerx(self):
  204. return self._rect.centerx
  205. @centerx.setter
  206. def centerx(self, value):
  207. self._rect.centerx # Run rect's onRead to update the Rect object.
  208. self._rect.centerx = value
  209. @property
  210. def centery(self):
  211. return self._rect.centery
  212. @centery.setter
  213. def centery(self, value):
  214. self._rect.centery # Run rect's onRead to update the Rect object.
  215. self._rect.centery = value
  216. @property
  217. def width(self):
  218. return self._rect.width
  219. @width.setter
  220. def width(self, value):
  221. self._rect.width # Run rect's onRead to update the Rect object.
  222. self._rect.width = value
  223. @property
  224. def height(self):
  225. return self._rect.height
  226. @height.setter
  227. def height(self, value):
  228. self._rect.height # Run rect's onRead to update the Rect object.
  229. self._rect.height = value
  230. @property
  231. def size(self):
  232. return self._rect.size
  233. @size.setter
  234. def size(self, value):
  235. self._rect.size # Run rect's onRead to update the Rect object.
  236. self._rect.size = value
  237. @property
  238. def area(self):
  239. return self._rect.area
  240. @area.setter
  241. def area(self, value):
  242. self._rect.area # Run rect's onRead to update the Rect object.
  243. self._rect.area = value
  244. @property
  245. def box(self):
  246. return self._rect.box
  247. @box.setter
  248. def box(self, value):
  249. self._rect.box # Run rect's onRead to update the Rect object.
  250. self._rect.box = value
  251. if sys.platform == "darwin":
  252. # raise NotImplementedError('PyGetWindow currently does not support macOS. If you have Appkit/Cocoa knowledge, please contribute! https://github.com/asweigart/pygetwindow') # TODO - implement mac
  253. from ._pygetwindow_macos import *
  254. Window = MacOSWindow
  255. elif sys.platform == "win32":
  256. from ._pygetwindow_win import (
  257. Win32Window,
  258. getActiveWindow,
  259. getActiveWindowTitle,
  260. getWindowsAt,
  261. getWindowsWithTitle,
  262. getAllWindows,
  263. getAllTitles,
  264. )
  265. Window = Win32Window
  266. else:
  267. raise NotImplementedError(
  268. "PyGetWindow currently does not support Linux. If you have Xlib knowledge, please contribute! https://github.com/asweigart/pygetwindow"
  269. )