From 51fe663a47c4ad4d36dcd316495c58213e501785 Mon Sep 17 00:00:00 2001 From: Kat Inskip Date: Sat, 17 Feb 2024 14:28:02 -0800 Subject: [PATCH] feat: add pystray for hyprland --- konawall/environments/hyprland.py | 1 + konawall/gui.py | 36 ++++++++++++++++++++++--------- package.nix | 15 +++++++++++-- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/konawall/environments/hyprland.py b/konawall/environments/hyprland.py index 846fadc..dd18434 100644 --- a/konawall/environments/hyprland.py +++ b/konawall/environments/hyprland.py @@ -1,5 +1,6 @@ import subprocess import dbus +import time from konawall.module_loader import add_environment @add_environment("hyprland_setter") diff --git a/konawall/gui.py b/konawall/gui.py index 3764479..f81eaba 100755 --- a/konawall/gui.py +++ b/konawall/gui.py @@ -19,9 +19,9 @@ class Konawall(wx.adv.TaskBarIcon): def __init__(self, version, file_logger): super().__init__() # Prevents it from closing before it has done any work on macOS - #if wx.Platform == "__WXMAC__" or wx.Platform == "__WXGTK__": - self.hidden_frame = wx.Frame(None) - self.hidden_frame.Hide() + if wx.Platform == "__WXMAC__" or wx.Platform == "__WXGTK__": + self.hidden_frame = wx.Frame(None) + self.hidden_frame.Hide() self.wallpaper_rotation_counter = 0 self.file_logger = file_logger @@ -61,6 +61,15 @@ class Konawall(wx.adv.TaskBarIcon): # Set up the taskbar icon, menu, bindings, ... icon = self.generate_icon() self.SetIcon(icon, self.title_string) + if self.environment == "hyprland": + import pystray + def setup(self): + self.visible = True + self.external_icon = pystray.Icon("Konawall - {version}", icon=self.generate_icon_bitmap(), menu=pystray.Menu( + pystray.MenuItem("Rotate", self.rotate_wallpapers), + pystray.MenuItem("Toggle Rotation", self.toggle_timed_wallpaper_rotation, checked=lambda item: self.rotate) + )) + self.external_icon.run(setup) self.hidden_frame.SetIcon(icon) self.create_menu() self.create_bindings() @@ -69,7 +78,7 @@ class Konawall(wx.adv.TaskBarIcon): self.rotate_wallpapers(None) # wxPython requires a wx.Bitmap, so we generate one from a PIL.Image - def generate_icon(self): + def generate_icon_bitmap(self): width = 128 height = 128 @@ -79,7 +88,10 @@ class Konawall(wx.adv.TaskBarIcon): image = image.resize((16, 16)) elif "wxGTK" in wx.PlatformInfo: image = image.resize((22, 22)) + return image + def generate_icon(self): + image = self.generate_icon_bitmap() # Write image to temporary file temp = tempfile.NamedTemporaryFile(suffix=".png", delete=False) image.save(temp.name) @@ -87,7 +99,7 @@ class Konawall(wx.adv.TaskBarIcon): # Convert to wxPython icon icon = wx.Icon() icon.CopyFromBitmap(wx.Bitmap(temp.name)) - return icon + return icon def toggle_timed_wallpaper_rotation_status(self): return f"{'Dis' if self.rotate else 'En'}able Timer" @@ -263,13 +275,14 @@ class Konawall(wx.adv.TaskBarIcon): # Update the menu item of the current interval display to read correctly def respect_current_interval_status(self): - self.current_interval_menu_item.SetItemLabel(f"Rotation interval: {format_timespan(self.interval)}") + if self.IsAvailable: + self.current_interval_menu_item.SetItemLabel(f"Rotation interval: {format_timespan(self.interval)}") # Set whether to rotate wallpapers automatically or not def toggle_timed_wallpaper_rotation(self, event): self.rotate = not self.rotate self.respect_timed_wallpaper_rotation_toggle() - + # Update the timer and the menu item to reflect our current state def respect_timed_wallpaper_rotation_toggle(self): if self.rotate and not self.wallpaper_rotation_timer.IsRunning(): @@ -277,14 +290,17 @@ class Konawall(wx.adv.TaskBarIcon): elif not self.rotate and self.wallpaper_rotation_timer.IsRunning(): self.wallpaper_rotation_timer.Stop() # Set the time left counter to show that it is disabled - self.timed_wallpaper_rotation_status_menu_item.SetItemLabel(f"Automatic wallpaper rotation disabled") + if self.IsAvailable: + self.current_interval_menu_item.SetItemLabel(f"Automatic wallpaper rotation disabled") # Update the menu item for the toggle - self.toggle_wallpaper_rotation_menu_item.SetItemLabel(self.toggle_timed_wallpaper_rotation_status()) + if self.IsAvailable: + self.toggle_wallpaper_rotation_menu_item.SetItemLabel(self.toggle_timed_wallpaper_rotation_status()) # Update wallpaper rotation time left counter def respect_timed_wallpaper_rotation_status(self): - self.timed_wallpaper_rotation_status_menu_item.SetItemLabel(f"Next rotation: {format_timespan(self.interval - self.wallpaper_rotation_counter)} remaining") + if self.IsAvailable: + self.timed_wallpaper_rotation_status_menu_item.SetItemLabel(f"Next rotation: {format_timespan(self.interval - self.wallpaper_rotation_counter)} remaining") # Perform the purpose of the application; get new wallpaper media and set 'em. def rotate_wallpapers(self, event): diff --git a/package.nix b/package.nix index 5ce44aa..f99afe6 100644 --- a/package.nix +++ b/package.nix @@ -2,7 +2,11 @@ lib, buildPythonPackage, python311Packages, - psmisc + psmisc, + gobject-introspection, + gtk3, + dbus-python, + wrapGAppsHook, }: let pyproject = builtins.fromTOML (builtins.readFile ./pyproject.toml); poetryBlock = pyproject.tool.poetry; @@ -18,12 +22,19 @@ in doCheck = false; + nativeBuildInputs = [ + wrapGAppsHook + gobject-introspection + ]; + propagatedBuildInputs = let - dependencyNames = (lib.attrNames poetryBlock.dependencies) ++ ["dbus-python"]; + dependencyNames = (lib.attrNames poetryBlock.dependencies) ++ ["setuptools" "pygobject3" "pystray" "dbus-python"]; dependencies = map (name: python311Packages.${name} or dependencyReplacements.${name}) dependencyNames; in dependencies ++ [ psmisc + gtk3 + dbus-python ]; meta = with lib; {