起因
从 KDE 换到 Gnome 之后,最让我思念的功能就是自动更换壁纸了。虽然 Gnome 下也有不少 Extensions 可以做到更换壁纸的效果,但是无奈无法完全满足我的需求其实就是 KDE 自带的实现:
- 对于长宽比不合适的图片,不是单纯的进行拉伸、居中或者平铺,而是:
先保持图片比例拉伸 -> 居中显示 -> 周围的黑边平铺填充
- 可以对添加的目录进行递归搜索,并且一次性添加上万张图片也不会崩溃。
- 随机更换壁纸而不是使用固定的顺序,支持跳过重复壁纸的功能。
在寻找相关工具未果之后,我决定利用 ImageMagick 自己造一个轮子。
思路
- 使用
find
命令生成包含所有图片地址的列表。 - 从列表中随机挑选一张图片。
- 利用
convert
(ImageMagick) 转换处理图片。 - 使用
gsettings
设置壁纸。 - 使用
systemd
定期执行脚本。
Bash 脚本
首先写一个 Bash 脚本,实现更换壁纸的目的,同时为了响应速度和硬盘寿命着想,所有相关文件都保存在 $XDG_RUNTIME_DIR
。
生成地址列表
查找 $1
下面的图片,并且生成列表到 $XDG_RUNTIME_DIR/wp_db
,如果已经生成过不需要重复生成。
1 2 3 |
|
随机挑选一张图片
使用 shuf
命令挑选一张图片,如果文件不存在则重新挑选,注意如果上一步没有找到任何图片会陷入死循环。
5 6 7 |
|
假如需要跳过重复壁纸只需要每次挑选图片后删掉相应的行,然后在地址列表为空时重新扫描即可。
处理图片
把图片高度缩放到 1440
, 同时保持宽高比。
8
|
|
将图片重复 n 次,n = 向上取整到偶数(向上取整(显示器宽度/图片宽度)-1)。之所以要向上取整到偶数是因为要避免重复后的图片(本身算作一次)数量为偶数,从而导致“接合的缝隙”显示在屏幕正中间这一悲剧。
例如我的屏幕分辨率为 5120x1440,resize 后的图片分辨率为 3000x1440,那么这张图片需要被重复两次,算上自身就会生成 3 张并排的图片,保证了宽度大于显示器宽度。
n 的计算、重复图片均可以通过 convert
命令完成:
8 9 |
|
最后只要按照屏幕宽度裁掉两侧多余的部分即可。
8 9 |
|
设置壁纸
通过 gsettings 来进行设置。
9
|
|
合体后的脚本 wp.sh
运行这个脚本就可以自动更换壁纸了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Systemd
使用 systemd --user
定期运行脚本,一时换一时爽,一直换一直爽。
wallpaper@.service
其中 %h
对于 systemd --user
而言相当于 $HOME
的作用,而 %I
则用于传递参数也就是存储的图片文件夹路径。
[Unit]
Description=Select a random wallpaper from %I
[Service]
Type=oneshot
ExecStart=%h/path/to/wp.sh "%I"
wallpaper@.timer
使用 AccuracySec=1s
避免随机延迟,另外 PartOf
以及 WantedBy
确保了只有处于 Gnome 桌面环境时才会触发。
[Unit]
Description=Select a random wallpaper from %I every 1 min
PartOf=graphical-session.target
[Timer]
OnStartupSec=1
OnUnitActiveSec=1min
AccuracySec=1s
[Install]
WantedBy=gnome-session.target
启动 Timer
install -m640 wallpaper@.service wallpaper@.timer ~/.config/systemd/user/
systemctl --user daemon-reload
PATH=$(systemd-escape "path/to/wallpaper/directory")
systemctl --user enable --now wallpaper@$PATH.timer
注意 @
后面的路径需要使用 systemd-escape
进行转义。
查看当前壁纸
有时候需要知道当前壁纸的原图位置,只需要在 wp.sh
相应位置添加:
echo "$TARGET" > "$XDG_RUNTIME_DIR/wp_path"
然后就可以方便做各种奇奇怪怪的事情了:
# 显示当前壁纸原图的位置
cat "$XDG_RUNTIME_DIR/wp_path"
# 在桌面环境打开原图
xdg-open $(cat "$XDG_RUNTIME_DIR/wp_path")
# 删除壁纸原图
rm "$(cat "$XDG_RUNTIME_DIR/wp_path")"