Compare commits

..

No commits in common. "main" and "wallman-releases" have entirely different histories.

23 changed files with 410 additions and 938 deletions

188
.gitignore vendored
View file

@ -1,188 +0,0 @@
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
### Python Patch ###
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
poetry.toml
# ruff
.ruff_cache/
# LSP config files
pyrightconfig.json
### VirtualEnv ###
# Virtualenv
# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
[Bb]in
[Ii]nclude
[Ll]ib
[Ll]ib64
[Ll]ocal
[Ss]cripts
pyvenv.cfg
pip-selfcheck.json
### Arch build files ###
*.tar.gz
**.tar.zst
pkg/
src/

View file

@ -1,16 +0,0 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.2
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
# Pre-commit's built-in hooks for minor fixes
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: trailing-whitespace # Remove trailing whitespace
- id: end-of-file-fixer # Ensure newline at end of file
- id: check-merge-conflict # Prevent merge conflicts from being committed
- id: detect-private-key # Prevent committing private keys

Binary file not shown.

Before

Width:  |  Height:  |  Size: 508 KiB

View file

@ -1,5 +1,2 @@
graft src
include sample_config.toml
include packaging/wallman.desktop
include DefaultFallbackWallpaper.jpg
recursive-include icons *
exclude README.org

View file

