From c82c96543b446c8650f5c62dc83b305e2b1729d6 Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 5 Sep 2023 21:16:43 +0900 Subject: [PATCH] Implementing saving for multiple monitors --- README.md | 13 +++++++------ waypaper/__main__.py | 21 ++++++++++++++------- waypaper/app.py | 35 ++++++++++++++--------------------- waypaper/config.py | 43 ++++++++++++++++++++++++++++++++----------- waypaper/displays.py | 44 -------------------------------------------- 5 files changed, 67 insertions(+), 89 deletions(-) delete mode 100644 waypaper/displays.py diff --git a/README.md b/README.md index fb57f11..4f84dc5 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ GUI wallpaper setter for Wayland and Xorg window managers. It works as a fronten ## Features -- GUI wallpaper selection -- Support for GIF animations (with `swww`) - Vim keys -- Works on both Wayland (with `swaybg` or `swww` or `wallutils`) and Xorg (with `feh` or `wallutils`) +- Support for GIF animations (with `swww`) +- Support for multiple monitors (with `swww`) +- Works on both Wayland (with `swww` or `swaybg` or `wallutils`) and Xorg (with `feh` or `wallutils`) - Restores wallpaper at launch of your WM - Caching for fast loading @@ -19,7 +19,7 @@ You need to install at least one of the backends and Waypaper, which works as a ### 1. Install a backend -Install a preferred backend from your package manager: [swaybg](https://github.com/swaywm/swaybg) or [swww](https://github.com/Horus645/swww) on Wayland or [feh](https://github.com/derf/feh) on Xorg or [wallutils](https://github.com/xyproto/wallutils) on both. +Install a preferred backend from your package manager: [swww](https://github.com/Horus645/swww) or [swaybg](https://github.com/swaywm/swaybg) on Wayland or [feh](https://github.com/derf/feh) on Xorg or [wallutils](https://github.com/xyproto/wallutils) on both. ### 2. Install Waypaper @@ -40,7 +40,7 @@ The [waypaper-git](https://aur.archlinux.org/packages/waypaper-git) package is a ### Dependencies -- `swaybg` or `swww` or `feh` or `wallutils` +- `swww` or `swaybg` or `feh` or `wallutils` - gobject python library (it might be called `python-gobject` or `python3-gi` or `python3-gobject` in your package manager.) ## Usage @@ -82,7 +82,8 @@ To restore your wallpaper at launch, add `waypaper --restore` to your startup co - Additional options for ~subfolders~, ~color~, ~sorting~, ~randomizing~ and setting a uniform color. - ~Support for other backends like swww, feh, wallutils~, and maybe hyprpaper. - ~Better keyboard-driven experience and hjkl support.~ -- Support for multiple monitors +- ~Support for multiple monitors with swww~ +- Support for multiple monitors with swaybg - Support for some backend-specific features ## Contributions diff --git a/waypaper/__main__.py b/waypaper/__main__.py index 2da0968..0083dfc 100644 --- a/waypaper/__main__.py +++ b/waypaper/__main__.py @@ -1,3 +1,7 @@ +"""Main module that runs the program and either runs GUI or just changer wallpaper""" + +import time + from waypaper.app import App from waypaper.changer import change_wallpaper from waypaper.config import cf @@ -5,20 +9,23 @@ from waypaper.arguments import args -__version__ = "1.8.2" +__version__ = "1.9" def run(): """Read user arguments and either run GUI app or just reset the wallpaper""" - # Pick random wallpaper: - if args.random: - cf.wallpaper = get_random_file(cf.image_folder, cf.include_subfolders) - # Set the wallpaper and quit: if args.restore: - if cf.wallpaper is not None: - change_wallpaper(cf.wallpaper, cf.fill_option, cf.color, cf.backend, cf.monitor) + for wallpaper, monitor in zip(cf.wallpaper, cf.monitors): + + if args.random: + wallpaper = get_random_file(cf.image_folder, cf.include_subfolders) + + if wallpaper is None: + continue + change_wallpaper(wallpaper, cf.fill_option, cf.color, cf.backend, monitor) + time.sleep(0.1) exit() # Print the version and quit: diff --git a/waypaper/app.py b/waypaper/app.py index 6677b02..4fc4a3a 100644 --- a/waypaper/app.py +++ b/waypaper/app.py @@ -165,7 +165,7 @@ def init_ui(self): def monitor_option_display(self): - """Display monitor option backend is swww""" + """Display monitor option if backend is swww""" self.options_box.remove(self.monitor_option_combo) # if "swww" not in self.missing_backends and cf.backend not in ["wallutils", "feh"]: if cf.backend == "swww": @@ -315,7 +315,6 @@ def choose_folder(self): response = dialog.run() if response == Gtk.ResponseType.OK: cf.image_folder = dialog.get_filename() - cf.save() threading.Thread(target=self.process_images).start() dialog.destroy() @@ -338,7 +337,7 @@ def on_fill_option_changed(self, combo): def on_monitor_option_changed(self, combo): """Save monitor parameter when it was changed""" - cf.monitor = combo.get_active_text() + cf.selected_monitor = combo.get_active_text() def on_sort_option_changed(self, combo): @@ -352,7 +351,7 @@ def on_sort_option_changed(self, combo): def on_backend_option_changed(self, combo): """Save backend parameter whet it is changed""" cf.backend = combo.get_active_text() - cf.monitor = "All" + cf.selected_monitor = "All" self.monitor_option_display() self.show_all() @@ -368,12 +367,12 @@ def on_color_set(self, color_button): def on_image_clicked(self, widget, path): """On clicking an image, set it as a wallpaper and save""" - cf.wallpaper = path + cf.selected_wallpaper = path self.selected_index = self.image_paths.index(path) self.load_image_grid() - print(MSG_PATH, cf.wallpaper) + print(MSG_PATH, cf.selected_wallpaper) cf.fill_option = self.fill_option_combo.get_active_text() or cf.fill_option - change_wallpaper(cf.wallpaper, cf.fill_option, cf.color, cf.backend, cf.monitor) + change_wallpaper(cf.selected_wallpaper, cf.fill_option, cf.color, cf.backend, cf.selected_monitor) cf.save() @@ -389,23 +388,17 @@ def on_random_clicked(self, widget): def on_exit_clicked(self, widget): """On clicking exit button, exit""" - self.exit_app() - - - def exit_app(self): - """Save the data and quit""" - cf.save() Gtk.main_quit() def set_random_wallpaper(self): """Choose a random image and set it as the wallpaper""" - cf.wallpaper = get_random_file(cf.image_folder, cf.include_subfolders) - if cf.wallpaper is None: + cf.selected_wallpaper = get_random_file(cf.image_folder, cf.include_subfolders) + if cf.selected_wallpaper is None: return - print(MSG_PATH, cf.wallpaper) + print(MSG_PATH, cf.selected_wallpaper) cf.fill_option = self.fill_option_combo.get_active_text() or cf.fill_option - change_wallpaper(cf.wallpaper, cf.fill_option, cf.color, cf.backend, cf.monitor) + change_wallpaper(cf.selected_wallpaper, cf.fill_option, cf.color, cf.backend, cf.selected_monitor) cf.save() @@ -423,7 +416,7 @@ def clear_cache(self): def on_key_pressed(self, widget, event): """Process various key bindigns""" if event.keyval == Gdk.KEY_q: - self.exit_app() + Gtk.main_quit() elif event.keyval == Gdk.KEY_r: self.clear_cache() @@ -464,10 +457,10 @@ def on_key_pressed(self, widget, event): elif event.keyval == Gdk.KEY_Return or event.keyval == Gdk.KEY_KP_Enter: wallpaper_path = self.image_paths[self.selected_index] - cf.wallpaper = wallpaper_path - print(MSG_PATH, cf.wallpaper) + cf.selected_wallpaper = wallpaper_path + print(MSG_PATH, cf.selected_wallpaper) cf.fill_option = self.fill_option_combo.get_active_text() or cf.fill_option - change_wallpaper(cf.wallpaper, cf.fill_option, cf.color, cf.backend, cf.monitor) + change_wallpaper(cf.selected_wallpaper, cf.fill_option, cf.color, cf.backend, cf.selected_monitor) cf.save() # Prevent other default key handling: diff --git a/waypaper/config.py b/waypaper/config.py index d129c43..1316cc8 100644 --- a/waypaper/config.py +++ b/waypaper/config.py @@ -14,16 +14,17 @@ def __init__(self): self.image_folder = str(pathlib.Path.home()) if os.path.exists(str(pathlib.Path.home()) + "/Pictures"): self.image_folder = str(pathlib.Path.home()) + "/Pictures" - self.wallpaper = None + self.selected_wallpaper = None + self.selected_monitor = "All" self.fill_option = "fill" self.sort_option = "name" self.backend = "swaybg" self.color = "#ffffff" - self.monitor = "All" - self.is_random = False + self.monitors = [self.selected_monitor] + self.wallpaper = [] self.include_subfolders = False - self.config_folder = str(pathlib.Path.home()) + "/.config/waypaper" - self.config_file = self.config_folder + "/config.ini" + self.config_folder = str(pathlib.Path.home()) + "/.config/waypaper" + self.config_file = self.config_folder + "/config.ini" def create(self): @@ -36,7 +37,8 @@ def create(self): "backend": str(self.backend), "color": str(self.color), "subfolders": str(self.include_subfolders), - "wallpaper": str(self.wallpaper), + "wallpaper": str(self.selected_wallpaper), + "monitors": str(self.selected_monitor), } with open(cf.config_file, "w") as configfile: config.write(configfile) @@ -48,7 +50,6 @@ def read(self): config = configparser.ConfigParser() config.read(self.config_file, 'utf-8') self.image_folder = config.get("Settings", "folder", fallback=self.image_folder) - self.wallpaper = config.get("Settings", "wallpaper", fallback=self.wallpaper) self.fill_option = config.get("Settings", "fill", fallback=self.fill_option) if self.fill_option not in FILL_OPTIONS: self.sort_option = FILL_OPTIONS[0] @@ -58,22 +59,44 @@ def read(self): self.backend = config.get("Settings", "backend", fallback=self.backend) self.color = config.get("Settings", "color", fallback=self.color) self.include_subfolders = config.getboolean("Settings", "subfolders", fallback=self.include_subfolders) + + self.monitors_str = config.get("Settings", "monitors", fallback=self.selected_monitor, raw=True) + if self.monitors_str is not None: + self.monitors = [str(monitor) for monitor in self.monitors_str.split(",")] + + self.wallpaper_str = config.get("Settings", "wallpaper", fallback=self.wallpaper, raw=True) + if self.wallpaper_str is not None: + self.wallpaper = [str(paper) for paper in self.wallpaper_str.split(",")] except Exception as e: print(e) exit() def save(self): - """Save the parameters to the configuration file""" + """Update the parameters and save them to the configuration file""" + + # If only certain monitor was affected, change only its wallpaper: + if self.selected_monitor == "All": + self.monitors = [self.selected_monitor] + self.wallpaper = [self.selected_wallpaper] + elif self.selected_monitor in self.monitors: + index = self.monitors.index(self.selected_monitor) + self.wallpaper[index] = self.selected_wallpaper + else: + self.monitors.append(self.selected_monitor) + self.wallpaper.append(self.selected_wallpaper) + + # Write configuration to the file: config = configparser.ConfigParser() config.read(self.config_file) config.set("Settings", "folder", cf.image_folder) - config.set("Settings", "wallpaper", str(cf.wallpaper)) config.set("Settings", "fill", cf.fill_option) config.set("Settings", "sort", cf.sort_option) config.set("Settings", "backend", cf.backend) config.set("Settings", "color", cf.color) config.set("Settings", "subfolders", str(cf.include_subfolders)) + config.set("Settings", "wallpaper", ",".join(self.wallpaper)) + config.set("Settings", "monitors", ",".join(self.monitors)) with open(cf.config_file, "w") as configfile: config.write(configfile) @@ -84,8 +107,6 @@ def read_parameters_from_user_arguments(self): self.backend = args.backend if args.fill: self.fill_option = args.fill - if args.random: - self.is_random = args.random cf = Config() diff --git a/waypaper/displays.py b/waypaper/displays.py deleted file mode 100644 index 93235ee..0000000 --- a/waypaper/displays.py +++ /dev/null @@ -1,44 +0,0 @@ -"""This module checks avaliable displays depending on the display server""" - -import os - -def detect_display_server(): - if os.environ.get('WAYLAND_DISPLAY'): - return "Wayland" - else: - return "Xorg" - -def get_wayland_displays(): - displays = [] - wayland_socket = os.environ.get('WAYLAND_DISPLAY') - if wayland_socket: - displays.append(f"wayland-{wayland_socket}") - return displays - -def get_xorg_displays(): - displays = [] - xorg_display = os.environ.get('DISPLAY') - if xorg_display: - displays.append(f"xorg-{xorg_display}") - return displays - -def main(display_server): - available_displays = [] - - if display_server.lower() == "wayland": - displays = get_wayland_displays() - else: - displays = get_xorg_displays() - available_displays.extend(displays) - - if not available_displays: - print("No displays found.") - else: - print("Available displays:") - for display in available_displays: - print(display) - -if __name__ == "__main__": - display_server = detect_display_server() - print(f"The system is running under: {display_server}") - main(display_server)