From f8c0dba1ee316b0b93f322422ec19db47cfb8ba6 Mon Sep 17 00:00:00 2001 From: guihkx <626206+guihkx@users.noreply.github.com> Date: Sun, 4 Jun 2023 02:05:37 -0300 Subject: [PATCH] Use icon.visible to show or hide the tray icon on all systems On Linux, pystray's icon.stop() currently doesn't work well with the AppIndicator backend. So, instead of destroying the icon when the user restores from tray (only to later re-create it when the user minimizes to tray again), we have the option to control the icon's visibility instead! Luckily, that works on Windows too! Note that for this change to work properly on Linux, we need to switch to the master version of pystray, because we need this specific fix: https://github.com/moses-palmer/pystray/commit/5943ed4e19be48224cf39b70444de8ffe22c23ce After pystray releases a version newer than 0.19.4, we can switch back. Co-authored-by: DevilXD --- gui.py | 48 ++++++++++++++++++++++++------------------------ requirements.txt | 3 ++- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/gui.py b/gui.py index fd7eea2..1bfb1d0 100644 --- a/gui.py +++ b/gui.py @@ -1048,11 +1048,9 @@ class TrayIcon: self._button.grid(column=0, row=0, sticky="ne") def __del__(self) -> None: + self.stop() self.icon_image.close() - def is_tray(self) -> bool: - return self.icon is not None - def get_title(self, drop: TimedDrop | None) -> str: if drop is None: return self.TITLE @@ -1064,23 +1062,22 @@ class TrayIcon: f"{drop.progress:.1%} ({campaign.claimed_drops}/{campaign.total_drops})" ) - def start(self): - if self.icon is None: - loop = asyncio.get_running_loop() - drop = self._manager.progress._drop + def _start(self): + loop = asyncio.get_running_loop() + drop = self._manager.progress._drop - # we need this because tray icon lives in a separate thread - def bridge(func): - return lambda: loop.call_soon_threadsafe(func) + # we need this because tray icon lives in a separate thread + def bridge(func): + return lambda: loop.call_soon_threadsafe(func) - menu = pystray.Menu( - pystray.MenuItem(_("gui", "tray", "show"), bridge(self.restore), default=True), - pystray.Menu.SEPARATOR, - pystray.MenuItem(_("gui", "tray", "quit"), bridge(self.quit)), - ) - self.icon = pystray.Icon("twitch_miner", self.icon_image, self.get_title(drop), menu) - # self.icon.run_detached() - loop.run_in_executor(None, self.icon.run) + menu = pystray.Menu( + pystray.MenuItem(_("gui", "tray", "show"), bridge(self.restore), default=True), + pystray.Menu.SEPARATOR, + pystray.MenuItem(_("gui", "tray", "quit"), bridge(self.quit)), + ) + self.icon = pystray.Icon("twitch_miner", self.icon_image, self.get_title(drop), menu) + # self.icon.run_detached() + loop.run_in_executor(None, self.icon.run) def stop(self): if self.icon is not None: @@ -1091,13 +1088,16 @@ class TrayIcon: self._manager.close() def minimize(self): - if not self.is_tray(): - self.start() - self._manager._root.withdraw() + if self.icon is None: + self._start() + else: + self.icon.visible = True + self._manager._root.withdraw() def restore(self): - if self.is_tray(): - self.stop() + if self.icon is not None: + # self.stop() + self.icon.visible = False self._manager._root.deiconify() def notify( @@ -1107,7 +1107,7 @@ class TrayIcon: if not self._manager._twitch.settings.tray_notifications: return None if self.icon is not None: - icon = self.icon + icon = self.icon # nonlocal scope bind async def notifier(): icon.notify(message, title) diff --git a/requirements.txt b/requirements.txt index fffb45f..3708b68 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ aiohttp>2.0,<4.0 Pillow -pystray +# TODO: switch back to a stable pystray release when a version newer than v0.19.4 is out +pystray@git+https://github.com/moses-palmer/pystray.git@903836104f8b1a2979f4fa5a333870ef7b075992 # selenium-wire # undetected-chromedriver # this is installed only on windows