mirror of
https://github.com/anufrievroman/waypaper.git
synced 2024-10-26 10:58:28 +03:00
Compare commits
3 Commits
8518e1e814
...
07ee2da7c1
Author | SHA1 | Date | |
---|---|---|---|
|
07ee2da7c1 | ||
|
e78289d878 | ||
|
f7235f551f |
11
README.md
11
README.md
@ -12,7 +12,7 @@ GUI wallpaper setter for Wayland and Xorg window managers. It works as a fronten
|
||||
- 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
|
||||
- Translated in en, fr, de, ru, pl
|
||||
- Translated in en, fr, de, ru, pl, zh
|
||||
|
||||
## Installation
|
||||
|
||||
@ -86,15 +86,12 @@ If you wish to change language, change `laguage` variable in `.config/waypaper/c
|
||||
|
||||
## Roadmap
|
||||
|
||||
- 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 with swww~ and swaybg
|
||||
- Possible support for other backends like mpvpaper, and maybe hyprpaper.
|
||||
- Support for various `swww` options
|
||||
- Display animated previews of gif wallpapers
|
||||
- Translations
|
||||
|
||||
## Contributions
|
||||
|
||||
Feel free to propose PR and suggest the improvements. I'll also appreciate any help with packaging for various distributions. Also, if you wish to contribute with translation into your language, plese translate `translation_en.py` file, and I'll do the rest.
|
||||
Feel free to propose PR and suggest the improvements. I'll highly appreciate help with packaging for various distributions. If you wish to contribute with translation into your language, please see the `translations.py` file.
|
||||
|
||||
If you'd like to support the development, consider [donations](https://www.buymeacoffee.com/angryprofessor).
|
||||
|
41
data/waypaper.1.gz
Normal file
41
data/waypaper.1.gz
Normal file
@ -0,0 +1,41 @@
|
||||
.TH WAYPAPER 2024-01-01
|
||||
.nh
|
||||
.SH NAME
|
||||
waypaper \- GUI wallpaper manager for Wayland and X11
|
||||
.SH SYNOPSIS
|
||||
.B waypaper
|
||||
[ \fIOPTION\fR ]
|
||||
.SH DESCRIPTION
|
||||
.B Waypaper
|
||||
is a TUI wallpaper setter for Wayland and Xorg window managers. It works as a frontend for popular wallpaper backends like swaybg, swww, wallutils and feh. \fIhttps://anufrievroman.gitbook.com/waypaper \fR
|
||||
.SH OPTIONS
|
||||
|
||||
.TP
|
||||
\fB\-v \fP
|
||||
Print version.
|
||||
|
||||
.TP
|
||||
\fB\-h \fP
|
||||
Print help.
|
||||
|
||||
.TP
|
||||
\fB\-\-restore \fP
|
||||
Restore the last chosen wallpaper. Useful at launch of the window manager.
|
||||
|
||||
.TP
|
||||
\fB\-\-random \fP
|
||||
Set a random wallpaper.
|
||||
|
||||
.TP
|
||||
\fB\-\-backend XXX \fP
|
||||
Specify which backend to use, which can be either \fIswaybg, swww, feh\fR, or \fIwallutils\fR. Useful if you use waypaper on both Wayland and Xorg on the same machine. By default, last used backend is used.
|
||||
|
||||
.TP
|
||||
\fB\-\-fill XXX \fP
|
||||
Specifies filling type, which can be eiher \fIfill, stretch, fit, center\fR, or \fItile\fR.
|
||||
|
||||
.SH COMMANDS DURING USE
|
||||
Press '\fB?\fP' during use to get a list of keybindings.
|
||||
.br
|
||||
.SH AUTHOR
|
||||
Written by Roman Anufriev. For more information, visit \fIhttps://anufrievroman.gitbook.com/waypaper\fR
|
7
setup.py
7
setup.py
@ -18,7 +18,7 @@ setuptools.setup(
|
||||
]
|
||||
},
|
||||
install_requires=["PyGObject", "importlib_metadata", "platformdirs", "Pillow"],
|
||||
version='2.0.3',
|
||||
version='2.0.4',
|
||||
python_requires='>3.9',
|
||||
classifiers=[
|
||||
"Development Status :: 4 - Beta",
|
||||
@ -43,6 +43,9 @@ setuptools.setup(
|
||||
),
|
||||
('share/applications',
|
||||
['data/waypaper.desktop']
|
||||
)
|
||||
),
|
||||
('share/man/man1',
|
||||
['data/waypaper.1.gz']
|
||||
),
|
||||
],
|
||||
)
|
||||
|
@ -7,7 +7,7 @@ import argparse
|
||||
from waypaper.config import Config
|
||||
from waypaper.app import App
|
||||
from waypaper.changer import change_wallpaper
|
||||
from waypaper.common import get_random_file, check_missing_backends
|
||||
from waypaper.common import get_random_file
|
||||
from waypaper.aboutdata import AboutData
|
||||
from waypaper.options import FILL_OPTIONS, BACKEND_OPTIONS
|
||||
from waypaper.translations import English, German, French, Russian, Polish, Chinese
|
||||
@ -39,12 +39,10 @@ parser.add_argument("--backend", help=txt.msg_arg_back, choices=BACKEND_OPTIONS)
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
|
||||
def run():
|
||||
"""Read user arguments and either run GUI app or just reset the wallpaper"""
|
||||
|
||||
cf.read_parameters_from_user_arguments(args)
|
||||
missing_backends = check_missing_backends()
|
||||
|
||||
# Set the wallpaper and quit:
|
||||
if args.restore:
|
||||
@ -55,7 +53,7 @@ def run():
|
||||
|
||||
if wallpaper is None:
|
||||
continue
|
||||
change_wallpaper(wallpaper, cf, monitor, txt, missing_backends)
|
||||
change_wallpaper(wallpaper, cf, monitor, txt)
|
||||
time.sleep(0.1)
|
||||
exit(0)
|
||||
|
||||
|
@ -4,14 +4,14 @@ import subprocess
|
||||
import threading
|
||||
import os
|
||||
import gi
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from platformdirs import user_cache_path
|
||||
from PIL import Image
|
||||
|
||||
from waypaper.aboutdata import AboutData
|
||||
from waypaper.changer import change_wallpaper
|
||||
from waypaper.config import Config
|
||||
from waypaper.common import get_image_paths, get_random_file, check_missing_backends
|
||||
from waypaper.common import get_image_paths, get_random_file
|
||||
from waypaper.options import FILL_OPTIONS, BACKEND_OPTIONS, SORT_OPTIONS, SORT_DISPLAYS
|
||||
|
||||
gi.require_version("Gtk", "3.0")
|
||||
@ -27,7 +27,7 @@ def read_webp_image(image_path):
|
||||
return pixbuf
|
||||
|
||||
|
||||
def cache_image(image_path, cachedir):
|
||||
def cache_image(image_path, cache_dir):
|
||||
"""Resize and cache images using gtk library"""
|
||||
ext = os.path.splitext(image_path)[1].lower()
|
||||
if ext == ".webp":
|
||||
@ -38,7 +38,7 @@ def cache_image(image_path, cachedir):
|
||||
scaled_width = 240
|
||||
scaled_height = int(scaled_width / aspect_ratio)
|
||||
scaled_pixbuf = pixbuf.scale_simple(scaled_width, scaled_height, GdkPixbuf.InterpType.BILINEAR)
|
||||
output_file = cachedir / Path(os.path.basename(image_path))
|
||||
output_file = cache_dir / Path(os.path.basename(image_path))
|
||||
scaled_pixbuf.savev(str(output_file), "jpeg", [], [])
|
||||
|
||||
|
||||
@ -47,15 +47,14 @@ class App(Gtk.Window):
|
||||
|
||||
def __init__(self, txt):
|
||||
super().__init__(title="Waypaper")
|
||||
self.cf = Config()
|
||||
self.about = AboutData()
|
||||
self.txt = txt
|
||||
self.check_backends()
|
||||
self.set_default_size(780, 600)
|
||||
self.connect("delete-event", Gtk.main_quit)
|
||||
self.selected_index = 0
|
||||
self.highlighted_image_row = 0
|
||||
self.aboutData = AboutData()
|
||||
self.cachePath = user_cache_path(self.aboutData.applicationName())
|
||||
self.cf = Config()
|
||||
self.init_ui()
|
||||
|
||||
# Start the image processing in a separate thread:
|
||||
@ -96,16 +95,13 @@ class App(Gtk.Window):
|
||||
|
||||
# Create a backend dropdown menu:
|
||||
self.backend_option_combo = Gtk.ComboBoxText()
|
||||
for backend, is_missing in zip(BACKEND_OPTIONS, self.missing_backends):
|
||||
if not is_missing:
|
||||
self.backend_option_combo.append_text(backend)
|
||||
for backend in self.cf.installed_backends:
|
||||
self.backend_option_combo.append_text(backend)
|
||||
|
||||
# Set as active line the backend from config, if it is installed:
|
||||
try:
|
||||
installed_backends = [value for value, miss in zip(BACKEND_OPTIONS, self.missing_backends) if not miss]
|
||||
active_num = installed_backends.index(self.cf.backend)
|
||||
except:
|
||||
active_num = 0
|
||||
active_num = 0
|
||||
if self.cf.backend in self.cf.installed_backends:
|
||||
active_num = self.cf.installed_backends.index(self.cf.backend)
|
||||
self.backend_option_combo.set_active(active_num)
|
||||
self.backend_option_combo.connect("changed", self.on_backend_option_changed)
|
||||
self.backend_option_combo.set_tooltip_text(self.txt.tip_backend)
|
||||
@ -192,7 +188,6 @@ class App(Gtk.Window):
|
||||
def monitor_option_display(self):
|
||||
"""Display monitor option if backend is swww"""
|
||||
self.options_box.remove(self.monitor_option_combo)
|
||||
# if "swww" not in self.missing_backends and self.cf.backend not in ["wallutils", "feh"]:
|
||||
if self.cf.backend == "swww":
|
||||
|
||||
# Check available monitors:
|
||||
@ -219,12 +214,9 @@ class App(Gtk.Window):
|
||||
|
||||
|
||||
def check_backends(self):
|
||||
"""Before running the app, check which backends are installed"""
|
||||
self.missing_backends = check_missing_backends()
|
||||
|
||||
# Show error message if no backends are installed:
|
||||
if all(self.missing_backends):
|
||||
self.show_message(sefl.txt.err_backend)
|
||||
"""Before running the app, check which backends are installed or show the error"""
|
||||
if not self.cf.installed_backends:
|
||||
self.show_message(self.txt.err_backend)
|
||||
exit()
|
||||
|
||||
|
||||
@ -275,9 +267,9 @@ class App(Gtk.Window):
|
||||
self.image_paths.remove(image_path)
|
||||
continue
|
||||
# If this image is not cached yet, resize and cache it:
|
||||
cached_image_path = self.cachePath/os.path.basename(image_path)
|
||||
cached_image_path = self.cf.cache_dir / os.path.basename(image_path)
|
||||
if not cached_image_path.exists():
|
||||
cache_image(image_path, self.cachePath)
|
||||
cache_image(image_path, self.cf.cache_dir)
|
||||
|
||||
# Load cached thumbnail:
|
||||
thumbnail = GdkPixbuf.Pixbuf.new_from_file(str(cached_image_path))
|
||||
@ -406,7 +398,7 @@ class App(Gtk.Window):
|
||||
self.load_image_grid()
|
||||
print(self.txt.msg_path, self.cf.selected_wallpaper)
|
||||
self.cf.fill_option = self.fill_option_combo.get_active_text() or self.cf.fill_option
|
||||
change_wallpaper(self.cf.selected_wallpaper, self.cf, self.cf.selected_monitor, self.txt, self.missing_backends)
|
||||
change_wallpaper(self.cf.selected_wallpaper, self.cf, self.cf.selected_monitor, self.txt)
|
||||
self.cf.save()
|
||||
|
||||
|
||||
@ -433,17 +425,17 @@ class App(Gtk.Window):
|
||||
return
|
||||
print(self.txt.msg_path, self.cf.selected_wallpaper)
|
||||
self.cf.fill_option = self.fill_option_combo.get_active_text() or self.cf.fill_option
|
||||
change_wallpaper(self.cf.selected_wallpaper, self.cf, self.cf.selected_monitor, self.txt, self.missing_backends)
|
||||
change_wallpaper(self.cf.selected_wallpaper, self.cf, self.cf.selected_monitor, self.txt)
|
||||
self.cf.save()
|
||||
|
||||
|
||||
def clear_cache(self):
|
||||
"""Delete cache folder and reprocess the images"""
|
||||
try:
|
||||
shutil.rmtree(self.cachePath)
|
||||
os.makedirs(self.cachePath)
|
||||
shutil.rmtree(self.cf.cache_dir)
|
||||
os.makedirs(self.cf.cache_dir)
|
||||
except OSError as e:
|
||||
print(f"{self.txt.err_cache} '{self.cachePath}': {e}")
|
||||
print(f"{self.txt.err_cache} '{self.cf.cache_dir}': {e}")
|
||||
threading.Thread(target=self.process_images).start()
|
||||
|
||||
|
||||
@ -501,7 +493,7 @@ class App(Gtk.Window):
|
||||
print(self.txt.msg_path, self.cf.selected_wallpaper)
|
||||
self.cf.backend = self.backend_option_combo.get_active_text()
|
||||
self.cf.fill_option = self.fill_option_combo.get_active_text() or self.cf.fill_option
|
||||
change_wallpaper(self.cf.selected_wallpaper, self.cf, self.cf.selected_monitor, self.txt, self.missing_backends)
|
||||
change_wallpaper(self.cf.selected_wallpaper, self.cf, self.cf.selected_monitor, self.txt)
|
||||
self.cf.save()
|
||||
|
||||
# Prevent other default key handling:
|
||||
|
@ -6,13 +6,14 @@ import time
|
||||
from waypaper.options import BACKEND_OPTIONS
|
||||
|
||||
|
||||
def change_wallpaper(image_path, cf, monitor, txt, missing_backends):
|
||||
"""Run a system command to change the wallpaper depending on the backend"""
|
||||
def change_wallpaper(image_path, cf, monitor, txt):
|
||||
"""Run system commands to change the wallpaper depending on the backend"""
|
||||
|
||||
fill_option = cf.fill_option
|
||||
color = cf.color
|
||||
backend = cf.backend
|
||||
swww_transition = cf.swww_transition
|
||||
installed_backends = cf.installed_backends
|
||||
|
||||
try:
|
||||
# swaybg backend:
|
||||
@ -41,14 +42,12 @@ def change_wallpaper(image_path, cf, monitor, txt, missing_backends):
|
||||
"tile": "no",
|
||||
}
|
||||
fill = fill_types[fill_option.lower()]
|
||||
is_swaybg_installed = not missing_backends[BACKEND_OPTIONS.index("swaybg")]
|
||||
if is_swaybg_installed:
|
||||
if "swaybg" in installed_backends:
|
||||
try:
|
||||
subprocess.Popen(["killall", "swaybg"])
|
||||
time.sleep(0.005)
|
||||
except Exception as e:
|
||||
print(f"{ERR_KILL} {e}")
|
||||
print(missing_backends)
|
||||
subprocess.Popen(["swww", "init"])
|
||||
command = ["swww", "img", image_path]
|
||||
command.extend(["--resize", fill])
|
||||
|
@ -38,12 +38,15 @@ def get_random_file(folder, include_subfolders):
|
||||
return None
|
||||
|
||||
|
||||
def check_missing_backends():
|
||||
def check_installed_backends():
|
||||
"""Check which backends are installed in the system"""
|
||||
missing_backends = []
|
||||
installed_backends = []
|
||||
for backend in BACKEND_OPTIONS:
|
||||
if backend == "wallutils":
|
||||
backend = "setwallpaper"
|
||||
is_backend_missing = not bool(shutil.which(backend))
|
||||
missing_backends.append(is_backend_missing)
|
||||
return missing_backends
|
||||
binary_name = "setwallpaper"
|
||||
else:
|
||||
binary_name = backend
|
||||
is_installed = bool(shutil.which(binary_name))
|
||||
if is_installed:
|
||||
installed_backends.append(backend)
|
||||
return installed_backends
|
||||
|
@ -7,31 +7,34 @@ from sys import exit
|
||||
from platformdirs import user_config_path, user_pictures_path, user_cache_path
|
||||
|
||||
from waypaper.aboutdata import AboutData
|
||||
from waypaper.options import FILL_OPTIONS, SORT_OPTIONS, SWWW_TRANSITIONS
|
||||
from waypaper.options import FILL_OPTIONS, SORT_OPTIONS, SWWW_TRANSITIONS, BACKEND_OPTIONS
|
||||
from waypaper.common import check_installed_backends
|
||||
|
||||
|
||||
class Config:
|
||||
"""User configuration loaded from the config.ini file"""
|
||||
def __init__(self):
|
||||
self.image_folder = user_pictures_path()
|
||||
self.installed_backends = check_installed_backends()
|
||||
self.selected_wallpaper = ""
|
||||
self.selected_monitor = "All"
|
||||
self.fill_option = "fill"
|
||||
self.sort_option = "name"
|
||||
self.backend = "swaybg"
|
||||
self.fill_option = FILL_OPTIONS[0]
|
||||
self.sort_option = SORT_OPTIONS[0]
|
||||
self.backend = self.installed_backends[0] if self.installed_backends else BACKEND_OPTIONS[0]
|
||||
self.color = "#ffffff"
|
||||
self.swww_transition = "any"
|
||||
self.swww_transition = SWWW_TRANSITIONS[0]
|
||||
self.lang = "en"
|
||||
self.monitors = [self.selected_monitor]
|
||||
self.wallpaper = []
|
||||
self.include_subfolders = False
|
||||
self.aboutData = AboutData()
|
||||
self.cachePath = user_cache_path(self.aboutData.applicationName())
|
||||
self.configPath = user_config_path(self.aboutData.applicationName())
|
||||
self.config_file = self.configPath / "config.ini"
|
||||
self.about = AboutData()
|
||||
self.cache_dir = user_cache_path(self.about.applicationName())
|
||||
self.config_dir = user_config_path(self.about.applicationName())
|
||||
self.config_file = self.config_dir / "config.ini"
|
||||
|
||||
# Create config and cache folders:
|
||||
self.configPath.mkdir(parents=True, exist_ok=True)
|
||||
self.cachePath.mkdir(parents=True,exist_ok=True)
|
||||
self.config_dir.mkdir(parents=True, exist_ok=True)
|
||||
self.cache_dir.mkdir(parents=True,exist_ok=True)
|
||||
|
||||
self.read()
|
||||
|
||||
|
@ -14,5 +14,5 @@ IMAGE_EXTENSIONS = {
|
||||
BACKEND_OPTIONS[3]: ['.gif', '.jpg', '.jpeg', '.png'],
|
||||
}
|
||||
|
||||
SWWW_TRANSITIONS = ["none", "simple", "fade", "wipe", "left", "right", "top", "bottom",
|
||||
"wave", "grow", "center", "any", "outer", "random"]
|
||||
SWWW_TRANSITIONS = ["any", "none", "simple", "fade", "wipe", "left", "right", "top",
|
||||
"bottom", "wave", "grow", "center", "outer", "random"]
|
||||
|
Loading…
Reference in New Issue
Block a user