Compare commits

..

81 commits

Author SHA1 Message Date
Emma Nora Theuer
018a651d28 Add various TODOs. 2024-10-16 19:39:13 +02:00
Emma Nora Theuer
49c7cc9a05 Update code to reflect changes in wallman_systray.py 2024-10-16 18:41:54 +02:00
Emma Nora Theuer
e845bccdae Significantly improved code readability 2024-10-16 18:41:22 +02:00
Emma Nora Theuer
c169438896 Fix bug where certain files wouldn't be included 2024-09-02 16:57:21 +02:00
Emma Nora Theuer
b3659914cd Fixed a bug where use of the blocking scheduler was not correctly logged 2024-09-02 16:56:13 +02:00
Emma Nora Theuer
d21fd29dff Fix bug that always resulted in a FileNotFoundError 2024-09-02 16:38:52 +02:00
Emma Nora Theuer
b6f42fbf97 Update version 2024-09-02 16:37:24 +02:00
Emma Nora Theuer
6f1d11a494 Update Version 2024-09-02 16:35:36 +02:00
Emma Nora Theuer
34590a6afe Several fixed and version update 2024-09-02 16:35:26 +02:00
Emma Nora Theuer
70f93f4405 Update version 2024-09-02 16:34:55 +02:00
Emma Nora Theuer
c0c83246e3 Update version and introduce major new build commands 2024-09-02 13:57:43 +02:00
Emma Nora Theuer
72c736e6cd Update version 2024-09-02 13:56:46 +02:00
Emma Nora Theuer
594ee118b6 Update verion number 2024-09-02 13:56:21 +02:00
Emma Nora Theuer
2515d2d411 Update version number 2024-09-02 13:41:57 +02:00
Emma Nora Theuer
28b13ab589 Add distfiles directory for build compatibility 2024-09-02 13:41:40 +02:00
Emma Nora Theuer
3477c51b3d Update version number 2024-09-02 13:27:05 +02:00
Emma Nora Theuer
01983bfea6 Update to reflect changes in README.org 2024-09-02 13:26:07 +02:00
Emma Nora Theuer
8523929abc Update documentation 2024-09-02 13:25:50 +02:00
Emma Nora Theuer
d3d2f8a829 Change location of systray icon 2024-09-02 13:16:58 +02:00
Emma Nora Theuer
10dabc805c Change location of logfile 2024-09-02 13:16:20 +02:00
Emma Nora Theuer
5a913e25d8 Initial commit 2024-09-02 13:13:27 +02:00
Emma Nora Theuer
5e0fd1f12b update default loglevel 2024-09-02 13:08:14 +02:00
Emma Nora Theuer
61a2962cb7 Include new dependencies and update version number 2024-09-01 20:08:46 +02:00
Emma Nora Theuer
02354022fd Add logo and icons to Manifest 2024-09-01 20:03:59 +02:00
Emma Nora Theuer
291b45ec58 Update to reflect changes in README.org 2024-09-01 20:00:25 +02:00
Emma Nora Theuer
d69f539dd1 Add documentation for systray 2024-09-01 20:00:01 +02:00
Emma Nora Theuer
3c77a5f161 Change location 2024-09-01 19:59:13 +02:00
Emma Nora Theuer
7fc02ac4a8 Adjust file location 2024-09-01 19:58:26 +02:00
Emma Nora Theuer
138053d8d1 Implement support for a systray 2024-09-01 19:29:04 +02:00
Emma Nora Theuer
fa13c7f135 Adjust naming of the function that actually runs the wallpapers 2024-09-01 19:28:34 +02:00
Emma Nora Theuer
e0aaed8e36 Initial Commit 2024-09-01 19:27:34 +02:00
Emma Nora Theuer
72b0d4b60f Add Systray option to config file 2024-09-01 19:18:59 +02:00
Emma Nora Theuer
9d761e355b Initial Commit 2024-09-01 17:11:27 +02:00
Emma Nora Theuer
12dd9d66eb Initial Commit 2024-09-01 17:02:25 +02:00
Emma Nora Theuer
42c59597bf Remove function annotations for better linting 2024-07-21 22:41:39 +02:00
Emma Nora Theuer
d69e03bcc0 Update Version 2024-06-20 18:02:18 +02:00
Emma Nora Theuer
55a753ac20 Update Version 2024-06-20 18:02:00 +02:00
Emma Nora Theuer
c9b76190f0 Adjust version number 2024-06-20 17:57:31 +02:00
Emma Nora Theuer
c6c4ba5a48 Adjust default loglevel. 2024-06-20 17:57:20 +02:00
Emma Nora Theuer
4aa7aa8577 Update Version 2024-06-09 21:47:28 +02:00
Emma Nora Theuer
22ae8e095f Clean up whitespace and comments 2024-06-09 21:38:08 +02:00
Emma Nora Theuer
8592c226e7 Update version number 2024-06-09 21:37:53 +02:00
Emma Nora Theuer
391d60822a Add loglevel option to sample config 2024-06-09 21:26:00 +02:00
Emma Nora Theuer
5fa2446830 Add support for defining the loglevel in the config. 2024-06-09 21:25:26 +02:00
Emma Nora Theuer
c4aa64fdd9 Update Version number 2024-06-09 21:24:40 +02:00
Emma Nora Theuer
155aad6fb7 Update to reflect changes in README.org 2024-06-09 21:23:06 +02:00
Emma Nora Theuer
93c5d7c938 Add documentation for new feature, remove done TODO. 2024-06-09 21:22:37 +02:00
Emma Nora Theuer
38a83d5e09 Update Version 2024-06-09 20:29:10 +02:00
Emma Nora Theuer
1f1d181641 Update Version 2024-06-09 20:28:47 +02:00
Emma Nora Theuer
67ba450c36 Adjust default logging level 2024-06-09 20:22:35 +02:00
Emma Nora Theuer
e7a8243d6d Update version number. 2024-06-09 20:20:21 +02:00
Emma Nora Theuer
c4bd6c2007 Significantly improve debugging and error output if a specified wallpaper has not been found. 2024-06-09 20:19:15 +02:00
Emma Nora Theuer
2b3c1518dc Update Version 2024-06-08 06:44:52 +02:00
Emma Nora Theuer
6f33d42600 Update Version 2024-06-08 06:44:42 +02:00
Emma Nora Theuer
76d2f164dd Update Version 2024-06-08 06:44:30 +02:00
Emma Nora Theuer
5fb88d7ccb Adjusted loglevel 2024-06-08 06:37:08 +02:00
Emma Nora Theuer
74a275b423 Fixed typo 2024-06-08 06:36:12 +02:00
Emma Nora Theuer
83e6157cad Adjusted version number 2024-06-08 06:35:52 +02:00
Emma Nora Theuer
b5c027a01a Slightly adjust backend for unittesting. 2024-06-07 22:41:41 +02:00
Emma Nora Theuer
246152537e Update version 2024-06-06 17:55:35 +02:00
Emma Nora Theuer
8918f934aa Update version 2024-06-06 17:54:58 +02:00
Emma Nora Theuer
d8a46f2913 Adjust loglevel 2024-06-06 17:49:36 +02:00
Emma Nora Theuer
4c114c0e07 Adjust version number 2024-06-06 17:48:33 +02:00
Emma Nora Theuer
1bda243430 Fix bug in config validator that broke the program 2024-06-06 17:47:44 +02:00
Emma Nora Theuer
647837be27 Remove outdated file 2024-06-05 16:18:02 +02:00
Emma Nora Theuer
aa927cd1db upgrade to new version 2024-06-05 16:17:00 +02:00
Emma Nora Theuer
1b4bb676f7 Updated version number 2024-06-05 15:39:10 +02:00
Emma Nora Theuer
61bcd19eb7 Update to reflect changes in README.org 2024-06-05 15:38:37 +02:00
Emma Nora Theuer
6c6e47a1c0 Remove done TODO and add additional documentation for fallback wallpapers. 2024-06-05 15:38:06 +02:00
Emma Nora Theuer
f329f3b455 Add setting fallback wallpaper if the selected wallpaper can't be found, adjusted parts of logic for unittesting 2024-06-05 15:33:02 +02:00
Emma Nora Theuer
fe657bdb02 Adjusted the config validator backend to make unittests possible 2024-06-05 15:07:21 +02:00
Emma Nora Theuer
03596e0423 Improve clarity 2024-06-04 03:30:47 +02:00
Emma Nora Theuer
e3a3cd2077 Update to reflect changes in README.org 2024-06-04 03:29:58 +02:00
Emma Nora Theuer
ce24b34eb1 Update to reflect changes in README.org 2024-06-04 03:26:34 +02:00
Emma Nora Theuer
c98d206ca3 Update instructions for manual packaging. 2024-06-04 03:26:18 +02:00
Emma Nora Theuer
a834483698 Adjust naming. 2024-06-04 03:18:57 +02:00
Emma Nora Theuer
95fc359073 Adjust naming. 2024-06-04 03:17:39 +02:00
Emma Nora Theuer
5a7b2fd43c Fix Typos and improve structuring. 2024-06-04 03:16:31 +02:00
Emma Nora Theuer
f509f0b696 Add documentation on packaging. 2024-06-04 03:12:54 +02:00
Emma Nora Theuer
3329eef36f Initial Commit 2024-06-04 02:58:18 +02:00
Emma Nora Theuer
0587d5a983 Corrected version number 2024-06-04 02:53:37 +02:00
17 changed files with 451 additions and 119 deletions

