Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

desktopmanager.py 8.0KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. # Demonstrates using a taskbar icon to create and navigate between desktops
  2. import _thread
  3. import io
  4. import time
  5. import traceback
  6. import pywintypes
  7. import win32api
  8. import win32con
  9. import win32gui
  10. import win32process
  11. import win32service
  12. ## "Shell_TrayWnd" is class of system tray window, broadcasts "TaskbarCreated" when initialized
  13. def desktop_name_dlgproc(hwnd, msg, wparam, lparam):
  14. """Handles messages from the desktop name dialog box"""
  15. if msg in (win32con.WM_CLOSE, win32con.WM_DESTROY):
  16. win32gui.DestroyWindow(hwnd)
  17. elif msg == win32con.WM_COMMAND:
  18. if wparam == win32con.IDOK:
  19. desktop_name = win32gui.GetDlgItemText(hwnd, 72)
  20. print("new desktop name: ", desktop_name)
  21. win32gui.DestroyWindow(hwnd)
  22. create_desktop(desktop_name)
  23. elif wparam == win32con.IDCANCEL:
  24. win32gui.DestroyWindow(hwnd)
  25. def get_new_desktop_name(parent_hwnd):
  26. """Create a dialog box to ask the user for name of desktop to be created"""
  27. msgs = {
  28. win32con.WM_COMMAND: desktop_name_dlgproc,
  29. win32con.WM_CLOSE: desktop_name_dlgproc,
  30. win32con.WM_DESTROY: desktop_name_dlgproc,
  31. }
  32. # dlg item [type, caption, id, (x,y,cx,cy), style, ex style
  33. style = (
  34. win32con.WS_BORDER
  35. | win32con.WS_VISIBLE
  36. | win32con.WS_CAPTION
  37. | win32con.WS_SYSMENU
  38. ) ## |win32con.DS_SYSMODAL
  39. h = win32gui.CreateDialogIndirect(
  40. win32api.GetModuleHandle(None),
  41. [
  42. ["One ugly dialog box !", (100, 100, 200, 100), style, 0],
  43. [
  44. "Button",
  45. "Create",
  46. win32con.IDOK,
  47. (10, 10, 30, 20),
  48. win32con.WS_VISIBLE
  49. | win32con.WS_TABSTOP
  50. | win32con.BS_HOLLOW
  51. | win32con.BS_DEFPUSHBUTTON,
  52. ],
  53. [
  54. "Button",
  55. "Never mind",
  56. win32con.IDCANCEL,
  57. (45, 10, 50, 20),
  58. win32con.WS_VISIBLE | win32con.WS_TABSTOP | win32con.BS_HOLLOW,
  59. ],
  60. ["Static", "Desktop name:", 71, (10, 40, 70, 10), win32con.WS_VISIBLE],
  61. ["Edit", "", 72, (75, 40, 90, 10), win32con.WS_VISIBLE],
  62. ],
  63. parent_hwnd,
  64. msgs,
  65. ) ## parent_hwnd, msgs)
  66. win32gui.EnableWindow(h, True)
  67. hcontrol = win32gui.GetDlgItem(h, 72)
  68. win32gui.EnableWindow(hcontrol, True)
  69. win32gui.SetFocus(hcontrol)
  70. def new_icon(hdesk, desktop_name):
  71. """Runs as a thread on each desktop to create a new tray icon and handle its messages"""
  72. global id
  73. id = id + 1
  74. hdesk.SetThreadDesktop()
  75. ## apparently the threads can't use same hinst, so each needs its own window class
  76. windowclassname = "PythonDesktopManager" + desktop_name
  77. wc = win32gui.WNDCLASS()
  78. wc.hInstance = win32api.GetModuleHandle(None)
  79. wc.lpszClassName = windowclassname
  80. wc.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW | win32con.CS_GLOBALCLASS
  81. wc.hCursor = win32gui.LoadCursor(0, win32con.IDC_ARROW)
  82. wc.hbrBackground = win32con.COLOR_WINDOW
  83. wc.lpfnWndProc = icon_wndproc
  84. windowclass = win32gui.RegisterClass(wc)
  85. style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU
  86. hwnd = win32gui.CreateWindow(
  87. windowclass,
  88. "dm_" + desktop_name,
  89. win32con.WS_SYSMENU,
  90. 0,
  91. 0,
  92. win32con.CW_USEDEFAULT,
  93. win32con.CW_USEDEFAULT,
  94. 0,
  95. 0,
  96. wc.hInstance,
  97. None,
  98. )
  99. win32gui.UpdateWindow(hwnd)
  100. flags = win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP
  101. notify_info = (
  102. hwnd,
  103. id,
  104. flags,
  105. win32con.WM_USER + 20,
  106. hicon,
  107. "Desktop Manager (%s)" % desktop_name,
  108. )
  109. window_info[hwnd] = notify_info
  110. ## wait for explorer to initialize system tray for new desktop
  111. tray_found = 0
  112. while not tray_found:
  113. try:
  114. tray_found = win32gui.FindWindow("Shell_TrayWnd", None)
  115. except win32gui.error:
  116. traceback.print_exc
  117. time.sleep(0.5)
  118. win32gui.Shell_NotifyIcon(win32gui.NIM_ADD, notify_info)
  119. win32gui.PumpMessages()
  120. def create_desktop(desktop_name, start_explorer=1):
  121. """Creates a new desktop and spawns a thread running on it
  122. Will also start a new icon thread on an existing desktop
  123. """
  124. sa = pywintypes.SECURITY_ATTRIBUTES()
  125. sa.bInheritHandle = 1
  126. try:
  127. hdesk = win32service.CreateDesktop(
  128. desktop_name, 0, win32con.MAXIMUM_ALLOWED, sa
  129. )
  130. except win32service.error:
  131. traceback.print_exc()
  132. errbuf = io.StringIO()
  133. traceback.print_exc(None, errbuf)
  134. win32api.MessageBox(0, errbuf.getvalue(), "Desktop creation failed")
  135. return
  136. if start_explorer:
  137. s = win32process.STARTUPINFO()
  138. s.lpDesktop = desktop_name
  139. prc_info = win32process.CreateProcess(
  140. None,
  141. "Explorer.exe",
  142. None,
  143. None,
  144. True,
  145. win32con.CREATE_NEW_CONSOLE,
  146. None,
  147. "c:\\",
  148. s,
  149. )
  150. th = _thread.start_new_thread(new_icon, (hdesk, desktop_name))
  151. hdesk.SwitchDesktop()
  152. def icon_wndproc(hwnd, msg, wp, lp):
  153. """Window proc for the tray icons"""
  154. if lp == win32con.WM_LBUTTONDOWN:
  155. ## popup menu won't disappear if you don't do this
  156. win32gui.SetForegroundWindow(hwnd)
  157. curr_desktop = win32service.OpenInputDesktop(0, True, win32con.MAXIMUM_ALLOWED)
  158. curr_desktop_name = win32service.GetUserObjectInformation(
  159. curr_desktop, win32con.UOI_NAME
  160. )
  161. winsta = win32service.GetProcessWindowStation()
  162. desktops = winsta.EnumDesktops()
  163. m = win32gui.CreatePopupMenu()
  164. desktop_cnt = len(desktops)
  165. ## *don't* create an item 0
  166. for d in range(1, desktop_cnt + 1):
  167. mf_flags = win32con.MF_STRING
  168. ## if you switch to winlogon yourself, there's nothing there and you're stuck
  169. if desktops[d - 1].lower() in ("winlogon", "disconnect"):
  170. mf_flags = mf_flags | win32con.MF_GRAYED | win32con.MF_DISABLED
  171. if desktops[d - 1] == curr_desktop_name:
  172. mf_flags = mf_flags | win32con.MF_CHECKED
  173. win32gui.AppendMenu(m, mf_flags, d, desktops[d - 1])
  174. win32gui.AppendMenu(m, win32con.MF_STRING, desktop_cnt + 1, "Create new ...")
  175. win32gui.AppendMenu(m, win32con.MF_STRING, desktop_cnt + 2, "Exit")
  176. x, y = win32gui.GetCursorPos()
  177. d = win32gui.TrackPopupMenu(
  178. m,
  179. win32con.TPM_LEFTBUTTON | win32con.TPM_RETURNCMD | win32con.TPM_NONOTIFY,
  180. x,
  181. y,
  182. 0,
  183. hwnd,
  184. None,
  185. )
  186. win32gui.PumpWaitingMessages()
  187. win32gui.DestroyMenu(m)
  188. if d == desktop_cnt + 1: ## Create new
  189. get_new_desktop_name(hwnd)
  190. elif d == desktop_cnt + 2: ## Exit
  191. win32gui.PostQuitMessage(0)
  192. win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, window_info[hwnd])
  193. del window_info[hwnd]
  194. origin_desktop.SwitchDesktop()
  195. elif d > 0:
  196. hdesk = win32service.OpenDesktop(
  197. desktops[d - 1], 0, 0, win32con.MAXIMUM_ALLOWED
  198. )
  199. hdesk.SwitchDesktop()
  200. return 0
  201. else:
  202. return win32gui.DefWindowProc(hwnd, msg, wp, lp)
  203. window_info = {}
  204. origin_desktop = win32service.OpenInputDesktop(0, True, win32con.MAXIMUM_ALLOWED)
  205. origin_desktop_name = win32service.GetUserObjectInformation(
  206. origin_desktop, win32service.UOI_NAME
  207. )
  208. hinst = win32api.GetModuleHandle(None)
  209. try:
  210. hicon = win32gui.LoadIcon(hinst, 1) ## python.exe and pythonw.exe
  211. except win32gui.error:
  212. hicon = win32gui.LoadIcon(hinst, 135) ## pythonwin's icon
  213. id = 0
  214. create_desktop(str(origin_desktop_name), 0)
  215. ## wait for first thread to initialize its icon
  216. while not window_info:
  217. time.sleep(1)
  218. ## exit when last tray icon goes away
  219. while window_info:
  220. win32gui.PumpWaitingMessages()
  221. time.sleep(3)