diff --git a/src/meson.build b/src/meson.build index a3dbf9f..e01d828 100644 --- a/src/meson.build +++ b/src/meson.build @@ -39,6 +39,7 @@ varia_sources_window = [ 'window/sidebar.py', 'window/preferences.py', 'window/scheduler.py', + 'window/tray.py' ] varia_sources_download = [ diff --git a/src/variamain.py b/src/variamain.py index 5496a29..b2373cd 100644 --- a/src/variamain.py +++ b/src/variamain.py @@ -23,11 +23,15 @@ from download.listen import listen_to_aria2 from download.scheduler import schedule_downloads +from window.tray import SystemTray + class MainWindow(Adw.ApplicationWindow): def __init__(self, variaapp, appdir, appconf, aria2c_subprocess, aria2cexec, *args, **kwargs): super().__init__(*args, **kwargs) self.set_hide_on_close(True) - self.connect('close-request', self.exitProgram, variaapp, False) + self.connect('close-request', self.exitProgram, variaapp, True) + + self.variaapp = variaapp self.scheduler_currently_downloading = False self.appdir = appdir @@ -87,6 +91,10 @@ def __init__(self, variaapp, appdir, appconf, aria2c_subprocess, aria2cexec, *ar thread = threading.Thread(target=schedule_downloads(self, True)) thread.start() + self.tray = SystemTray(window=self) + thread = threading.Thread(target=self.tray.run()) + thread.start() + # Load incomplete downloads: default_state = {"url": None, "filename": None} @@ -283,6 +291,13 @@ def save_appconf(self): json.dump(self.appconf, f) print("Config saved") + def trayExit(self): + notification = Gio.Notification.new(_("Exiting")) + notification.set_body(_("Exiting Varia.")) + notification.set_title(_("Exit")) + self.variaapp.send_notification(None, notification) + self.exitProgram(self, self.variaapp, False) + def exitProgram(self, app, variaapp, background): if (background == True): self.hide() @@ -323,6 +338,7 @@ def exitProgram(self, app, variaapp, background): GLib.timeout_add(3000, self.aria2c_exiting_check, app, 0, variaapp, exiting_dialog) else: + self.tray.exit() self.destroy() variaapp.quit() @@ -337,6 +353,7 @@ def aria2c_exiting_check(self, app, counter, variaapp, exiting_dialog): if (exiting_dialog is not None): exiting_dialog.destroy() self.destroy() + self.tray.exit() variaapp.quit() for thread in threading.enumerate(): print(thread.name) diff --git a/src/window/tray.py b/src/window/tray.py new file mode 100644 index 0000000..8924265 --- /dev/null +++ b/src/window/tray.py @@ -0,0 +1,42 @@ +from PyQt6.QtGui import QIcon, QAction +from PyQt6.QtWidgets import QApplication, QSystemTrayIcon, QMenu + + +class SystemTray: + def __init__(self, window): + self.app = QApplication([]) + self.app.setQuitOnLastWindowClosed(False) + + self.window = window + self.shown = False + + icon = QIcon.fromTheme("io.github.giantpinkrobots.varia") + + tray = QSystemTrayIcon(icon=icon, parent=self.app) + tray.setVisible(True) + + menu = QMenu() + self.quit_action = QAction("Quit Varia") + self.quit_action.triggered.connect(lambda: self.window.trayExit()) + menu.addAction(self.quit_action) + + tray.activated.connect(lambda: self._toggle_window()) + + tray.setContextMenu(menu) + + def run(self): + if not self.window.appconf["default_mode"] == "background": + self.shown = True + self.window.show() + self.app.exec() + + def exit(self): + self.app.quit() + + def _toggle_window(self): + if not self.shown: + self.window.show() + self.shown = True + else: + self.window.hide() + self.shown = False