View file

@ -1,2 +1,6 @@
graft src graft src
include src/*.py
graft icons
graft distfiles
include sample_config.toml include sample_config.toml
exclude README.org

View file

@ -12,6 +12,7 @@ Wallman currently has three main features:
+ Reading configuration details from a TOML file + Reading configuration details from a TOML file
+ Choosing from a set of Wallpapers and then setting the rest of the wallpapers accordingly + Choosing from a set of Wallpapers and then setting the rest of the wallpapers accordingly
+ Settings Wallpapers at a specific time of the day + Settings Wallpapers at a specific time of the day
+ Be controlled via a systray
* Installation * Installation
** Depedencies ** Depedencies
@ -21,30 +22,54 @@ Wallman currently has three main features:
+ feh (Used for setting the wallpapers, hard dependency) + feh (Used for setting the wallpapers, hard dependency)
*** Optional *** Optional
+ libnotify (for desktop notification support) + libnotify (for desktop notification support)
+ pillow (For systray support)
+ pystray (For systray support)
*** Build dependencies *** Build dependencies
+ setuptools + setuptools
+ build + build
** Installing with package Manager
*** Gentoo
This program, as of now, can be installed very easily on gentoo. Just follow these instructions:
#+BEGIN_SRC shell
git clone https://git.entheuer.de/emma/Wallman.git
doas eselect repository create wallman
doas cp -rf Wallman/distfiles/Gentoo/wallman /var/db/repos/
doas emerge -av wallman
#+END_SRC
A proper portage overlay will be created soon, so that updates can be handled automatically.
*** Arch Linux
Support for Arch Linux will be added soon.
*** Others
I will potentially write a version for nixpkgs and will also bundle wallman as a flatpak.
** Installing with pip ** Installing with pip
Wallman is available on PYPI. Simply run: Wallman is available on PyPI. Simply run:
#+BEGIN_SRC shell #+BEGIN_SRC shell
pip install wallman pip install wallman
#+END_SRC #+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 ** Installing manually
+ Clone this git repo + Install libnotify and feh from your package manager
+ Create a log file and a configuration file:
#+BEGIN_SRC shell #+BEGIN_SRC shell
mkdir -p ~/.local/share/wallman pip install APScheduler pystray pillow
git clone https://git.entheuer.de/emma/Wallman.git
cd Wallman/
sudo mkdir -p /var/log/wallman
sudo chmod 733 /var/log/wallman
mkdir -p ~/.config/wallman mkdir -p ~/.config/wallman
touch ~/.local/share/wallman/wallman.log
cp sample_config.toml ~/.config/wallman/wallman.toml cp sample_config.toml ~/.config/wallman/wallman.toml
doas mkdir -p /etc/wallman/
cp -R icons/ /etc/wallman/
doas cp src/wallman.py /usr/bin/wallman
doas cp src/wallman_lib.py /usr/bin/wallman_lib.py
doas cp src/wallman_systray.py /usr/bin/wallman_systray.py
doas chmod +x /usr/bin/wallman
#+END_SRC #+END_SRC
+ Edit the sample config + 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 + Profit
* Configuration * Configuration
@ -52,7 +77,7 @@ This is a short guide on how to correctly configure wallman. Look in the sample
** TOML Dictionaries ** 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. 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 *** general
In general, you need to always define 3 variables and you can optionally add two more: In general, you need to always define 3 variables and you can optionally add three more:
+ enable_wallpaper_sets: bool + enable_wallpaper_sets: bool
A simple switch that states if you want to use different sets of wallpapers or not. A simple switch that states if you want to use different sets of wallpapers or not.
+ used_sets: list + used_sets: list
@ -62,7 +87,11 @@ In general, you need to always define 3 variables and you can optionally add two
+ Optional: notify: bool + 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. 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: bool + 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. Wallpaper to be set if an error is found in the config or the wallpaper intended to be set cannot be found. Defaults to None. 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 exit with Code 1. 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.
+ 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.
*** changing_times *** 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. 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.
@ -78,13 +107,11 @@ The keys in the dictionary once again do not matter, the names of the keys in ea
+ Add documentation for developers + Add documentation for developers
** Technical Details ** Technical Details
+ Improve Modularity + Improve Modularity (Partially done)
+ Make the enabled flag in wallpaper_sets actually useful by making the used_sets field optional + 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 + Drop the feh dependecy and set wallpapers using pywlroots or python-xlib
** Features ** 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 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 wallpapers that change by the weather
+ Add support for live wallpapers + Add support for live wallpapers

View file

@ -0,0 +1 @@
DIST wallman-1.4.2.4.tar.gz 871198 BLAKE2B 02ccfa69e14b73eff667ecf4707fcebd08ba63362a6e25ae77bef96ff77d8723e417e14e8586f2b8a9e0b23f29a1be8b7e1c0cab10a7f242dc8a7b2fe418cfe4 SHA512 87f2cad40f6db418dc4a94a259b4c491e69fc0f7bdf121196679270492227449f79751f40467d6f50e4bf7598e38d78853818ac9df8cfa96a7dc34698128ac71

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE pkgmetadata SYSTEM "https://www.gentoo.org/dtd/metadata.dtd">
<pkgmetadata>
<maintainer type="person">
<name>Emma Nora Theuer</name>
<email>gentoo@entheuer.de</email>
</maintainer>
<upstream>
<remote-id type="pypi">Wallman</remote-id>
</upstream>
<longdescription>
Wallman is a small python program meant to bring dynamic wallpapers
to standalone X11 Window managers and Wayland compositors.
It uses APScheduler in the background. For setting wallpaperss
It currently relies on feh in the background. libnotify is used for
Desktop notifications.
Wallman reads it's configuration data from a TOML file and logs to
~/.local/share/wallman/wallman.log
</longdescription>
</pkgmetadata>

View file

@ -0,0 +1,70 @@
# Copyright 1999-2024 Gentoo Authors
# Distributed under the terms of the MIT License
EAPI=8
DISTUTILS_USE_PEP517=setuptools
PYTHON_COMPAT=( python3_{11,12} )
inherit distutils-r1 pypi
DESCRIPTION="A python program that sets dynamic wallpapers on minimalistic Window Managers."
HOMEPAGE="https://git.entheuer.de/emma/wallman/"
SRC_URI="$(pypi_sdist_url "${PN^}" "${PV}")"
LICENSE="MIT"
SLOT="0"
KEYWORDS="~amd64 ~x86"
RDEPEND="
dev-python/APScheduler[${PYTHON_USEDEP}]
dev-python/pillow[${PYTHON_USEDEP}]
dev-python/pystray[${PYTHON_USEDEP}]
media-gfx/feh
x11-libs/libnotify
"
BDEPEND="
dev-python/setuptools[${PYTHON_USEDEP}]
dev-python/wheel[${PYTHON_USEDEP}]
dev-python/certifi[${PYTHON_USEDEP}]
"
src_prepare() {
distutils-r1_python_prepare_all
}
#src_prepare() {
# mv src/* . || die "Failed to move source files"
#}
python_compile() {
distutils-r1_python_compile -j1
}
python_install() {
distutils-r1_python_install
# Add a symlink to make the script callable from the commandline
local scriptname="wallman.py"
local target="/usr/bin/wallman"
local scriptpath="$(python_get_sitedir)/${scriptname}"
fperms +x "${scriptpath}"
dosym "${scriptpath}" "${target}"
# Copy files into /etc/wallman
dodir /etc/wallman
insinto /etc/wallman
newins "${S}/sample_config.toml" "wallman.toml"
doins -r "${S}/icons/" "icons/"
# Create logfile directory
dodir /var/log/wallman
keepdir /var/log/wallman
fperms 0733 /var/log/wallman
# Copy .desktop file into the appropriate location
insinto /usr/share/applications
newins "${S}/distfiles/wallman.desktop" "wallman.desktop"
}
#src_install() {
#}
pkg_postinst() {
elog "Wallman has been installed. A sample configuration file called wallman.toml is located in /etc/wallman. Copy that file into ~/.config/wallman/wallman.toml to configure wallman."
elog "A log file for Wallman can be found in /etc/log/wallman"
}

View file

@ -0,0 +1,3 @@
masters = gentoo
thin-manifests = true
sign-manifests = false

View file

@ -0,0 +1 @@
8

View file

@ -0,0 +1 @@
wallman

8
distfiles/wallman.desktop Executable file
View file

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

BIN
icons/WallmanLogo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 KiB

BIN
icons/systrayIcon.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,34 +1,38 @@
# Table of Contents # Table of Contents
1. [Overwiev](#org19ef638) 1. [Overwiev](#orga779aae)
1. [What is this?](#org148aad0) 1. [What is this?](#orgf7b412d)
2. [What can it do?](#org0041bf1) 2. [What can it do?](#org935ec0e)
2. [Installation](#orgc40ee8b) 2. [Installation](#org022a1fd)
1. [Depedencies](#org2cb62ef) 1. [Depedencies](#org90be55c)
1. [Always Required](#org0d0b0f7) 1. [Always Required](#orgadb7aa8)
2. [Optional](#orgf04ec77) 2. [Optional](#org407e4c9)
3. [Build dependencies](#org3951087) 3. [Build dependencies](#orgab711aa)
2. [Installing with pip](#org24bde1c) 2. [Installing with package Manager](#org2a19ad0)
3. [Installing with package Manager](#org9575c55) 1. [Gentoo](#org6686b86)
4. [Installing manually](#org2c63e0f) 2. [Arch Linux](#org4eb492d)
3. [Configuration](#org812c501) 3. [Others](#orga6b4e6a)
1. [TOML Dictionaries](#org51e3333) 3. [Installing with pip](#org1b5b1b3)
1. [general](#org79747a5) 4. [Installing manually](#org050e242)
2. [changing<sub>times</sub>](#orgc425813) 3. [Configuration](#orgf368a5c)
3. [The other dictionaries](#org9f47b06) 1. [TOML Dictionaries](#org05ab08e)
4. [TODOs](#orgc26c243) 1. [general](#orgfa7800e)
1. [Structuring](#org8dd22d4) 2. [changing<sub>times</sub>](#org2778aa9)
2. [Technical Details](#org6103451) 3. [The other dictionaries](#orgf21f2d8)
3. [Features](#org38d78ba) 4. [TODOs](#org8cbebae)
1. [Structuring](#orgb43553d)
2. [Technical Details](#org0a633fb)
3. [Features](#org1c5725d)
<a id="org19ef638"></a> <a id="orga779aae"></a>
# Overwiev # Overwiev
<a id="org148aad0"></a> <a id="orgf7b412d"></a>
## What is this? ## What is this?
@ -37,7 +41,7 @@ This version is an early Alpha. As of now, it supports the most important featur
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. 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> <a id="org935ec0e"></a>
## What can it do? ## What can it do?
@ -46,19 +50,20 @@ Wallman currently has three main features:
- Reading configuration details from a TOML file - Reading configuration details from a TOML file
- Choosing from a set of Wallpapers and then setting the rest of the wallpapers accordingly - Choosing from a set of Wallpapers and then setting the rest of the wallpapers accordingly
- Settings Wallpapers at a specific time of the day - Settings Wallpapers at a specific time of the day
- Be controlled via a systray
<a id="orgc40ee8b"></a> <a id="org022a1fd"></a>
# Installation # Installation
<a id="org2cb62ef"></a> <a id="org90be55c"></a>
## Depedencies ## Depedencies
<a id="org0d0b0f7"></a> <a id="orgadb7aa8"></a>
### Always Required ### Always Required
@ -67,14 +72,16 @@ Wallman currently has three main features:
- feh (Used for setting the wallpapers, hard dependency) - feh (Used for setting the wallpapers, hard dependency)
<a id="orgf04ec77"></a> <a id="org407e4c9"></a>
### Optional ### Optional
- libnotify (for desktop notification support) - libnotify (for desktop notification support)
- pillow (For systray support)
- pystray (For systray support)
<a id="org3951087"></a> <a id="orgab711aa"></a>
### Build dependencies ### Build dependencies
@ -82,58 +89,91 @@ Wallman currently has three main features:
- build - build
<a id="org24bde1c"></a> <a id="org2a19ad0"></a>
## Installing with package Manager
<a id="org6686b86"></a>
### Gentoo
This program, as of now, can be installed very easily on gentoo. Just follow these instructions:
git clone https://git.entheuer.de/emma/Wallman.git
doas eselect repository create wallman
doas cp -rf Wallman/distfiles/Gentoo/wallman /var/db/repos/
doas emerge -av wallman
A proper portage overlay will be created soon, so that updates can be handled automatically.
<a id="org4eb492d"></a>
### Arch Linux
Support for Arch Linux will be added soon.
<a id="orga6b4e6a"></a>
### Others
I will potentially write a version for nixpkgs and will also bundle wallman as a flatpak.
<a id="org1b5b1b3"></a>
## Installing with pip ## Installing with pip
Wallman is available on PYPI. Simply run: Wallman is available on PyPI. Simply run:
pip install wallman pip install wallman
<a id="org9575c55"></a> <a id="org050e242"></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 ## Installing manually
- Clone this git repo - Install libnotify and feh from your package manager
- Create a log file and a configuration file:
mkdir -p ~/.local/share/wallman pip install APScheduler pystray pillow
git clone https://git.entheuer.de/emma/Wallman.git
cd Wallman/
sudo mkdir -p /var/log/wallman
sudo chmod 733 /var/log/wallman
mkdir -p ~/.config/wallman mkdir -p ~/.config/wallman
touch ~/.local/share/wallman/wallman.log
cp sample_config.toml ~/.config/wallman/wallman.toml cp sample_config.toml ~/.config/wallman/wallman.toml
doas mkdir -p /etc/wallman/
cp -R icons/ /etc/wallman/
doas cp src/wallman.py /usr/bin/wallman
doas cp src/wallman_lib.py /usr/bin/wallman_lib.py
doas cp src/wallman_systray.py /usr/bin/wallman_systray.py
doas chmod +x /usr/bin/wallman
- Edit the sample config - 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 - Profit
<a id="org812c501"></a> <a id="orgf368a5c"></a>
# Configuration # Configuration
This is a short guide on how to correctly configure wallman. Look in the sample config for additional context. This is a short guide on how to correctly configure wallman. Look in the sample config for additional context.
<a id="org51e3333"></a> <a id="org05ab08e"></a>
## TOML Dictionaries ## 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. 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> <a id="orgfa7800e"></a>
### general ### general
In general, you need to always define 3 variables and you can optionally add two more: In general, you need to always define 3 variables and you can optionally add three more:
- enable<sub>wallpaper</sub><sub>sets</sub>: bool - enable<sub>wallpaper</sub><sub>sets</sub>: bool
A simple switch that states if you want to use different sets of wallpapers or not. A simple switch that states if you want to use different sets of wallpapers or not.
@ -144,17 +184,21 @@ In general, you need to always define 3 variables and you can optionally add two
- Optional: notify: bool - 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. 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 - 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. Wallpaper to be set if an error is found in the config or the wallpaper intended to be set cannot be found. Defaults to None. 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 exit with Code 1. If The config is written correctly but the wallpaper intended to be set can&rsquo;t be found, wallman will set the fallback wallpaper and continue to try setting future wallpapers.
- 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 &ldquo;true&rdquo;. 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.
<a id="orgc425813"></a> <a id="org2778aa9"></a>
### changing<sub>times</sub> ### 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. 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> <a id="orgf21f2d8"></a>
### The other dictionaries ### The other dictionaries
@ -162,12 +206,12 @@ The other dictionaries must always have the names of the wallpaper sets from use
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. 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> <a id="org8cbebae"></a>
# TODOs # TODOs
<a id="org8dd22d4"></a> <a id="orgb43553d"></a>
## Structuring ## Structuring
@ -175,21 +219,19 @@ The keys in the dictionary once again do not matter, the names of the keys in ea
- Add documentation for developers - Add documentation for developers
<a id="org6103451"></a> <a id="org0a633fb"></a>
## Technical Details ## Technical Details
- Improve Modularity - Improve Modularity (Partially done)
- Make the enabled flag in wallpaper<sub>sets</sub> actually useful by making the used<sub>sets</sub> field optional - 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 - Drop the feh dependecy and set wallpapers using pywlroots or python-xlib
<a id="org38d78ba"></a> <a id="org1c5725d"></a>
## Features ## 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 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 wallpapers that change by the weather
- Add support for live wallpapers - Add support for live wallpapers

View file

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "wallman" name = "wallman"
version = "1.3.0b1" version = "1.4.2.4"
authors = [ authors = [
{name = "Emma Nora Theuer", email = "wallman@entheuer.de"}, {name = "Emma Nora Theuer", email = "wallman@entheuer.de"},
] ]
@ -24,6 +24,8 @@ classifiers = [
] ]
dependencies = [ dependencies = [
"APScheduler", "APScheduler",
"pillow",
"pystray",
'importlib-metadata; python_version<"3.10"', 'importlib-metadata; python_version<"3.10"',
] ]

View file

@ -6,6 +6,8 @@ used_sets = ["anime", "nature"]
wallpapers_per_set = 5 wallpapers_per_set = 5
notify = False notify = False
fallback_wallpaper = "/path/to/paper" fallback_wallpaper = "/path/to/paper"
loglevel = "INFO"
systray = true
# Enter the hours at which you want the wallpaper to change. # 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. # If the script is called between one of this times, it will go back to the previous time.

View file

@ -6,7 +6,7 @@ def main():
logic = wallman_lib.WallpaperLogic() logic = wallman_lib.WallpaperLogic()
validator.validate_config() validator.validate_config()
logic.set_wallpaper_by_time() logic.set_wallpaper_by_time()
logic.schedule_wallpapers() logic.run_wallpapers()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View file

@ -1,33 +1,18 @@
#!/usr/bin/env python3
from sys import exit from sys import exit
from os import chdir, getenv, system from os import chdir, getenv, system
import logging import logging
import tomllib import tomllib
from datetime import datetime, time from datetime import datetime, time
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger from apscheduler.triggers.cron import CronTrigger
# setup logging # Setup Logging. NOTE: Declaration as a global variable is necessary to ensure correct functionality across multiple modules.
chdir(str(getenv("HOME")) + "/.local/share/wallman/") logger = logging.getLogger("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): class ConfigError(Exception):
pass pass
class _ConfigLib: class _ConfigLib:
def _initialize_config(self) -> dict: # Initializes the most important config values. TODO: Add handling for the empty config case
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): def __init__(self):
self.config_file: dict = self._initialize_config() # Full config self.config_file: dict = self._initialize_config() # Full config
# Dictionaries # Dictionaries
@ -38,11 +23,46 @@ class _ConfigLib:
self.config_used_sets: list = self.config_general["used_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_wallpapers_per_set: int = self.config_general["wallpapers_per_set"]
self.config_total_changing_times: int = len(self.config_changing_times) self.config_total_changing_times: int = len(self.config_changing_times)
self.config_log_level: str = self.config_general.get("loglevel", "INFO").upper()
# HACK: Add a function to handle these try/except blocks cleanlier.
try: try:
self.config_notify = self.config_general["notify"] self.config_notify: bool = self.config_general["notify"]
except KeyError: except KeyError:
self.config_notify = False self.config_notify: bool = False
logger.warning("'notify' is not set in dictionary general in the config file, defaulting to 'false'.") logger.warning("'notify' is not set in dictionary general in the config file, defaulting to 'false'.")
try:
self.config_systray = self.config_general["systray"]
except KeyError:
self.config_systray = True
logger.warning("'systray' is not set in the dictionary general in the config file, defaulting to 'true'.")
# Setup logging
self._set_log_level()
# Setup systray.
if self.config_systray:
self._initialize_systray()
# Read config. TODO: Add error handling for the config not found case.
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
# HACK on this to avoid double importing of wallman_systray due to variable scope. Idea: Global variable or Variable that is inherited?
def _initialize_systray(self):
try:
import wallman_systray
except (ImportError, FileNotFoundError):
self.config_systray = False
def _set_log_level(self):
global logging
global logger
chdir("/var/log/wallman/")
numeric_level = getattr(logging, self.config_log_level, logging.INFO)
logger.setLevel(numeric_level)
logging.basicConfig(filename="wallman.log", encoding="utf-8", level=numeric_level)
def _set_fallback_wallpaper(self): def _set_fallback_wallpaper(self):
if self.config_general["fallback_wallpaper"]: if self.config_general["fallback_wallpaper"]:
@ -53,94 +73,121 @@ class _ConfigLib:
raise ConfigError("An error occured and no fallback wallpaper has been set, exiting...") raise ConfigError("An error occured and no fallback wallpaper has been set, exiting...")
class ConfigValidity(_ConfigLib): class ConfigValidity(_ConfigLib):
# TODO: Add handling for the empty config case.
def __init__(self): def __init__(self):
super().__init__() super().__init__()
def _check_fallback_wallpaper(self): def _check_fallback_wallpaper(self):
if self.config_general["fallback_wallpaper"]: if self.config_general["fallback_wallpaper"]:
logger.debug("A fallback wallpaper has been defined.") logger.debug("A fallback wallpaper has been defined.")
return True
else: else:
logger.warning("No fallback wallpaper has been provided. If the config is written incorrectly, the program will not be able to be executed.") logger.warning("No fallback wallpaper has been provided. If the config is written incorrectly, the program will not be able to be executed.")
return False
def _check_wallpapers_per_set_and_changing_times(self) -> None: def _check_wallpapers_per_set_and_changing_times(self) -> bool:
# Check if the amount of wallpapers_per_set and given changing times match # Check if the amount of wallpapers_per_set and given changing times match
if self.config_total_changing_times == self.config_wallpapers_per_set: 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") logger.debug("The amount of changing times and wallpapers per set is set correctly")
return True
else: else:
try: try:
self._set_fallback_wallpaper() 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.") logger.error("The amount of changing_times and the amount of wallpapers_per_set does not match, 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.") print("ERROR: The amount of changing_times and the amount of wallpapers_per_set does not match, the fallback wallpaper has been set.")
exit(1) return False
except ConfigError: except ConfigError:
logger.critical("The amount of changing times and the amount of wallpapers per set does not match, exiting...") 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...") raise ConfigError("Please provide an amount of changing_times equal to wallpapers_per_set, exiting...")
def _check_general_validity(self) -> None: def _check_general_validity(self) -> bool:
# FIXME!
# HACK: Adjust it to check for the actually required variables existing rather than check if a number of options is set, which is highly error prone.
if len(self.config_general) < 3: if len(self.config_general) < 3:
try: try:
self._set_fallback_wallpaper() self._set_fallback_wallpaper()
logger.error("An insufficient amount of elements has been provided for general, the fallback wallpaper has been set.") 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.") print("ERROR: An insufficient amount of wallpapers has been provided for general, the fallback wallpaper has been set.")
exit(1) return False
except ConfigError: except ConfigError:
logger.critical("An insufficient amount of elements for general has been provided, exiting...") logger.critical("An insufficient amount of elements for general has been provided, exiting...")
raise ConfigError("general should have at least 3 elements, exiting...") raise ConfigError("general should have at least 3 elements, exiting...")
def _check_wallpaper_dicts(self)-> None: else:
logger.debug("A valid amount of options has been provided in general")
return True
def _check_wallpaper_dicts(self):
# This block checks if a dictionary for each wallpaper set exists # This block checks if a dictionary for each wallpaper set exists
for wallpaper_set in self.config_used_sets: for wallpaper_set in self.config_used_sets:
if wallpaper_set in self.config_file: if wallpaper_set in self.config_file:
logger.debug(f"The dictionary {wallpaper_set} has been found in config.") logger.debug(f"The dictionary {wallpaper_set} has been found in config.")
return True
# TODO split this into smaller pieces. This goes too deep.
else: else:
try: try:
self._set_fallback_wallpaper() self._set_fallback_wallpaper()
logger.error(f"The dictionary {wallpaper_set} has not been found in the config, the fallback wallpaper has been set.") 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.") print(f"ERROR: The dictionary {wallpaper_set} has not been found in the config, the fallback wallpaper has been set.")
exit(1) return False
except ConfigError: except ConfigError:
logger.critical(f"No dictionary {wallpaper_set} has been found in the config exiting...") 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...") raise ConfigError(f"The dictionary {wallpaper_set} has not been found in the config, exiting...")
def _check_wallpaper_amount(self) -> None: def _check_wallpaper_amount(self):
# This block checks if if each wallpaper set dictionary provides enough wallpapers to satisfy wallpapers_per_set # 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: for wallpaper_set in self.config_used_sets:
if len(self.config_file[wallpaper_set]) == self.config_wallpapers_per_set: if len(self.config_file[wallpaper_set]) == self.config_wallpapers_per_set:
logger.debug(f"Dictionary {wallpaper_set} has sufficient values.") logger.debug(f"Dictionary {wallpaper_set} has sufficient values.")
return True
else: else:
try: try:
self._set_fallback_wallpaper() self._set_fallback_wallpaper()
logger.error(f"The Dictionary {wallpaper_set} does not have sufficient entries, the fallback wallpaper has been set.") 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.") print(f"ERROR: The Dictionaty {wallpaper_set} does not have sufficient entries, the fallback wallpaper has been set.")
exit(1) return False
except ConfigError: except ConfigError:
logger.critical(f"Dictionary {wallpaper_set} does not have sufficient entries, exciting...") 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...") raise ConfigError(f"Dictionary {wallpaper_set} does not have the correct amount of entries, exciting...")
def validate_config(self) -> None: def validate_config(self) -> bool:
self._check_fallback_wallpaper() # NOTE: Consider changing this to exit(-1)
self._check_wallpapers_per_set_and_changing_times() # HACK: Consider using different exit codes for different errors to help users debug.
self._check_general_validity() if not self._check_fallback_wallpaper():
self._check_wallpaper_dicts() pass
self._check_wallpaper_amount() if not self._check_wallpapers_per_set_and_changing_times():
exit(1)
if not self._check_general_validity():
exit(1)
if not self._check_wallpaper_dicts():
exit(1)
if not self._check_wallpaper_amount():
exit(1)
logger.debug("The config file has been validated successfully (No Errors)") logger.debug("The config file has been validated successfully (No Errors)")
return True
# 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(_ConfigLib): class WallpaperLogic(_ConfigLib):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
# NOTE: This looks a bit ugly. Consider pros and cons of adding this into _ConfigLib
self.chosen_wallpaper_set = False self.chosen_wallpaper_set = False
# 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 # Returns a list of a split string that contains a changing time from the config file
def _clean_times(self, desired_time) -> list: def _clean_times(self, desired_time) -> list:
unclean_times = list(self.config_changing_times.values())[desired_time] unclean_times = list(self.config_changing_times.values())[desired_time]
return unclean_times.split(":") 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: def _choose_wallpaper_set(self) -> None:
from random import choice as choose_from from random import choice as choose_from
self.chosen_wallpaper_set = choose_from(self.config_used_sets) self.chosen_wallpaper_set = choose_from(self.config_used_sets)
self.wallpaper_list = list(self.config_file[self.chosen_wallpaper_set].values()) self.wallpaper_list = list(self.config_file[self.chosen_wallpaper_set].values())
logger.debug(f"Chose wallpaper set {self.chosen_wallpaper_set}") 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 # Verify if a given time is in a given range
def _time_in_range(self, start, end, x) -> bool: def _time_in_range(self, start, end, x) -> bool:
if start <= end: if start <= end:
@ -148,35 +195,96 @@ class WallpaperLogic(_ConfigLib):
else: else:
return start <= x or x < end 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) -> 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): def _notify_user(self):
system("notify-send 'Wallman' 'A new Wallpaper has been set.'") system("notify-send 'Wallman' 'A new Wallpaper has been set.'")
logger.debug("Sent desktop notification.") logger.debug("Sent desktop notification.")
def set_wallpaper_by_time(self) -> None: # 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 # Ensure use of a consistent wallpaper set
if self.chosen_wallpaper_set is False: if self.chosen_wallpaper_set is False:
self._choose_wallpaper_set() self._choose_wallpaper_set()
for time_range in range(self.config_total_changing_times - 1): 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 = self._clean_times(time_range) clean_time = self._clean_times(time_range)
clean_time_two = self._clean_times(time_range + 1) clean_time_two = 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. # 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()): 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]}") system(f"feh --bg-scale --no-fehbg --quiet {self.wallpaper_list[time_range]}")
exitcode = system(f"feh --bg-scale --no-fehbg --quiet {self.wallpaper_list[time_range]}")
has_wallpaper_been_set = self._check_system_exitcode(exitcode)
# TODO: Add this check to _notify_user.
if self.config_notify: if self.config_notify:
self._notify_user() self._notify_user()
return return has_wallpaper_been_set
else: else:
continue continue
system(f"feh --bg-scale --no-fehbg {self.wallpaper_list[-1]}") system(f"feh --bg-scale --no-fehbg {self.wallpaper_list[-1]}")
exitcode = system(f"feh --bg-scale --no-fehbg {self.wallpaper_list[-1]}")
has_wallpaper_been_set = self._check_system_exitcode(exitcode)
if self.config_notify: if self.config_notify:
self._notify_user() self._notify_user()
return has_wallpaper_been_set
# NOTE: Consider avoiding nested functions.
def schedule_wallpapers(self): def schedule_wallpapers(self):
scheduler = BlockingScheduler() def _schedule_background_wallpapers():
# Create a scheduled job for every changing time from apscheduler.schedulers.background import BackgroundScheduler
for changing_time in range(len(self.config_changing_times)): scheduler = BackgroundScheduler()
clean_time = self._clean_times(changing_time) # Create a scheduled job for every changing time
scheduler.add_job(self.set_wallpaper_by_time, trigger=CronTrigger(hour=clean_time[0], minute=clean_time[1], second=clean_time[2])) # NOTE: This should be a function.
scheduler.start() for changing_time in range(len(self.config_changing_times)):
logger.info("The scheduler has been started.") 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():
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:
# NOTE: The wallman_systray impomrt should be handled differently. See the note in Config_Validity.
import wallman_systray as systray
from functools import partial
scheduler = _schedule_background_wallpapers()
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()

42
src/wallman_systray.py Normal file
View file

@ -0,0 +1,42 @@
from os import getenv, chdir
import logging
# Use logger that is also in wallman_lib
logger = logging.getLogger("wallman")
try:
from PIL import Image
except ImportError:
logging.error("Couldn't import PIL, wallman will launch without a systray.")
print("Couldn't import PIL, wallman will launch without a systray.")
raise
try:
from pystray import Icon, MenuItem as item, Menu
except ImportError:
logging.error("Couldn't import pystray, wallman will launch without a systray.")
print("Couldn't import pystray, wallman will launch without a systray.")
raise
# This should always be ran with "set_wallpaper_by_time" as input!
def set_wallpaper_again(icon, item, wallpaper_setter):
logging.info("Re-Setting wallpaper due to systray input.")
wallpaper_setter()
def reroll_wallpapers(icon, item, wallpaper_chooser, wallpaper_setter):
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):
logging.info("Shutting down wallman due to systray input.")
shutdown_scheduler()
icon.stop()
chdir("/etc/wallman/icons/")
try:
icon_image = Image.open("systrayIcon.jpg")
except FileNotFoundError:
logger.error("~/.config/wallman/systrayIcon.jpg has not been found, wallman will launch without a systray.")
print("~/.config/wallman/systrayIcon.jpg has not been found, wallman will launch without a systray.")