@ -1,3 +0,0 @@
# Wallman
For the full documentation, please see: **[README.org](https://git.entheuer.de/emma/Wallman/src/branch/main/README.org)**

View file

@ -12,7 +12,6 @@ Wallman currently has three main features:
+ Reading configuration details from a TOML file
+ Choosing from a set of Wallpapers and then setting the rest of the wallpapers accordingly
+ Settings Wallpapers at a specific time of the day
+ Be controlled via a systray
* Installation
** Depedencies
@ -22,54 +21,30 @@ Wallman currently has three main features:
+ feh (Used for setting the wallpapers, hard dependency)
*** Optional
+ libnotify (for desktop notification support)
+ pillow (For systray support)
+ pystray (For systray support)
*** Build dependencies
+ setuptools
+ build
** Installing with package Manager
*** Gentoo
Gentoo support has been dropped for now, as I currently don't have a Gentoo system to build on.
*** Arch Linux
Wallman is available in the AUR. Install it using your favorite AUR helper (I'm using paru as an example here)
#+BEGIN_SRC shell
paru -Syu wallman
mkdir ~/.config/wallman
cp /etc/wallman/sample_config.toml ~/.config/wallman/wallman.toml
#+END_SRC
Simply edit the config file and you're done.
*** Others
I will potentially write a version for nixpkgs and will also bundle wallman as a flatpak.
** Installing with pip
Wallman is available on PyPI. Simply run:
Wallman is available on PYPI. Simply run:
#+BEGIN_SRC shell
pip install wallman
#+END_SRC
** Installing with package Manager
Versions in the AUR and an ebuild for Gentoo will be added soon. A flatpak and Nixpkgs version are on the horizon, too.
** Installing manually
+ Install libnotify and feh, (preferably, also install the python dependencies from there) from your package manager
+ Clone this git repo
+ Create a log file and a configuration file:
#+BEGIN_SRC shell
git clone https://git.entheuer.de/emma/Wallman.git
cd Wallman/
pip install -r requirements.txt
pip install installer
sudo mkdir -p /var/log/wallman
sudo chmod 733 /var/log/wallman
touch /var/log/wallman
mkdir -p ~/.local/share/wallman
mkdir -p ~/.config/wallman
touch ~/.local/share/wallman/wallman.log
cp sample_config.toml ~/.config/wallman/wallman.toml
sudo mkdir -p /etc/wallman/
sudo cp -r icons /etc/wallman
sudo cp -r DefaultFallbackWallpaper /etc/wallman/DefaultFallbackWallpaper.jpg
python -m build
sudo python -m installer --destdir=/ dist/*.whl
#+END_SRC
+ Edit the sample config
+ (Optional): Adjust the loglevel to your liking. This will be part of the config or a command line argument soon.
+ Profit
* Configuration
@ -77,7 +52,7 @@ This is a short guide on how to correctly configure wallman. Look in the sample
** TOML Dictionaries
First of all, the config file is structured via different TOML dictionaries. There are two TOML dictionaries: general and changing_times that must be present in every config. Aside from that, further dictionaries are needed depending on how wallman is configured. You need to create a dictionary with the name of each wallpaper set defined in the used_sets list (more on that later). You should probably just configure wallman by editing the sample config as it is by far the easiest way to do it.
*** general
In general, you need to always define 3 variables and you can optionally add three more:
In general, you need to always define 3 variables and you can optionally add two more:
+ enable_wallpaper_sets: bool
A simple switch that states if you want to use different sets of wallpapers or not.
+ used_sets: list
@ -86,21 +61,8 @@ In general, you need to always define 3 variables and you can optionally add thr
The amount of wallpapers that you use in each set. It should be an integer.
+ Optional: notify: bool
This defaults to "false". Enable to set send a desktop notification when the wallpaper is changed. The program will still work correctly, even if this option is not defined at all.
+ Optional: fallback_wallpaper: string
Wallpaper to be set if an error is found in the config or the wallpaper intended to be set cannot be found. Defaults to "/etc/wallman/DefaultFallbackWallpaper.jpg". If none is set and the config has been written incorrectly, a ConfigError is raised and the program is exited. If an error in the config occurs but the fallback wallpaper has been defined, it will be set and wallman will raise a config error. If The config is written correctly but the wallpaper intended to be set can't be found, wallman will set the fallback wallpaper and continue to try setting future wallpapers. You can both change this location (recommended) or the wallpaper that the path points to.
+ Optional: loglevel: string
Loglevel to be used by wallman. Defaults to INFO. Choices MUST be DEBUG, INFO, WARNING, ERROR or CRITICAL. Using any capitalization is valid, all caps is reccomended. Wallman will crash if a value is specified that is not one of the specified ones.
+ Optional: systray: bool
This defaults to "true". This enables support for a systray that has the features to re-set your wallpaper (Mostly useful if feh shits itself or if you want to set the correct wallpaper for a specific time of day after your device was suspended) without rerolling the wallpaper set used, a button to reroll and then re-set the wallpaper, as well as a Quit button. Disable this to save a very tiny amount of memory.
+ Optional: behavior: string
This defaults to ~--bg-fill~. This is also the value that will be used when an invalid configuration option has been set. This supports 6 different modes, each mode has 2 possible keywords, resulting in 12 total valid keywords.
~--bg~, ~plain~. What happens when feh is used with the ~--bg~ flag. Sets a wallpaper without any scaling.
~--bg-tile~, ~tile~. Sets the wallpaper only on one monitor, the other ones get filled with black or white. Mostly useful for Xinerama setups with overlapping monitors. Equivalent to ~--bg-tile~ in feh.
~--bg-center~, ~center~. Sets a wallpaper with the center of the wallpaper centered on the middle of the screen. Crops edges. Equivalent to ~--bg-center~ in feh.
~--bg-fill~, ~fill~ (Default). Fills the whole screen with the wallpaper and zooms to preserve the original aspect ratio. Equivalent to ~--bg-fill~ in feh.
~--bg-max~, ~max~. Scales the image to the maximum possible size. Equivalent to ~--bg-max~ in feh.
~--bg-scale~, ~scale~. Scales the wallpaper to fill the screen, but does not preserve the original aspect ratio. Leads to squishing if aspect ratio of screen and wallpaper don't match. Equivalent to ~--bg-scale~ in feh.
+ Optional: fallback_wallpaper: bool
Wallpaper to be set if an error is found in the config. Defaults to None. If none is set and the config is written incorrectly, a ConfigError is raised and the program is exited. If an error in the config occurs but the fallback wallpaper has been defined, it will be set and wallman will exit with Code 1.
*** changing_times
The changing_times dictionary is used to specify the times of the day when your wallpaper is switched. The names of the keys do not matter here, the values must always be strings in the "XX:YY:ZZ" 24 hour time system. use 00:00:00 for midnight. Note that XX should be in the range of 00-23 and YY and ZZ should be in the range of 00-59.
@ -116,10 +78,13 @@ The keys in the dictionary once again do not matter, the names of the keys in ea
+ Add documentation for developers
** Technical Details
+ Improve Modularity (Partially done)
+ Improve Modularity
+ Make the enabled flag in wallpaper_sets actually useful by making the used_sets field optional
+ Add support for different loglevels in the config file or as a command line argument
+ Drop the feh dependecy and set wallpapers using pywlroots or python-xlib
** Features
+ Add support for setting a fallback wallpaper if a wallpaper the user set is not found
+ Add support for wallpapers that dynamically change with the time of day (Morning, noon, evening, night or light levels) rather than to times set in the config
+ Add support for wallpapers that change by the weather
+ Add support for live wallpapers

Binary file not shown.

Before

Width:  |  Height:  |  Size: 833 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,24 +0,0 @@
pkgbase = wallman
pkgdesc = A simple program to set dynamic wallpapers on standalone X11 window managers and wayland compositors
pkgver = 1.5.2.8
pkgrel = 1
url = https://git.entheuer.de/emma/wallman
arch = any
license = MIT
makedepends = python-build
makedepends = python-setuptools
makedepends = python-wheel
makedepends = python-installer
depends = feh
depends = python
depends = python-apscheduler
depends = python-pillow
depends = python-pystray
provides = wallman=1.5.2.8
backup = etc/wallman/icons/WallmanLogo.jpg
backup = etc/wallman/icons/systrayIcon.jpg
backup = etc/wallman/DefaultFallbackWallpaper.jpg
source = https://files.pythonhosted.org/packages/4e/fe/0998cd577e5b4e72cc60a7a3d95d11ff9b86c7c5e848aa0d8dc4690f75e8/wallman-1.5.2.8.tar.gz
b2sums = 116ef95afff6569cea63d0777b13a59da07ea6e0cf08692a3c470d1b3d135b7051adc0892f5558aecba2a49c81f7a2c848baa63763dceffe53d8565952654b3a
pkgname = wallman

View file

@ -1,48 +0,0 @@
# Maintainer: Emma Nora Theuer <wallman@entheuer.de>
pkgname=wallman
pkgver=1.5.2.8
pkgrel=1
pkgdesc="A simple program to set dynamic wallpapers on standalone X11 window managers and wayland compositors"
arch=('any')
url="https://git.entheuer.de/emma/wallman"
license=('MIT')
depends=('feh' 'python' 'python-apscheduler' 'python-pillow' 'python-pystray')
makedepends=('python-build' 'python-setuptools' 'python-wheel' 'python-installer')
provides=("$pkgname=$pkgver")
source=("https://files.pythonhosted.org/packages/4e/fe/0998cd577e5b4e72cc60a7a3d95d11ff9b86c7c5e848aa0d8dc4690f75e8/wallman-1.5.2.8.tar.gz")
b2sums=('116ef95afff6569cea63d0777b13a59da07ea6e0cf08692a3c470d1b3d135b7051adc0892f5558aecba2a49c81f7a2c848baa63763dceffe53d8565952654b3a')
# Treating this as config files seems to be necessary for python to do not complain
backup=('etc/wallman/icons/WallmanLogo.jpg' 'etc/wallman/icons/systrayIcon.jpg' 'etc/wallman/DefaultFallbackWallpaper.jpg')
build(){
cd "$pkgname-$pkgver"
python -m build --wheel --no-isolation
}
package(){
cd "$pkgname-$pkgver"
python -m installer --destdir="$pkgdir" dist/*.whl
# Copy LICENSE
install -D -m 644 LICENSE -t "$pkgdir/usr/share/licenses/$pkgname/"
# Copy Icons
if [ -d "icons" ]; then
install -d -m 755 "$pkgdir/etc/$pkgname/icons"
cp -r icons/* "$pkgdir/etc/$pkgname/icons/"
fi
# Copy sample config
install -D -m 644 sample_config.toml -t "$pkgdir/etc/$pkgname/"
# Copy Fallback Wallpaper
install -D -m 644 DefaultFallbackWallpaper.jpg -t "$pkgdir/etc/$pkgname/"
# Copy .desktop file
install -D -m 755 packaging/wallman.desktop -t "$pkgdir/usr/share/application/$pkgname.desktop"
# Create logdirectory
install -d -m 733 "$pkgdir/var/log/$pkgname"
}

View file

@ -1,8 +0,0 @@
[Desktop Entry]
Name=wallman
Comment=run wallman
Exec=wallman
Icon=/etc/wallman/icons/WallmanLogo.jpg
Terminal=false
Type=Application
Categories=Utility;

196
pypireadme.md Normal file
View file

@ -0,0 +1,196 @@
# Table of Contents
1. [Overwiev](#org19ef638)
1. [What is this?](#org148aad0)
2. [What can it do?](#org0041bf1)
2. [Installation](#orgc40ee8b)
1. [Depedencies](#org2cb62ef)
1. [Always Required](#org0d0b0f7)
2. [Optional](#orgf04ec77)
3. [Build dependencies](#org3951087)
2. [Installing with pip](#org24bde1c)
3. [Installing with package Manager](#org9575c55)
4. [Installing manually](#org2c63e0f)
3. [Configuration](#org812c501)
1. [TOML Dictionaries](#org51e3333)
1. [general](#org79747a5)
2. [changing<sub>times</sub>](#orgc425813)
3. [The other dictionaries](#org9f47b06)
4. [TODOs](#orgc26c243)
1. [Structuring](#org8dd22d4)
2. [Technical Details](#org6103451)
3. [Features](#org38d78ba)
<a id="org19ef638"></a>
# Overwiev
<a id="org148aad0"></a>
## What is this?
This is my project wallman. Wallman is a simple python program used for setting Dynamic Wallpapers on minimalist X11 Window Managers and Wayland compositors. The name is a reference to TomSka: <https://www.youtube.com/watch?v=k4Q3qD93rgI&t=131s>
This version is an early Alpha. As of now, it supports the most important features for my usecase, those being randomly selected wallpaper sets and wallpaper sets that change by the time of day. The program is not modular yet and I would expect a lot of bugs related to the configuration file. Just how it is, I&rsquo;m working on it.
As such, please make absolutely sure you follow the instructions on how to write the config file very closely. I will implement better config handling with more meaningful error output in the future. For now, follow everything really closely and read the logs if needed. If you do that, it *should* work.
<a id="org0041bf1"></a>
## What can it do?
Wallman currently has three main features:
- Reading configuration details from a TOML file
- Choosing from a set of Wallpapers and then setting the rest of the wallpapers accordingly
- Settings Wallpapers at a specific time of the day
<a id="orgc40ee8b"></a>
# Installation
<a id="org2cb62ef"></a>
## Depedencies
<a id="org0d0b0f7"></a>
### Always Required
- Python 3.11 or newer (Required because of tomllib)
- APScheduler (Install python-apscheduler or APScheduler, depending on the package manager)
- feh (Used for setting the wallpapers, hard dependency)
<a id="orgf04ec77"></a>
### Optional
- libnotify (for desktop notification support)
<a id="org3951087"></a>
### Build dependencies
- setuptools
- build
<a id="org24bde1c"></a>
## Installing with pip
Wallman is available on PYPI. Simply run:
pip install wallman
<a id="org9575c55"></a>
## Installing with package Manager
Versions in the AUR and an ebuild for Gentoo will be added soon. A flatpak and Nixpkgs version are on the horizon, too.
<a id="org2c63e0f"></a>
## Installing manually
- Clone this git repo
- Create a log file and a configuration file:
mkdir -p ~/.local/share/wallman
mkdir -p ~/.config/wallman
touch ~/.local/share/wallman/wallman.log
cp sample_config.toml ~/.config/wallman/wallman.toml
- Edit the sample config
- (Optional): Adjust the loglevel to your liking. This will be part of the config or a command line argument soon.
- Profit
<a id="org812c501"></a>
# Configuration
This is a short guide on how to correctly configure wallman. Look in the sample config for additional context.
<a id="org51e3333"></a>
## TOML Dictionaries
First of all, the config file is structured via different TOML dictionaries. There are two TOML dictionaries: general and changing<sub>times</sub> that must be present in every config. Aside from that, further dictionaries are needed depending on how wallman is configured. You need to create a dictionary with the name of each wallpaper set defined in the used<sub>sets</sub> list (more on that later). You should probably just configure wallman by editing the sample config as it is by far the easiest way to do it.
<a id="org79747a5"></a>
### general
In general, you need to always define 3 variables and you can optionally add two more:
- enable<sub>wallpaper</sub><sub>sets</sub>: bool
A simple switch that states if you want to use different sets of wallpapers or not.
- used<sub>sets</sub>: list
A list that includes the names of the wallpaper sets you want to use. If you want to use only one, the list should have one entry.
- wallpapers<sub>per</sub><sub>set</sub>: int
The amount of wallpapers that you use in each set. It should be an integer.
- Optional: notify: bool
This defaults to &ldquo;false&rdquo;. Enable to set send a desktop notification when the wallpaper is changed. The program will still work correctly, even if this option is not defined at all.
- Optional: fallback<sub>wallpaper</sub>: bool
Wallpaper to be set if an error is found in the config. Defaults to None. If none is set and the config is written incorrectly, a ConfigError is raised and the program is exited. If an error in the config occurs but the fallback wallpaper has been defined, it will be set and wallman will exit with Code 1.
<a id="orgc425813"></a>
### changing<sub>times</sub>
The changing<sub>times</sub> dictionary is used to specify the times of the day when your wallpaper is switched. The names of the keys do not matter here, the values must always be strings in the &ldquo;XX:YY:ZZ&rdquo; 24 hour time system. use 00:00:00 for midnight. Note that XX should be in the range of 00-23 and YY and ZZ should be in the range of 00-59.
<a id="org9f47b06"></a>
### The other dictionaries
The other dictionaries must always have the names of the wallpaper sets from used<sub>sets</sub>. If you have one wallpaper set, you need one additional dictionary, if you have two you need two etc. The standard config uses nature and anime, these names can be whatever you please as long as they are the same as the ones specified in used<sub>sets</sub>.
The keys in the dictionary once again do not matter, the names of the keys in each dictionary must be strings and be absolute paths. They should not include spaces unless prefaced by a backslash.
<a id="orgc26c243"></a>
# TODOs
<a id="org8dd22d4"></a>
## Structuring
- Write unittests
- Add documentation for developers
<a id="org6103451"></a>
## Technical Details
- Improve Modularity
- Make the enabled flag in wallpaper<sub>sets</sub> actually useful by making the used<sub>sets</sub> field optional
- Add support for different loglevels in the config file or as a command line argument
- Drop the feh dependecy and set wallpapers using pywlroots or python-xlib
<a id="org38d78ba"></a>
## Features
- Add support for setting a fallback wallpaper if a wallpaper the user set is not found
- Add support for wallpapers that dynamically change with the time of day (Morning, noon, evening, night or light levels) rather than to times set in the config
- Add support for wallpapers that change by the weather
- Add support for live wallpapers

View file

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "wallman"
version = "1.5.2.8"
version = "1.3.0b1"
authors = [
{name = "Emma Nora Theuer", email = "wallman@entheuer.de"},
]
@ -24,22 +24,9 @@ classifiers = [
]
dependencies = [
"APScheduler",
"pillow",
"pystray",
'importlib-metadata; python_version<"3.10"',
]
[tool.setuptools.packages.find]
where = ["."]
include = ["wallman*"]
exclude = ["icons*", "packaging*", "DefaultFallbackWallpaper.jpg"]
[project.urls]
Homepage = "https://git.entheuer.de/emma/Wallman"
Issues = "https://git.entheuer.de/emma/Wallman/issues"
[project.scripts]
wallman = "wallman.main:main"
[tool.mypy]
disable_error_code = ["import-untyped", "no-redef"]

View file

@ -1,6 +0,0 @@
APScheduler==3.11.0
pillow==11.0.0
pystray==0.19.5
setuptools==75.6.0
build==1.2.2.post1
twine==6.0.1

View file

@ -4,11 +4,8 @@
enable_wallpaper_sets = true
used_sets = ["anime", "nature"]
wallpapers_per_set = 5
notify = false
fallback_wallpaper = "/etc/wallman/DefaultFallbackWallpaper.jpg" # Feel free to use a different filepath for this!
loglevel = "INFO"
systray = true
behavior = "fill"
notify = False
fallback_wallpaper = "/path/to/paper"
# Enter the hours at which you want the wallpaper to change.
# If the script is called between one of this times, it will go back to the previous time.

12
src/__main__.py Normal file
View file

@ -0,0 +1,12 @@
#!/usr/bin/env python3
import wallman_lib
def main():
validator = wallman_lib.ConfigValidity()
logic = wallman_lib.WallpaperLogic()
validator.validate_config()
logic.set_wallpaper_by_time()
logic.schedule_wallpapers()
if __name__ == "__main__":
main()

182
src/wallman_lib.py Normal file
View file

@ -0,0 +1,182 @@
#!/usr/bin/env python3
from sys import exit
from os import chdir, getenv, system
import logging
import tomllib
from datetime import datetime, time
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
# setup logging
chdir(str(getenv("HOME")) + "/.local/share/wallman/")
logger = logging.getLogger(__name__)
logging.basicConfig(filename="wallman.log", encoding="utf-8", level=logging.WARNING)
# read config
# a = list(data["changing_times"].values())
# print(a[0])
class ConfigError(Exception):
pass
class _ConfigLib:
def _initialize_config(self) -> dict:
chdir(str(getenv("HOME")) + "/.config/wallman/")
with open("wallman.toml", "rb") as config_file:
data = tomllib.load(config_file)
return data
# a = list(data["changing_times"].values())
# print(a[0])
def __init__(self):
self.config_file: dict = self._initialize_config() # Full config
# Dictionaries
self.config_general: dict = self.config_file["general"]
self.config_changing_times: dict = self.config_file["changing_times"]
# Values in Dicts
self.config_wallpaper_sets_enabled: bool = self.config_general["enable_wallpaper_sets"]
self.config_used_sets: list = self.config_general["used_sets"]
self.config_wallpapers_per_set: int = self.config_general["wallpapers_per_set"]
self.config_total_changing_times: int = len(self.config_changing_times)
try:
self.config_notify = self.config_general["notify"]
except KeyError:
self.config_notify = False
logger.warning("'notify' is not set in dictionary general in the config file, defaulting to 'false'.")
def _set_fallback_wallpaper(self):
if self.config_general["fallback_wallpaper"]:
system(f"feh --bg-fill --no-fehbg {self.config_general['fallback_wallpaper']}")
logger.info("The fallback Wallpaper has been set.")
else:
logger.critical("An Error occured and no fallback wallpaper was provided, exiting...")
raise ConfigError("An error occured and no fallback wallpaper has been set, exiting...")
class ConfigValidity(_ConfigLib):
def __init__(self):
super().__init__()
def _check_fallback_wallpaper(self):
if self.config_general["fallback_wallpaper"]:
logger.debug("A fallback wallpaper has been defined.")
else:
logger.warning("No fallback wallpaper has been provided. If the config is written incorrectly, the program will not be able to be executed.")
def _check_wallpapers_per_set_and_changing_times(self) -> None:
# Check if the amount of wallpapers_per_set and given changing times match
if self.config_total_changing_times == self.config_wallpapers_per_set:
logger.debug("The amount of changing times and wallpapers per set is set correctly")
else:
try:
self._set_fallback_wallpaper()
logger.error("The amount of changing_times and the amount of wallpapers_per_set does not much, the fallback wallpaper has been set.")
print("ERROR: The amount of changing_times and the amount of wallpapers_per_set does not much, the fallback wallpaper has been set.")
exit(1)
except ConfigError:
logger.critical("The amount of changing times and the amount of wallpapers per set does not match, exiting...")
raise ConfigError("Please provide an amount of changing_times equal to wallpapers_per_set, exiting...")
def _check_general_validity(self) -> None:
if len(self.config_general) < 3:
try:
self._set_fallback_wallpaper()
logger.error("An insufficient amount of elements has been provided for general, the fallback wallpaper has been set.")
print("ERROR: An insufficient amount of wallpapers has been provided for general, the fallback wallpaper has been set.")
exit(1)
except ConfigError:
logger.critical("An insufficient amount of elements for general has been provided, exiting...")
raise ConfigError("general should have at least 3 elements, exiting...")
def _check_wallpaper_dicts(self)-> None:
# This block checks if a dictionary for each wallpaper set exists
for wallpaper_set in self.config_used_sets:
if wallpaper_set in self.config_file:
logger.debug(f"The dictionary {wallpaper_set} has been found in config.")
else:
try:
self._set_fallback_wallpaper()
logger.error(f"The dictionary {wallpaper_set} has not been found in the config, the fallback wallpaper has been set.")
print(f"ERROR: The dictionary {wallpaper_set} has not been found in the config, the fallback wallpaper has been set.")
exit(1)
except ConfigError:
logger.critical(f"No dictionary {wallpaper_set} has been found in the config exiting...")
raise ConfigError(f"The dictionary {wallpaper_set} has not been found in the config, exiting...")
def _check_wallpaper_amount(self) -> None:
# This block checks if if each wallpaper set dictionary provides enough wallpapers to satisfy wallpapers_per_set
for wallpaper_set in self.config_used_sets:
if len(self.config_file[wallpaper_set]) == self.config_wallpapers_per_set:
logger.debug(f"Dictionary {wallpaper_set} has sufficient values.")
else:
try:
self._set_fallback_wallpaper()
logger.error(f"The Dictionary {wallpaper_set} does not have sufficient entries, the fallback wallpaper has been set.")
print(f"ERROR: The Dictionaty {wallpaper_set} does not have sufficient entries, the fallback wallpaper has been set.")
exit(1)
except ConfigError:
logger.critical(f"Dictionary {wallpaper_set} does not have sufficient entries, exciting...")
raise ConfigError(f"Dictionary {wallpaper_set} does not have the correct amount of entries, exciting...")
def validate_config(self) -> None:
self._check_fallback_wallpaper()
self._check_wallpapers_per_set_and_changing_times()
self._check_general_validity()
self._check_wallpaper_dicts()
self._check_wallpaper_amount()
logger.debug("The config file has been validated successfully (No Errors)")
class WallpaperLogic(_ConfigLib):
def __init__(self):
super().__init__()
self.chosen_wallpaper_set = False
# Returns a list of a split string that contains a changing time from the config file
def _clean_times(self, desired_time) -> list:
unclean_times = list(self.config_changing_times.values())[desired_time]
return unclean_times.split(":")
def _choose_wallpaper_set(self) -> None:
from random import choice as choose_from
self.chosen_wallpaper_set = choose_from(self.config_used_sets)
self.wallpaper_list = list(self.config_file[self.chosen_wallpaper_set].values())
logger.debug(f"Chose wallpaper set {self.chosen_wallpaper_set}")
# Verify if a given time is in a given range
def _time_in_range(self, start, end, x) -> bool:
if start <= end:
return start <= x <= end
else:
return start <= x or x < end
def _notify_user(self):
system("notify-send 'Wallman' 'A new Wallpaper has been set.'")
logger.debug("Sent desktop notification.")
def set_wallpaper_by_time(self) -> None:
# Ensure use of a consistent wallpaper set
if self.chosen_wallpaper_set is False:
self._choose_wallpaper_set()
for time_range in range(self.config_total_changing_times - 1):
clean_time = self._clean_times(time_range)
clean_time_two = self._clean_times(time_range + 1)
# Check if the current time is between a given and the following changing time and if so, set that wallpaper. If not, keep trying.
if self._time_in_range(time(int(clean_time[0]), int(clean_time[1]), int(clean_time[2])), time(int(clean_time_two[0]), int(clean_time_two[1]), int(clean_time_two[2])), datetime.now().time()):
system(f"feh --bg-scale --no-fehbg {self.wallpaper_list[time_range]}")
if self.config_notify:
self._notify_user()
return
else:
continue
system(f"feh --bg-scale --no-fehbg {self.wallpaper_list[-1]}")
if self.config_notify:
self._notify_user()
def schedule_wallpapers(self):
scheduler = BlockingScheduler()
# Create a scheduled job for every changing time
for changing_time in range(len(self.config_changing_times)):
clean_time = self._clean_times(changing_time)
scheduler.add_job(self.set_wallpaper_by_time, trigger=CronTrigger(hour=clean_time[0], minute=clean_time[1], second=clean_time[2]))
scheduler.start()
logger.info("The scheduler has been started.")

View file

View file

@ -1,6 +0,0 @@
#!/usr/bin/env python3
from wallman.main import main
if __name__ == "__main__":
main()

View file

@ -1,12 +0,0 @@
#!/usr/bin/env python3
from wallman.wallman_lib import WallpaperLogic
def main() -> None:
logic: WallpaperLogic = WallpaperLogic()
logic.set_wallpaper_by_time()
logic.schedule_wallpapers()
if __name__ == "__main__":
main()

View file

@ -1,28 +0,0 @@
from typing import TypedDict, List, Dict
"""
This is where library classes, like the config error
And other utility things like TypedDicts for better
linting and type checking go. I should also consider
to move some other import here
"""
class ConfigError(Exception):
pass
class ConfigGeneral(TypedDict):
enable_wallpaper_sets: bool
used_sets: List[str]
wallpapers_per_set: int
notify: bool
fallback_wallpaper: str
log_level: str
systray: bool
behavior: str
class ConfigFile(TypedDict):
general: ConfigGeneral
changing_times: Dict[str, str]

View file

@ -1,485 +0,0 @@
from os import chdir, getenv, system, path
import logging
import tomllib
from datetime import datetime, time
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
from typing import Dict, List
from wallman.wallman_classes import ConfigError, ConfigGeneral, ConfigFile
# Setup Logging. NOTE: Declaration as a global variable is necessary to ensure correct functionality across multiple modules.
global logger
logger = logging.getLogger("wallman")
class _Config:
# Initializes the most important config values.
def __init__(self) -> None:
# Config file
self.config_file: ConfigFile = self._initialize_config() # Full config
# Config general
valid_general: bool = self._initialize_general()
if not valid_general:
logger.critical("The general dictionary was not found or contains errors")
print("CRITICAL: The general dictionary was not found or contains errors")
raise ConfigError("The general dictionary was not found or contains errors")
# Changing times
valid_changing_times: bool = self._initialize_changing_times()
if not valid_changing_times:
logger.critical(
"The amount of provided changing times does not match the amount of wallpapers per set, or the dictionary has not been found in the config file."
)
print(
"CRITICAL: The amount of provided changing times does not match the amount of wallpapers per set, or the dictionary has not been found in the config file."
)
raise ConfigError
# Wallpaper sets
valid_wallpaper_amount: bool = self._check_wallpaper_amount()
if not valid_wallpaper_amount:
raise ConfigError(
"The amount of wallpapers in a set does not match the amount of wallpapers_per_set provided in general."
)
# Read config
def _initialize_config(self) -> ConfigFile:
chdir(str(getenv("HOME")) + "/.config/wallman/")
try:
with open("wallman.toml", "rb") as config_file:
data: ConfigFile = tomllib.load(config_file) # type: ignore #pyright:ignore
return data
except FileNotFoundError:
raise FileNotFoundError(
"No config file could be found in ~/.config/wallman/wallman.toml"
)
except tomllib.TOMLDecodeError as e:
print("ERROR: Config could not be parsed: Invalid TOML Syntax")
raise e
def _verify_systray_deps(self):
from importlib import util
if util.find_spec("pystray") is None or util.find_spec("PIL") is None:
logger.error(
"systray is enabled, but dependencies for the systray couldn't be found. Are pystray and pillow installed?"
)
logger.info("Setting self.config_systray to false.")
print(
"ERROR: systray is enabled, but dependencies for the systray couldn't be found. Are pystray and pillow installed?"
)
self.config_systray = False
def _set_log_level(self) -> None:
global logging
global logger
chdir("/var/log/wallman/")
numeric_level: int = getattr(logging, self.config_log_level, logging.INFO)
logger.setLevel(numeric_level)
if not path.exists("wallman.log"):
system("touch wallman.log")
logging.basicConfig(
filename="wallman.log", encoding="utf-8", level=numeric_level
)
def _set_behavior(self) -> str:
try:
behavior: str = self.config_general["behavior"]
except KeyError:
logger.warning(
"There is no wallpaper behavior specified in general, defaulting to fill..."
)
print(
"WARNING: There is no wallpaper behavior specified in general, defaulting to fill..."
)
human_behaviors: List[str] = ["plain", "tile", "center", "fill", "max", "scale"]
machine_behaviors: List[str] = [
"--bg",
"--bg-tile",
"--bg-center",
"--bg-fill",
"--bg-max",
"--bg-scale",
]
behavior: str = self.config_general.get("behavior", "--bg-fill").lower()
if behavior not in human_behaviors and behavior not in machine_behaviors:
logging.error(
f"The value provided for behaviors, {behavior}, is not valid. Defaulting to fill..."
)
print(
f"ERROR: The value provided for behaviors, {behavior}, is not valid. Defaulting to --bg-fill..."
)
if behavior not in machine_behaviors:
match behavior:
case "plain":
behavior = "--bg"
case "tile":
behavior = "--bg-tile"
case "center":
behavior = "--bg-center"
case "max":
behavior = "--bg-max"
case "scale":
behavior = "--bg-scale"
case _:
behavior = "--bg-fill"
logger.info(f"The wallpaper behavior '{behavior}' has been set.")
return behavior
def _set_fallback_wallpaper(self) -> None:
if self.config_fallback_wallpaper:
successfully_set: int = system(
f"feh {self.config_behavior} --no-fehbg {self.config_fallback_wallpaper}"
)
if successfully_set == 0:
logger.info("The fallback Wallpaper has been set.")
else:
logger.critical(
"An Error occured and no fallback wallpaper was provided, exiting..."
)
raise ConfigError(
"An error occured and no fallback wallpaper has been set, exiting..."
)
def _initialize_general(self) -> bool:
# Create Config General Dict
try:
self.config_general: ConfigGeneral = self.config_file["general"]
except KeyError:
print("CRITICAL: No general dictionary found in Config file.")
raise ConfigError(
"The general dictionary could not be found in the config, exiting!"
)
# Set up logger.
self.config_log_level = self.config_general.get("log_level", "INFO").upper()
self._set_log_level()
logger.debug(f"Log level has been set to {self.config_log_level}")
logger.debug("Logger initialized successfully")
# Set up fallback wallpaper
self.config_fallback_wallpaper: str = self.config_general.get(
"fallback_wallpaper", "/etc/wallman/DefaultFallbackWallpaper.jpg"
)
logger.debug(f"Set fallback wallpaper: {self.config_fallback_wallpaper}")
# Wallpapers per set
try:
self.config_wallpapers_per_set: int = self.config_general[
"wallpapers_per_set"
]
logger.debug(
f"Set config_wallpapers_per_set to {self.config_wallpapers_per_set}"
)
except KeyError:
print(
"CRITICAL: No option wallpapers_per_set provided in the general dictionary. Attempting to set the fallback wallpaper"
)
logger.critical(
"No option wallpapers_per_set provided in the general dictionary. Attempting to set the fallback wallpaper"
)
self._set_fallback_wallpaper()
return False
# Are wallpaper sets enabled to begin with?
try:
self.config_wallpaper_sets_enabled: bool = self.config_general[
"enable_wallpaper_sets"
]
logger.debug(
f"Set config_wallpaper_sets_enabled to {self.config_wallpaper_sets_enabled}"
)
except KeyError:
logger.critical(
"No option enable_wallpaper_sets provided in the general dictionary. Attempting to set the fallback wallpaper"
)
print(
"CRITICAL: No option enable_wallpaper_sets provided in the general dictionary. Attempting to set the fallback wallpaper"
)
self._set_fallback_wallpaper()
return False
# Configure used sets
if self.config_wallpaper_sets_enabled:
try:
self.config_used_sets: List[str] = self.config_general["used_sets"]
logger.debug(
f"These wallpaper sets are in use: {self.config_used_sets}"
)
except KeyError:
print(
"CRITICAL: No array used_sets provided in the general dictionary. Attempting to set the fallback wallpaper."
)
logger.critical(
"No array used_sets provided in the general dictionary. Attempting to set the fallback wallpaper."
)
self._set_fallback_wallpaper()
return False
# Systray
try:
self.config_systray: bool = self.config_general["systray"]
logger.debug(f"config_systray has been set to: {self.config_systray}")
except KeyError:
self.config_systray: bool = True
logger.warning("No option systray found in general. Defaulting to true...")
if self.config_systray:
self._verify_systray_deps()
# Wallpaper behavior
self.config_behavior = self._set_behavior()
# Notifications
try:
self.config_notify: bool = self.config_general["notify"]
logger.debug(f"Set config_notify to {self.config_notify}.")
except KeyError:
self.config_notify: bool = False
logger.warning(
"notify is not set in dictionary general in the config file, defaulting to 'false'."
)
return True
def _initialize_changing_times(self) -> bool:
try:
self.config_changing_times: Dict[str, str] = self.config_file[
"changing_times"
]
self.config_total_changing_times: int = len(self.config_changing_times)
logger.debug(f"Changing times are {self.config_changing_times}")
except KeyError:
logger.critical(
"No dictionary called changing_times has been found in the config file."
)
print(
"CRITICAL: No dictionary called changing_times has been found in the config file."
)
return False
return self._wallpapers_per_set_and_changing_times_match()
def _wallpapers_per_set_and_changing_times_match(self) -> bool:
# Check if the amount of wallpapers_per_set and given changing times match
if self.config_total_changing_times == self.config_wallpapers_per_set:
logger.debug(
"The amount of changing times and wallpapers per set is set correctly"
)
return True
else:
try:
self._set_fallback_wallpaper()
logger.critical(
"The amount of changing_times and the amount of wallpapers_per_set does not match, the fallback wallpaper has been set."
)
print(
"CRITICAL: The amount of changing_times and the amount of wallpapers_per_set does not match, the fallback wallpaper has been set."
)
return False
except ConfigError:
logger.critical(
"The amount of changing times and the amount of wallpapers per set does not match, exiting..."
)
print(
"CRITICAL: The amount of changing times and the amount of wallpapers per set does not match, exiting..."
)
raise ConfigError(
"The amount of changing times and the amount of wallpapers per set does not match."
)
def _check_wallpaper_amount(self) -> bool:
# This block checks if if each wallpaper set dictionary provides enough wallpapers to satisfy wallpapers_per_set
for wallpaper_set in self.config_used_sets:
if len(self.config_file[wallpaper_set]) == self.config_wallpapers_per_set: # type: ignore
logger.debug(f"Dictionary {wallpaper_set} has sufficient values.")
return True
else:
try:
self._set_fallback_wallpaper()
logger.error(
f"The Dictionary {wallpaper_set} does not have sufficient entries, the fallback wallpaper has been set."
)
print(
f"ERROR: The Dictionaty {wallpaper_set} does not have sufficient entries, the fallback wallpaper has been set."
)
return False
except ConfigError:
logger.critical(
f"Dictionary {wallpaper_set} does not have sufficient entries, exciting..."
)
print(
f"Dictionary {wallpaper_set} does not have sufficient entries, exciting..."
)
return False
# TODO: Improve modularity. See notes inside the class for more details.
# TODO: Ensure functionality and if needed add handling for the 1 wallpaper per set case.
class WallpaperLogic(_Config):
def __init__(self) -> None:
super().__init__()
self.wallpaper_list: List[str] = None # type: ignore # pyright: ignore
self.chosen_wallpaper_set: str = None # type: ignore # pyright: ignore
# NOTE: This function could be in a different file because it's not needed in the case only 1 wallpaper per set is needed.
# Returns a list of a split string that contains a changing time from the config file
def _clean_times(self, desired_time: int) -> List[str]:
unclean_times: str = list(self.config_changing_times.values())[desired_time]
return unclean_times.split(":")
# NOTE: This could be in a different file because it's not needed in the "Only one wallpaper set" case.
def _choose_wallpaper_set(self) -> None:
from random import choice as choose_from
self.chosen_wallpaper_set = choose_from(self.config_used_sets)
self.wallpaper_list: List[str] = list(
self.config_file[self.chosen_wallpaper_set].values()
) # type: ignore
logger.debug(f"Chose wallpaper set {self.chosen_wallpaper_set}")
# NOTE: Same as _clean_times()
# Verify if a given time is in a given range
def _time_in_range(self, start: time, end: time, x: time) -> bool:
if start <= end:
return start <= x <= end
else:
return start <= x or x < end
# NOTE: Potentially add handling for this to be also usable for notify_user and add logging if notify_user fails. Consider adding an argument that is where it's called from and handle accordingly.
def _check_system_exitcode(self, code: int) -> bool:
if code != 0:
try:
self._set_fallback_wallpaper()
logger.error(
f"The wallpaper {self.wallpaper_list[self.current_time_range]} has not been found, the fallback wallpaper has been set. Future wallpapers will still attempted to be set."
)
print(
f"ERROR: The wallpaper {self.wallpaper_list[self.current_time_range]} has not been found, the fallback wallpaper has been set. Future wallpapers will still attempted to be set."
)
return False
except ConfigError:
logger.error(
f"The wallpaper {self.wallpaper_list[self.current_time_range]} has not been found and no fallback wallpaper has been set. Future wallpapers will still attempted to be set."
)
print(
f"ERROR: The wallpaper {self.wallpaper_list[self.current_time_range]} has not been found and no fallback wallpaper has been set. Future wallpapers will still attempted to be set."
)
return False
else:
logger.info(
f"The wallpaper {self.wallpaper_list[self.current_time_range]} has been set."
)
return True
# NOTE: Add error handling in case libnotify is not installed or notify-send fails for any other reason.
# TODO: Add a check whether config[notify] is true or not.
def _notify_user(self):
system("notify-send 'Wallman' 'A new Wallpaper has been set.'")
logger.debug("Sent desktop notification.")
# TODO: Clean this up. It's way too large and way too intimidating.
# NOTE: This could be in a different for the case that the user only wants 1 wallpaper per set.
# TODO: Add an way for the user to choose if the wallpaper should scale, fill or otherwise. This needs to be editable in the config file.
def set_wallpaper_by_time(self) -> bool:
# Ensure use of a consistent wallpaper set
if not self.chosen_wallpaper_set:
self._choose_wallpaper_set()
for time_range in range(self.config_total_changing_times - 1):
self.current_time_range = (
time_range # Store current time for better debugging output
)
clean_time: List[str] = self._clean_times(time_range)
clean_time_two: List[str] = self._clean_times(time_range + 1)
# HACK on this to make it more readable. This function call is way too long. Consider storing these in a bunch of temporary variables, though keep function length in mind.
# HACK on this to see if this logic can be simplified. It's very ugly to check it that way.
# Check if the current time is between a given and the following changing time and if so, set that wallpaper. If not, keep trying.
if self._time_in_range(
time(int(clean_time[0]), int(clean_time[1]), int(clean_time[2])),
time(
int(clean_time_two[0]),
int(clean_time_two[1]),
int(clean_time_two[2]),
),
datetime.now().time(),
):
exitcode: int = system(
f"feh {self.config_behavior} --no-fehbg --quiet {self.wallpaper_list[time_range]}"
)
has_wallpaper_been_set: bool = self._check_system_exitcode(exitcode)
# TODO: Add this check to _notify_user.
if self.config_notify:
self._notify_user()
return has_wallpaper_been_set
else:
continue
exitcode: int = system(
f"feh {self.config_behavior} --no-fehbg {self.wallpaper_list[-1]}"
)
has_wallpaper_been_set: bool = self._check_system_exitcode(exitcode)
if self.config_notify:
self._notify_user()
return has_wallpaper_been_set
# NOTE: Consider avoiding nested functions.
def schedule_wallpapers(self) -> None:
def _schedule_background_wallpapers() -> BackgroundScheduler:
from apscheduler.schedulers.background import BackgroundScheduler
scheduler = BackgroundScheduler()
# Create a scheduled job for every changing time
# NOTE: This should be a function.
for changing_time in range(len(self.config_changing_times)):
clean_time = self._clean_times(changing_time)
scheduler.add_job(
self.set_wallpaper_by_time,
trigger=CronTrigger(
hour=clean_time[0], minute=clean_time[1], second=clean_time[2]
),
)
scheduler.start()
logger.info("The background scheduler has been started.")
return scheduler
def _schedule_blocking_wallpapers() -> None:
from apscheduler.schedulers.blocking import BlockingScheduler
scheduler = BlockingScheduler()
# Create a scheduled job for every changing time
# NOTE: Thisshould be a function.
for changing_time in range(len(self.config_changing_times)):
clean_time = self._clean_times(changing_time)
scheduler.add_job(
self.set_wallpaper_by_time,
trigger=CronTrigger(
hour=clean_time[0], minute=clean_time[1], second=clean_time[2]
),
)
logger.info("The blocking scheduler has been started.")
scheduler.start()
if self.config_systray:
import wallman.wallman_systray as systray
from functools import partial
scheduler: BackgroundScheduler = _schedule_background_wallpapers()
menu: systray.Menu = systray.Menu(
systray.item(
"Re-Set Wallpaper",
partial(
systray.set_wallpaper_again,
wallpaper_setter=self.set_wallpaper_by_time,
),
),
systray.item(
"Reroll Wallpapers",
partial(
systray.reroll_wallpapers,
wallpaper_chooser=self._choose_wallpaper_set,
wallpaper_setter=self.set_wallpaper_by_time,
),
),
systray.item(
"Quit",
partial(systray.on_quit, shutdown_scheduler=scheduler.shutdown),
),
)
icon = systray.Icon(
"wallman_icon", systray.icon_image, "My Tray Icon", menu
)
icon.run()
else:
_schedule_blocking_wallpapers()

View file

@ -1,40 +0,0 @@
from os import chdir
import logging
from PIL import Image
from pystray import Icon, MenuItem as item, Menu # noqa: F401
# Use logger that is also in wallman_lib
logger = logging.getLogger("wallman")
# This should always be ran with "set_wallpaper_by_time" as input!
def set_wallpaper_again(icon, item, wallpaper_setter): # noqa: F811
logging.info("Re-Setting wallpaper due to systray input.")
wallpaper_setter()
def reroll_wallpapers(icon, item, wallpaper_chooser, wallpaper_setter): # noqa: F811
logging.info(
"Rerolling Wallpaper sets and resetting wallpaper due to systray input"
)
wallpaper_chooser()
wallpaper_setter()
# This should always be ran with "scheduler.shutdown" as input!
def on_quit(icon, item, shutdown_scheduler): # noqa: F811
logging.info("Shutting down wallman due to systray input.")
shutdown_scheduler()
icon.stop()
chdir("/etc/wallman/icons/")
try:
icon_image: Image.Image = Image.open("systrayIcon.jpg")
except FileNotFoundError:
logger.error(
"/etc/wallman/icons/systrayIcon.jpg has not been found, wallman will launch without a systray."
)
print(
"ERROR: /etc/wallman/icons/systrayIcon.jpg has not been found, wallman will launch without a systray."
)