Collection of tools useful for audio production
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.

679 lines
23KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # KDE, App-Indicator or Qt Systray
  4. # Copyright (C) 2011-2018 Filipe Coelho <falktx@falktx.com>
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # For a full copy of the GNU General Public License see the COPYING file
  17. # Imports (Global)
  18. import os, sys
  19. if True:
  20. from PyQt5.QtCore import QTimer
  21. from PyQt5.QtGui import QIcon
  22. from PyQt5.QtWidgets import QAction, QMainWindow, QMenu, QSystemTrayIcon
  23. else:
  24. from PyQt4.QtCore import QTimer
  25. from PyQt4.QtGui import QIcon
  26. from PyQt4.QtGui import QAction, QMainWindow, QMenu, QSystemTrayIcon
  27. try:
  28. if os.getenv("DESKTOP_SESSION") in ("ubuntu", "ubuntu-2d") and not os.path.exists("/var/cadence/no_app_indicators"):
  29. from gi.repository import Gtk, AppIndicator3 as AppIndicator
  30. TrayEngine = "AppIndicator"
  31. elif os.getenv("KDE_SESSION_VERSION") >= 5:
  32. TrayEngine = "Qt"
  33. elif os.getenv("KDE_FULL_SESSION") or os.getenv("DESKTOP_SESSION") == "kde-plasma":
  34. from PyKDE5.kdeui import KAction, KIcon, KMenu, KStatusNotifierItem
  35. TrayEngine = "KDE"
  36. else:
  37. TrayEngine = "Qt"
  38. except:
  39. TrayEngine = "Qt"
  40. print("Using Tray Engine '%s'" % TrayEngine)
  41. iActNameId = 0
  42. iActWidget = 1
  43. iActParentMenuId = 2
  44. iActFunc = 3
  45. iSepNameId = 0
  46. iSepWidget = 1
  47. iSepParentMenuId = 2
  48. iMenuNameId = 0
  49. iMenuWidget = 1
  50. iMenuParentMenuId = 2
  51. # Get Icon from user theme, using our own as backup (Oxygen)
  52. def getIcon(icon, size=16):
  53. return QIcon.fromTheme(icon, QIcon(":/%ix%i/%s.png" % (size, size, icon)))
  54. # Global Systray class
  55. class GlobalSysTray(object):
  56. def __init__(self, parent, name, icon):
  57. object.__init__(self)
  58. self._app = None
  59. self._parent = parent
  60. self._gtk_running = False
  61. self._quit_added = False
  62. self.act_indexes = []
  63. self.sep_indexes = []
  64. self.menu_indexes = []
  65. if TrayEngine == "KDE":
  66. self.menu = KMenu(parent)
  67. self.menu.setTitle(name)
  68. self.tray = KStatusNotifierItem()
  69. self.tray.setAssociatedWidget(parent)
  70. self.tray.setCategory(KStatusNotifierItem.ApplicationStatus)
  71. self.tray.setContextMenu(self.menu)
  72. self.tray.setIconByPixmap(getIcon(icon))
  73. self.tray.setTitle(name)
  74. self.tray.setToolTipTitle(" ")
  75. self.tray.setToolTipIconByPixmap(getIcon(icon))
  76. # Double-click is managed by KDE
  77. elif TrayEngine == "AppIndicator":
  78. self.menu = Gtk.Menu()
  79. self.tray = AppIndicator.Indicator.new(name, icon, AppIndicator.IndicatorCategory.APPLICATION_STATUS)
  80. self.tray.set_menu(self.menu)
  81. # Double-click is not possible with App-Indicators
  82. elif TrayEngine == "Qt":
  83. self.menu = QMenu(parent)
  84. self.tray = QSystemTrayIcon(getIcon(icon))
  85. self.tray.setContextMenu(self.menu)
  86. self.tray.setParent(parent)
  87. self.tray.activated.connect(self.qt_systray_clicked)
  88. # -------------------------------------------------------------------------------------------
  89. def addAction(self, act_name_id, act_name_string, is_check=False):
  90. if TrayEngine == "KDE":
  91. act_widget = KAction(act_name_string, self.menu)
  92. act_widget.setCheckable(is_check)
  93. self.menu.addAction(act_widget)
  94. elif TrayEngine == "AppIndicator":
  95. if is_check:
  96. act_widget = Gtk.CheckMenuItem(act_name_string)
  97. else:
  98. act_widget = Gtk.ImageMenuItem(act_name_string)
  99. act_widget.set_image(None)
  100. act_widget.show()
  101. self.menu.append(act_widget)
  102. elif TrayEngine == "Qt":
  103. act_widget = QAction(act_name_string, self.menu)
  104. act_widget.setCheckable(is_check)
  105. self.menu.addAction(act_widget)
  106. else:
  107. act_widget = None
  108. act_obj = [None, None, None, None]
  109. act_obj[iActNameId] = act_name_id
  110. act_obj[iActWidget] = act_widget
  111. self.act_indexes.append(act_obj)
  112. def addSeparator(self, sep_name_id):
  113. if TrayEngine == "KDE":
  114. sep_widget = self.menu.addSeparator()
  115. elif TrayEngine == "AppIndicator":
  116. sep_widget = Gtk.SeparatorMenuItem()
  117. sep_widget.show()
  118. self.menu.append(sep_widget)
  119. elif TrayEngine == "Qt":
  120. sep_widget = self.menu.addSeparator()
  121. else:
  122. sep_widget = None
  123. sep_obj = [None, None, None]
  124. sep_obj[iSepNameId] = sep_name_id
  125. sep_obj[iSepWidget] = sep_widget
  126. self.sep_indexes.append(sep_obj)
  127. def addMenu(self, menu_name_id, menu_name_string):
  128. if TrayEngine == "KDE":
  129. menu_widget = KMenu(menu_name_string, self.menu)
  130. self.menu.addMenu(menu_widget)
  131. elif TrayEngine == "AppIndicator":
  132. menu_widget = Gtk.MenuItem(menu_name_string)
  133. menu_parent = Gtk.Menu()
  134. menu_widget.set_submenu(menu_parent)
  135. menu_widget.show()
  136. self.menu.append(menu_widget)
  137. elif TrayEngine == "Qt":
  138. menu_widget = QMenu(menu_name_string, self.menu)
  139. self.menu.addMenu(menu_widget)
  140. else:
  141. menu_widget = None
  142. menu_obj = [None, None, None]
  143. menu_obj[iMenuNameId] = menu_name_id
  144. menu_obj[iMenuWidget] = menu_widget
  145. self.menu_indexes.append(menu_obj)
  146. # -------------------------------------------------------------------------------------------
  147. def addMenuAction(self, menu_name_id, act_name_id, act_name_string, is_check=False):
  148. i = self.get_menu_index(menu_name_id)
  149. if i < 0: return
  150. menu_widget = self.menu_indexes[i][iMenuWidget]
  151. if TrayEngine == "KDE":
  152. act_widget = KAction(act_name_string, menu_widget)
  153. act_widget.setCheckable(is_check)
  154. menu_widget.addAction(act_widget)
  155. elif TrayEngine == "AppIndicator":
  156. menu_widget = menu_widget.get_submenu()
  157. if is_check:
  158. act_widget = Gtk.CheckMenuItem(act_name_string)
  159. else:
  160. act_widget = Gtk.ImageMenuItem(act_name_string)
  161. act_widget.set_image(None)
  162. act_widget.show()
  163. menu_widget.append(act_widget)
  164. elif TrayEngine == "Qt":
  165. act_widget = QAction(act_name_string, menu_widget)
  166. act_widget.setCheckable(is_check)
  167. menu_widget.addAction(act_widget)
  168. else:
  169. act_widget = None
  170. act_obj = [None, None, None, None]
  171. act_obj[iActNameId] = act_name_id
  172. act_obj[iActWidget] = act_widget
  173. act_obj[iActParentMenuId] = menu_name_id
  174. self.act_indexes.append(act_obj)
  175. def addMenuSeparator(self, menu_name_id, sep_name_id):
  176. i = self.get_menu_index(menu_name_id)
  177. if i < 0: return
  178. menu_widget = self.menu_indexes[i][iMenuWidget]
  179. if TrayEngine == "KDE":
  180. sep_widget = menu_widget.addSeparator()
  181. elif TrayEngine == "AppIndicator":
  182. menu_widget = menu_widget.get_submenu()
  183. sep_widget = Gtk.SeparatorMenuItem()
  184. sep_widget.show()
  185. menu_widget.append(sep_widget)
  186. elif TrayEngine == "Qt":
  187. sep_widget = menu_widget.addSeparator()
  188. else:
  189. sep_widget = None
  190. sep_obj = [None, None, None]
  191. sep_obj[iSepNameId] = sep_name_id
  192. sep_obj[iSepWidget] = sep_widget
  193. sep_obj[iSepParentMenuId] = menu_name_id
  194. self.sep_indexes.append(sep_obj)
  195. #def addSubMenu(self, menu_name_id, new_menu_name_id, new_menu_name_string):
  196. #menu_index = self.get_menu_index(menu_name_id)
  197. #if menu_index < 0: return
  198. #menu_widget = self.menu_indexes[menu_index][1]
  199. ##if TrayEngine == "KDE":
  200. ##new_menu_widget = KMenu(new_menu_name_string, self.menu)
  201. ##menu_widget.addMenu(new_menu_widget)
  202. ##elif TrayEngine == "AppIndicator":
  203. ##new_menu_widget = Gtk.MenuItem(new_menu_name_string)
  204. ##new_menu_widget.show()
  205. ##menu_widget.get_submenu().append(new_menu_widget)
  206. ##parent_menu_widget = Gtk.Menu()
  207. ##new_menu_widget.set_submenu(parent_menu_widget)
  208. ##else:
  209. #if (1):
  210. #new_menu_widget = QMenu(new_menu_name_string, self.menu)
  211. #menu_widget.addMenu(new_menu_widget)
  212. #self.menu_indexes.append([new_menu_name_id, new_menu_widget, menu_name_id])
  213. # -------------------------------------------------------------------------------------------
  214. def connect(self, act_name_id, act_func):
  215. i = self.get_act_index(act_name_id)
  216. if i < 0: return
  217. act_widget = self.act_indexes[i][iActWidget]
  218. if TrayEngine == "AppIndicator":
  219. act_widget.connect("activate", self.gtk_call_func, act_name_id)
  220. elif TrayEngine in ("KDE", "Qt"):
  221. act_widget.triggered.connect(act_func)
  222. self.act_indexes[i][iActFunc] = act_func
  223. # -------------------------------------------------------------------------------------------
  224. #def setActionChecked(self, act_name_id, yesno):
  225. #index = self.get_act_index(act_name_id)
  226. #if index < 0: return
  227. #act_widget = self.act_indexes[index][1]
  228. ##if TrayEngine == "KDE":
  229. ##act_widget.setChecked(yesno)
  230. ##elif TrayEngine == "AppIndicator":
  231. ##if type(act_widget) != Gtk.CheckMenuItem:
  232. ##return # Cannot continue
  233. ##act_widget.set_active(yesno)
  234. ##else:
  235. #if (1):
  236. #act_widget.setChecked(yesno)
  237. def setActionEnabled(self, act_name_id, yesno):
  238. i = self.get_act_index(act_name_id)
  239. if i < 0: return
  240. act_widget = self.act_indexes[i][iActWidget]
  241. if TrayEngine == "KDE":
  242. act_widget.setEnabled(yesno)
  243. elif TrayEngine == "AppIndicator":
  244. act_widget.set_sensitive(yesno)
  245. elif TrayEngine == "Qt":
  246. act_widget.setEnabled(yesno)
  247. def setActionIcon(self, act_name_id, icon):
  248. i = self.get_act_index(act_name_id)
  249. if i < 0: return
  250. act_widget = self.act_indexes[i][iActWidget]
  251. if TrayEngine == "KDE":
  252. act_widget.setIcon(KIcon(icon))
  253. elif TrayEngine == "AppIndicator":
  254. if not isinstance(act_widget, Gtk.ImageMenuItem):
  255. # Cannot use icons here
  256. return
  257. act_widget.set_image(Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.MENU))
  258. #act_widget.set_always_show_image(True)
  259. elif TrayEngine == "Qt":
  260. act_widget.setIcon(getIcon(icon))
  261. def setActionText(self, act_name_id, text):
  262. i = self.get_act_index(act_name_id)
  263. if i < 0: return
  264. act_widget = self.act_indexes[i][iActWidget]
  265. if TrayEngine == "KDE":
  266. act_widget.setText(text)
  267. elif TrayEngine == "AppIndicator":
  268. if isinstance(act_widget, Gtk.ImageMenuItem):
  269. # Fix icon reset
  270. last_icon = act_widget.get_image()
  271. act_widget.set_label(text)
  272. act_widget.set_image(last_icon)
  273. else:
  274. act_widget.set_label(text)
  275. elif TrayEngine == "Qt":
  276. act_widget.setText(text)
  277. def setIcon(self, icon):
  278. if TrayEngine == "KDE":
  279. self.tray.setIconByPixmap(getIcon(icon))
  280. #self.tray.setToolTipIconByPixmap(getIcon(icon))
  281. elif TrayEngine == "AppIndicator":
  282. self.tray.set_icon(icon)
  283. elif TrayEngine == "Qt":
  284. self.tray.setIcon(getIcon(icon))
  285. def setToolTip(self, text):
  286. if TrayEngine == "KDE":
  287. self.tray.setToolTipSubTitle(text)
  288. elif TrayEngine == "AppIndicator":
  289. # ToolTips are disabled in App-Indicators by design
  290. pass
  291. elif TrayEngine == "Qt":
  292. self.tray.setToolTip(text)
  293. # -------------------------------------------------------------------------------------------
  294. #def removeAction(self, act_name_id):
  295. #index = self.get_act_index(act_name_id)
  296. #if index < 0: return
  297. #act_widget = self.act_indexes[index][1]
  298. #parent_menu_widget = self.get_parent_menu_widget(self.act_indexes[index][2])
  299. ##if TrayEngine == "KDE":
  300. ##parent_menu_widget.removeAction(act_widget)
  301. ##elif TrayEngine == "AppIndicator":
  302. ##act_widget.hide()
  303. ##parent_menu_widget.remove(act_widget)
  304. ##else:
  305. #if (1):
  306. #parent_menu_widget.removeAction(act_widget)
  307. #self.act_indexes.pop(index)
  308. #def removeSeparator(self, sep_name_id):
  309. #index = self.get_sep_index(sep_name_id)
  310. #if index < 0: return
  311. #sep_widget = self.sep_indexes[index][1]
  312. #parent_menu_widget = self.get_parent_menu_widget(self.sep_indexes[index][2])
  313. ##if TrayEngine == "KDE":
  314. ##parent_menu_widget.removeAction(sep_widget)
  315. ##elif TrayEngine == "AppIndicator":
  316. ##sep_widget.hide()
  317. ##parent_menu_widget.remove(sep_widget)
  318. ##else:
  319. #if (1):
  320. #parent_menu_widget.removeAction(sep_widget)
  321. #self.sep_indexes.pop(index)
  322. #def removeMenu(self, menu_name_id):
  323. #index = self.get_menu_index(menu_name_id)
  324. #if index < 0: return
  325. #menu_widget = self.menu_indexes[index][1]
  326. #parent_menu_widget = self.get_parent_menu_widget(self.menu_indexes[index][2])
  327. ##if TrayEngine == "KDE":
  328. ##parent_menu_widget.removeAction(menu_widget.menuAction())
  329. ##elif TrayEngine == "AppIndicator":
  330. ##menu_widget.hide()
  331. ##parent_menu_widget.remove(menu_widget.get_submenu())
  332. ##else:
  333. #if (1):
  334. #parent_menu_widget.removeAction(menu_widget.menuAction())
  335. #self.remove_actions_by_menu_name_id(menu_name_id)
  336. #self.remove_separators_by_menu_name_id(menu_name_id)
  337. #self.remove_submenus_by_menu_name_id(menu_name_id)
  338. # -------------------------------------------------------------------------------------------
  339. #def clearAll(self):
  340. ##if TrayEngine == "KDE":
  341. ##self.menu.clear()
  342. ##elif TrayEngine == "AppIndicator":
  343. ##for child in self.menu.get_children():
  344. ##self.menu.remove(child)
  345. ##else:
  346. #if (1):
  347. #self.menu.clear()
  348. #self.act_indexes = []
  349. #self.sep_indexes = []
  350. #self.menu_indexes = []
  351. #def clearMenu(self, menu_name_id):
  352. #menu_index = self.get_menu_index(menu_name_id)
  353. #if menu_index < 0: return
  354. #menu_widget = self.menu_indexes[menu_index][1]
  355. ##if TrayEngine == "KDE":
  356. ##menu_widget.clear()
  357. ##elif TrayEngine == "AppIndicator":
  358. ##for child in menu_widget.get_submenu().get_children():
  359. ##menu_widget.get_submenu().remove(child)
  360. ##else:
  361. #if (1):
  362. #menu_widget.clear()
  363. #list_of_submenus = [menu_name_id]
  364. #for x in range(0, 10): # 10x level deep, should cover all cases...
  365. #for this_menu_name_id, menu_widget, parent_menu_id in self.menu_indexes:
  366. #if parent_menu_id in list_of_submenus and this_menu_name_id not in list_of_submenus:
  367. #list_of_submenus.append(this_menu_name_id)
  368. #for this_menu_name_id in list_of_submenus:
  369. #self.remove_actions_by_menu_name_id(this_menu_name_id)
  370. #self.remove_separators_by_menu_name_id(this_menu_name_id)
  371. #self.remove_submenus_by_menu_name_id(this_menu_name_id)
  372. # -------------------------------------------------------------------------------------------
  373. def getTrayEngine(self):
  374. return TrayEngine
  375. def isTrayAvailable(self):
  376. if TrayEngine in ("KDE", "Qt"):
  377. # Ask Qt
  378. return QSystemTrayIcon.isSystemTrayAvailable()
  379. if TrayEngine == "AppIndicator":
  380. # Ubuntu/Unity always has a systray
  381. return True
  382. return False
  383. def handleQtCloseEvent(self, event):
  384. if self.isTrayAvailable() and self._parent.isVisible():
  385. event.accept()
  386. self.__hideShowCall()
  387. return
  388. self.close()
  389. QMainWindow.closeEvent(self._parent, event)
  390. # -------------------------------------------------------------------------------------------
  391. def show(self):
  392. if not self._quit_added:
  393. self._quit_added = True
  394. if TrayEngine != "KDE":
  395. self.addSeparator("_quit")
  396. self.addAction("show", self._parent.tr("Minimize"))
  397. self.addAction("quit", self._parent.tr("Quit"))
  398. self.setActionIcon("quit", "application-exit")
  399. self.connect("show", self.__hideShowCall)
  400. self.connect("quit", self.__quitCall)
  401. if TrayEngine == "KDE":
  402. self.tray.setStatus(KStatusNotifierItem.Active)
  403. elif TrayEngine == "AppIndicator":
  404. self.tray.set_status(AppIndicator.IndicatorStatus.ACTIVE)
  405. elif TrayEngine == "Qt":
  406. self.tray.show()
  407. def hide(self):
  408. if TrayEngine == "KDE":
  409. self.tray.setStatus(KStatusNotifierItem.Passive)
  410. elif TrayEngine == "AppIndicator":
  411. self.tray.set_status(AppIndicator.IndicatorStatus.PASSIVE)
  412. elif TrayEngine == "Qt":
  413. self.tray.hide()
  414. def close(self):
  415. if TrayEngine == "KDE":
  416. self.menu.close()
  417. elif TrayEngine == "AppIndicator":
  418. if self._gtk_running:
  419. self._gtk_running = False
  420. Gtk.main_quit()
  421. elif TrayEngine == "Qt":
  422. self.menu.close()
  423. def exec_(self, app):
  424. self._app = app
  425. if TrayEngine == "AppIndicator":
  426. self._gtk_running = True
  427. return Gtk.main()
  428. else:
  429. return app.exec_()
  430. # -------------------------------------------------------------------------------------------
  431. def get_act_index(self, act_name_id):
  432. for i in range(len(self.act_indexes)):
  433. if self.act_indexes[i][iActNameId] == act_name_id:
  434. return i
  435. else:
  436. print("systray.py - Failed to get action index for %s" % act_name_id)
  437. return -1
  438. def get_sep_index(self, sep_name_id):
  439. for i in range(len(self.sep_indexes)):
  440. if self.sep_indexes[i][iSepNameId] == sep_name_id:
  441. return i
  442. else:
  443. print("systray.py - Failed to get separator index for %s" % sep_name_id)
  444. return -1
  445. def get_menu_index(self, menu_name_id):
  446. for i in range(len(self.menu_indexes)):
  447. if self.menu_indexes[i][iMenuNameId] == menu_name_id:
  448. return i
  449. else:
  450. print("systray.py - Failed to get menu index for %s" % menu_name_id)
  451. return -1
  452. #def get_parent_menu_widget(self, parent_menu_id):
  453. #if parent_menu_id != None:
  454. #menu_index = self.get_menu_index(parent_menu_id)
  455. #if menu_index >= 0:
  456. #return self.menu_indexes[menu_index][1]
  457. #else:
  458. #print("systray.py::Failed to get parent Menu widget for", parent_menu_id)
  459. #return None
  460. #else:
  461. #return self.menu
  462. #def remove_actions_by_menu_name_id(self, menu_name_id):
  463. #h = 0
  464. #for i in range(len(self.act_indexes)):
  465. #act_name_id, act_widget, parent_menu_id, act_func = self.act_indexes[i - h]
  466. #if parent_menu_id == menu_name_id:
  467. #self.act_indexes.pop(i - h)
  468. #h += 1
  469. #def remove_separators_by_menu_name_id(self, menu_name_id):
  470. #h = 0
  471. #for i in range(len(self.sep_indexes)):
  472. #sep_name_id, sep_widget, parent_menu_id = self.sep_indexes[i - h]
  473. #if parent_menu_id == menu_name_id:
  474. #self.sep_indexes.pop(i - h)
  475. #h += 1
  476. #def remove_submenus_by_menu_name_id(self, submenu_name_id):
  477. #h = 0
  478. #for i in range(len(self.menu_indexes)):
  479. #menu_name_id, menu_widget, parent_menu_id = self.menu_indexes[i - h]
  480. #if parent_menu_id == submenu_name_id:
  481. #self.menu_indexes.pop(i - h)
  482. #h += 1
  483. # -------------------------------------------------------------------------------------------
  484. def gtk_call_func(self, gtkmenu, act_name_id):
  485. i = self.get_act_index(act_name_id)
  486. if i < 0: return None
  487. return self.act_indexes[i][iActFunc]
  488. def qt_systray_clicked(self, reason):
  489. if reason in (QSystemTrayIcon.DoubleClick, QSystemTrayIcon.Trigger):
  490. self.__hideShowCall()
  491. # -------------------------------------------------------------------------------------------
  492. def __hideShowCall(self):
  493. if self._parent.isVisible():
  494. self.setActionText("show", self._parent.tr("Restore"))
  495. self._parent.hide()
  496. if self._app:
  497. self._app.setQuitOnLastWindowClosed(False)
  498. else:
  499. self.setActionText("show", self._parent.tr("Minimize"))
  500. if self._parent.isMaximized():
  501. self._parent.showMaximized()
  502. else:
  503. self._parent.showNormal()
  504. if self._app:
  505. self._app.setQuitOnLastWindowClosed(True)
  506. QTimer.singleShot(500, self.__raiseWindow)
  507. def __quitCall(self):
  508. if self._app:
  509. self._app.setQuitOnLastWindowClosed(True)
  510. self._parent.hide()
  511. self._parent.close()
  512. def __raiseWindow(self):
  513. self._parent.activateWindow()
  514. self._parent.raise_()
  515. #--------------- main ------------------
  516. if __name__ == '__main__':
  517. from PyQt5.QtWidgets import QApplication, QDialog, QMessageBox
  518. class ExampleGUI(QDialog):
  519. def __init__(self, parent=None):
  520. QDialog.__init__(self, parent)
  521. self.setWindowIcon(getIcon("audacity"))
  522. self.systray = GlobalSysTray(self, "Claudia", "claudia")
  523. self.systray.addAction("about", self.tr("About"))
  524. self.systray.setIcon("audacity")
  525. self.systray.setToolTip("Demo systray app")
  526. self.systray.connect("about", self.about)
  527. self.systray.show()
  528. def about(self):
  529. QMessageBox.about(self, self.tr("About"), self.tr("Systray Demo"))
  530. def done(self, r):
  531. QDialog.done(self, r)
  532. self.close()
  533. def closeEvent(self, event):
  534. self.systray.close()
  535. QDialog.closeEvent(self, event)
  536. app = QApplication(sys.argv)
  537. gui = ExampleGUI()
  538. gui.show()
  539. sys.exit(gui.systray.exec_(app))