win32.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. # coding=utf-8
  2. # pystray
  3. # Copyright (C) 2016-2020 Moses Palmér
  4. #
  5. # This program is free software: you can redistribute it and/or modify it under
  6. # the terms of the GNU Lesser General Public License as published by the Free
  7. # Software Foundation, either version 3 of the License, or (at your option) any
  8. # later version.
  9. #
  10. # This program is distributed in the hope that it will be useful, but WITHOUT
  11. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  13. # details.
  14. #
  15. # You should have received a copy of the GNU Lesser General Public License
  16. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. import ctypes
  18. from ctypes import wintypes
  19. windll = ctypes.LibraryLoader(ctypes.WinDLL)
  20. WM_CREATE = 0x0001
  21. WM_NCCREATE = 0x0081
  22. WM_LBUTTONUP = 0x0202
  23. WM_RBUTTONUP = 0x0205
  24. WM_USER = 0x400
  25. WM_STOP = WM_USER + 10
  26. WM_NOTIFY = WM_USER + 11
  27. LR_DEFAULTSIZE = 0x00000040
  28. LR_LOADFROMFILE = 0x00000010
  29. MFS_CHECKED = 0x00000008
  30. MFS_DEFAULT = 0x00001000
  31. MFS_DISABLED = 0x00000003
  32. MFS_ENABLED = 0x00000000
  33. MFS_GRAYED = 0x00000003
  34. MFS_HILITE = 0x00000080
  35. MFS_UNCHECKED = 0x00000000
  36. MFS_UNHILITE = 0x00000000
  37. MFT_BITMAP = 0x00000004
  38. MFT_MENUBARBREAK = 0x00000020
  39. MFT_MENUBREAK = 0x00000040
  40. MFT_OWNERDRAW = 0x00000100
  41. MFT_RADIOCHECK = 0x00000200
  42. MFT_RIGHTJUSTIFY = 0x00004000
  43. MFT_RIGHTORDER = 0x00002000
  44. MFT_SEPARATOR = 0x00000800
  45. MFT_STRING = 0x00000000
  46. MIIM_BITMAP = 0x00000080
  47. MIIM_CHECKMARKS = 0x00000008
  48. MIIM_DATA = 0x00000020
  49. MIIM_FTYPE = 0x00000100
  50. MIIM_ID = 0x00000002
  51. MIIM_STATE = 0x00000001
  52. MIIM_STRING = 0x00000040
  53. MIIM_SUBMENU = 0x00000004
  54. MIIM_TYPE = 0x00000010
  55. MSGFLT_ALLOW = 1
  56. MSGFLT_DISALLOW = 2
  57. MSGFLT_RESET = 0
  58. NIF_MESSAGE = 0x00000001
  59. NIF_ICON = 0x00000002
  60. NIF_TIP = 0x00000004
  61. NIF_STATE = 0x00000008
  62. NIF_INFO = 0x00000010
  63. NIF_GUID = 0x00000020
  64. NIF_REALTIME = 0x00000040
  65. NIF_SHOWTIP = 0x00000080
  66. NIM_ADD = 0x00000000
  67. NIM_MODIFY = 0x00000001
  68. NIM_DELETE = 0x00000002
  69. NIM_SETFOCUS = 0x00000003
  70. NIM_SETVERSION = 0x00000004
  71. TPM_CENTERALIGN = 0x0004
  72. TPM_LEFTALIGN = 0x0000
  73. TPM_RIGHTALIGN = 0x0008
  74. TPM_BOTTOMALIGN = 0x0020
  75. TPM_TOPALIGN = 0x0000
  76. TPM_VCENTERALIGN = 0x0010
  77. TPM_NONOTIFY = 0x0080
  78. TPM_RETURNCMD = 0x0100
  79. TPM_LEFTBUTTON = 0x0000
  80. TPM_RIGHTBUTTON = 0x0002
  81. TPM_HORNEGANIMATION = 0x0800
  82. TPM_HORPOSANIMATION = 0x0400
  83. TPM_NOANIMATION = 0x4000
  84. TPM_VERNEGANIMATION = 0x2000
  85. TPM_VERPOSANIMATION = 0x1000
  86. TPM_HORIZONTAL = 0x0000
  87. TPM_VERTICAL = 0x0040
  88. WS_POPUP = 0x80000000
  89. PM_NOREMOVE = 0
  90. COLOR_WINDOW = 5
  91. HWND_MESSAGE = -3
  92. IMAGE_ICON = 1
  93. LPMSG = ctypes.POINTER(wintypes.MSG)
  94. LPPOINT = ctypes.POINTER(wintypes.POINT)
  95. WNDPROC = ctypes.WINFUNCTYPE(
  96. ctypes.HRESULT,
  97. wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)
  98. class MENUITEMINFO(ctypes.Structure):
  99. _fields_ = [
  100. ('cbSize', wintypes.UINT),
  101. ('fMask', wintypes.UINT),
  102. ('fType', wintypes.UINT),
  103. ('fState', wintypes.UINT),
  104. ('wID', wintypes.UINT),
  105. ('hSubMenu', wintypes.HMENU),
  106. ('hbmpChecked', wintypes.HBITMAP),
  107. ('hbmpUnchecked', wintypes.HBITMAP),
  108. ('dwItemData', wintypes.LPVOID),
  109. ('dwTypeData', wintypes.LPCWSTR),
  110. ('cch', wintypes.UINT),
  111. ('hbmpItem', wintypes.HBITMAP)]
  112. LPMENUITEMINFO = ctypes.POINTER(MENUITEMINFO)
  113. class NOTIFYICONDATAW(ctypes.Structure):
  114. class VERSION_OR_TIMEOUT(ctypes.Union):
  115. _fields_ = [
  116. ('uTimeout', wintypes.UINT),
  117. ('uVersion', wintypes.UINT)]
  118. class GUID(ctypes.Structure):
  119. _fields_ = [
  120. ('Data1', wintypes.ULONG),
  121. ('Data2', wintypes.WORD),
  122. ('Data3', wintypes.WORD),
  123. ('Data4', wintypes.BYTE * 8)]
  124. _fields_ = [
  125. ('cbSize', wintypes.DWORD),
  126. ('hWnd', wintypes.HWND),
  127. ('uID', wintypes.UINT),
  128. ('uFlags', wintypes.UINT),
  129. ('uCallbackMessage', wintypes.UINT),
  130. ('hIcon', wintypes.HICON),
  131. ('szTip', wintypes.WCHAR * 128),
  132. ('dwState', wintypes.DWORD),
  133. ('dwStateMask', wintypes.DWORD),
  134. ('szInfo', wintypes.WCHAR * 256),
  135. ('version_or_timeout', VERSION_OR_TIMEOUT),
  136. ('szInfoTitle', wintypes.WCHAR * 64),
  137. ('dwInfoFlags', wintypes.DWORD),
  138. ('guidItem', GUID),
  139. ('hBalloonIcon', wintypes.HICON)]
  140. _anonymous_ = [
  141. 'version_or_timeout']
  142. LPNOTIFYICONDATAW = ctypes.POINTER(NOTIFYICONDATAW)
  143. class TPMPARAMS(ctypes.Structure):
  144. _fields_ = [
  145. ('cbSize', wintypes.UINT),
  146. ('rcExclude', wintypes.RECT)]
  147. LPTPMPARAMS = ctypes.POINTER(TPMPARAMS)
  148. class WNDCLASSEX(ctypes.Structure):
  149. _fields_ = [
  150. ('cbSize', wintypes.UINT),
  151. ('style', wintypes.UINT),
  152. ('lpfnWndProc', WNDPROC),
  153. ('cbClsExtra', wintypes.INT),
  154. ('cbWndExtra', wintypes.INT),
  155. ('hInstance', wintypes.HANDLE),
  156. ('hIcon', wintypes.HICON),
  157. ('hCursor', wintypes.HANDLE),
  158. ('hbrBackground', wintypes.HBRUSH),
  159. ('lpszMenuName', wintypes.LPCWSTR),
  160. ('lpszClassName', wintypes.LPCWSTR),
  161. ('hIconSm', wintypes.HICON)]
  162. def _err(result, func, arguments):
  163. """A *ctypes* ``errchecker`` that ensures truthy values.
  164. """
  165. if not result:
  166. raise ctypes.WinError()
  167. else:
  168. return result
  169. LPWNDCLASSEX = ctypes.POINTER(WNDCLASSEX)
  170. CreatePopupMenu = windll.user32.CreatePopupMenu
  171. CreatePopupMenu.argtypes = ()
  172. CreatePopupMenu.restype = wintypes.HMENU
  173. CreatePopupMenu.errcheck = _err
  174. CreateWindowEx = windll.user32.CreateWindowExW
  175. CreateWindowEx.argtypes = (
  176. wintypes.DWORD, wintypes.ATOM, wintypes.LPCWSTR, wintypes.DWORD,
  177. wintypes.INT, wintypes.INT, wintypes.INT, wintypes.INT, wintypes.HWND,
  178. wintypes.HMENU, wintypes.HINSTANCE, wintypes.LPVOID)
  179. CreateWindowEx.restype = wintypes.HWND
  180. CreateWindowEx.errcheck = _err
  181. DefWindowProc = windll.user32.DefWindowProcW
  182. DefWindowProc.argtypes = (
  183. wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)
  184. DefWindowProc.restype = wintypes.DWORD
  185. DestroyIcon = windll.user32.DestroyIcon
  186. DestroyIcon.argtypes = (
  187. wintypes.HICON,)
  188. DestroyIcon.restype = wintypes.BOOL
  189. DestroyIcon.errcheck = _err
  190. DestroyMenu = windll.user32.DestroyMenu
  191. DestroyMenu.argtypes = (
  192. wintypes.HMENU,)
  193. DestroyMenu.restype = wintypes.BOOL
  194. DestroyMenu.errcheck = _err
  195. DestroyWindow = windll.user32.DestroyWindow
  196. DestroyWindow.argtypes = (
  197. wintypes.HWND,)
  198. DestroyWindow.restype = wintypes.BOOL
  199. DestroyWindow.errcheck = _err
  200. DispatchMessage = windll.user32.DispatchMessageW
  201. DispatchMessage.argtypes = (
  202. LPMSG,)
  203. DispatchMessage.restype = wintypes.DWORD
  204. GetCursorPos = windll.user32.GetCursorPos
  205. GetCursorPos.argtypes = (
  206. LPPOINT,)
  207. GetCursorPos.restype = wintypes.BOOL
  208. GetCursorPos.errcheck = _err
  209. GetMessage = windll.user32.GetMessageW
  210. GetMessage.argtypes = (
  211. LPMSG, wintypes.HWND, wintypes.UINT, wintypes.UINT)
  212. GetMessage.restype = wintypes.BOOL
  213. GetModuleHandle = windll.kernel32.GetModuleHandleW
  214. GetModuleHandle.argtypes = (
  215. wintypes.LPCWSTR,)
  216. GetModuleHandle.restype = wintypes.HMODULE
  217. GetModuleHandle.errcheck = _err
  218. InsertMenuItem = windll.user32.InsertMenuItemW
  219. InsertMenuItem.argtypes = (
  220. wintypes.HMENU, wintypes.UINT, wintypes.BOOL, LPMENUITEMINFO)
  221. InsertMenuItem.restype = wintypes.BOOL
  222. InsertMenuItem.errcheck = _err
  223. LoadImage = windll.user32.LoadImageW
  224. LoadImage.argtypes = (
  225. wintypes.HINSTANCE, wintypes.LPCWSTR, wintypes.UINT, wintypes.INT,
  226. wintypes.INT, wintypes.UINT)
  227. LoadImage.restype = wintypes.HANDLE
  228. LoadImage.errcheck = _err
  229. PeekMessage = windll.user32.PeekMessageW
  230. PeekMessage.argtypes = (
  231. LPMSG, wintypes.HWND, wintypes.UINT, wintypes.UINT, wintypes.UINT)
  232. PeekMessage.restype = wintypes.BOOL
  233. PostMessage = windll.user32.PostMessageW
  234. PostMessage.argtypes = (
  235. wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)
  236. PostMessage.restype = wintypes.BOOL
  237. PostMessage.restype = wintypes.BOOL
  238. PostQuitMessage = windll.user32.PostQuitMessage
  239. PostQuitMessage.argtypes = (
  240. wintypes.INT,)
  241. RegisterClassEx = windll.user32.RegisterClassExW
  242. RegisterClassEx.argtypes = (
  243. LPWNDCLASSEX,)
  244. RegisterClassEx.restype = wintypes.ATOM
  245. RegisterClassEx.errcheck = _err
  246. SetForegroundWindow = windll.user32.SetForegroundWindow
  247. SetForegroundWindow.argtypes = (
  248. wintypes.HWND,)
  249. SetForegroundWindow.restype = wintypes.BOOL
  250. Shell_NotifyIcon = windll.shell32.Shell_NotifyIconW
  251. Shell_NotifyIcon.argtypes = (
  252. wintypes.DWORD, LPNOTIFYICONDATAW)
  253. Shell_NotifyIcon.restype = wintypes.BOOL
  254. TranslateMessage = windll.user32.TranslateMessage
  255. TranslateMessage.argtypes = (
  256. LPMSG,)
  257. TranslateMessage.restype = wintypes.BOOL
  258. TrackPopupMenuEx = windll.user32.TrackPopupMenuEx
  259. TrackPopupMenuEx.argtypes = (
  260. wintypes.HMENU, wintypes.UINT, wintypes.INT, wintypes.INT, wintypes.HWND,
  261. LPTPMPARAMS)
  262. UnregisterClass = windll.user32.UnregisterClassW
  263. UnregisterClass.argtypes = (
  264. wintypes.ATOM, wintypes.HINSTANCE)
  265. UnregisterClass.restype = wintypes.BOOL
  266. UnregisterClass.errcheck = _err
  267. RegisterWindowMessage = windll.user32.RegisterWindowMessageW
  268. RegisterWindowMessage.argtypes = (
  269. wintypes.LPCWSTR,)
  270. RegisterWindowMessage.restype = wintypes.UINT
  271. RegisterWindowMessage.errcheck = _err
  272. #: The message broadcast to top-level windows on Explorer restart
  273. WM_TASKBARCREATED = RegisterWindowMessage('TaskbarCreated')
  274. # Ensure that we receive WM_TASKBARCREATED even when running with elevated
  275. # privileges
  276. try:
  277. ChangeWindowMessageFilterEx = windll.user32.ChangeWindowMessageFilterEx
  278. ChangeWindowMessageFilterEx.argtypes = (
  279. wintypes.HWND, wintypes.UINT, wintypes.DWORD, wintypes.LPVOID)
  280. ChangeWindowMessageFilterEx.restype = wintypes.BOOL
  281. ChangeWindowMessageFilterEx.errcheck = _err
  282. except KeyError:
  283. def ChangeWindowMessageFilterEx(
  284. hWnd, message, action, pCHangeFilterStruct):
  285. """A dummy implementation of ``ChangeWindowMessageFilterEx`` always
  286. returning ``TRUE``.
  287. This is used on version of *Windows* prior to *Windows Vista*.
  288. """
  289. return True