本文参考:
定时替换 Gnome 壁纸

Gnome 的壁纸更换功能需要自己编写 2 个 xml 文件,xml 文件要手动将所有图片的地址写进去非常的麻烦。虽然 Gnome 下也有不少 Extensions 可以做到更换壁纸的效果,但是总体而言并不好用。

换壁纸的思路

  1. 使用 find 命令生成包含所有图片地址的列表。

  2. 从列表中随机挑选一张图片。

  3. 使用 gsettings 设置壁纸。

  4. 使用 systemd 定期执行脚本。

Bash 脚本

首先写一个 Bash 脚本,实现更换壁纸的目的,同时为了响应速度和硬盘寿命着想,所有相关文件都保存在 $XDG_RUNTIME_DIR

$XDG_RUNTIME_DIR 是一个变量,后面将使用 systemd 传入你存放壁纸文件夹的路径这个变量。

生成地址列表

查找 $1 下面的图片,并且生成列表到 $XDG_RUNTIME_DIR/bg_db,如果已经生成过不需要重复生成。

1
2
3
if [[ ! -f "${XDG_RUNTIME_DIR}/bg_db" ]]; then
find "${1}" \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' \) -print > "${XDG_RUNTIME_DIR}/bg_db"
fi

随机挑选一张图片

使用 shuf 命令挑选一张图片,如果文件不存在则重新挑选,注意如果上一步没有找到任何图片会陷入死循环。

1
2
3
while [[ ! -f "${TARGET}" ]]; do
TARGET=$(shuf -n 1 "${XDG_RUNTIME_DIR}/bg_db")
done

假如需要跳过重复壁纸只需要每次挑选图片后删掉相应的行,然后在地址列表为空时重新扫描即可。

设置壁纸

通过 gsettings 来进行设置。

1
2
gsettings set org.gnome.desktop.background picture-uri "file://${TARGET}/" || true
gsettings set org.gnome.desktop.background picture-uri-dark "file://${TARGET}" || true

picture-uri 是亮色模式下的壁纸,picture-uri-dark 是暗色模式下的壁纸。我这里将两个模式下的壁纸换为同一个。

合体后的脚本 background.sh

运行这个脚本就可以自动更换壁纸了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env bash
set -Eeo pipefail

if [[ ! -f "${XDG_RUNTIME_DIR}/bg_db" ]]; then
find "${1}" \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' \) -print > "${XDG_RUNTIME_DIR}/bg_db"
fi

while [[ ! -f "${TARGET}" ]]; do
TARGET=$(shuf -n 1 "${XDG_RUNTIME_DIR}/bg_db")
done


gsettings set org.gnome.desktop.background picture-uri "file://${TARGET}/" || true
gsettings set org.gnome.desktop.background picture-uri-dark "file://${TARGET}" || true

记得给这个文件添加可执行权限:chmod +x background.sh

运行时记得传入你壁纸文件夹的路径: background.sh ./your/background/PATH

Systemd

使用 systemd --user 定期运行脚本。systemd 会给每个用户生成一个 systemd 实例,用户可以在这个实例下管理服务,启动、停止、启用以及禁用他们自己的单元。这个能力大大方便了那些通常在特定用户下运行的守护进程和服务。详细的玩法可以参见 ArchWiki

background@.service

创建文件 background@.service,内容如下:

1
2
3
4
5
6
[Unit]
Description=Select a random background from %I

[Service]
Type=oneshot
ExecStart=%h/path/to/background.sh "%I"

其中 %h 对于 systemd --user 而言相当于 $HOME 的作用,而 %I 则用于传递参数也就是存储的图片文件夹路径。

background@.timer

创建文件 background@.service,内容如下:

1
2
3
4
5
6
7
8
9
10
11
[Unit]
Description=Select a random background from %I every 1 min
PartOf=graphical-session.target

[Timer]
OnStartupSec=1
OnUnitActiveSec=5min
AccuracySec=1s

[Install]
WantedBy=gnome-session.target

使用 AccuracySec=1s 避免随机延迟,另外 PartOf 以及 WantedBy 确保了只有处于 Gnome 桌面环境时才会触发。

启动 Timer

将 background@.service 和 background@.timer 放入 ~/.config/systemd/user/ 下,并启动 systemd 定时任务。

1
2
3
4
install -m640 background@.service background@.timer ~/.config/systemd/user/
systemctl --user daemon-reload
BGPATH=$(systemd-escape "path/to/background/directory")
systemctl --user enable --now background@$BGPATH.timer

第三行 path/to/background/directory 替换为你壁纸的路径。

注意 @ 后面的路径需要使用 systemd-escape 进行转义。

查看当前壁纸

有时候需要知道当前壁纸的原图位置,只需要在 background.sh 相应位置添加:

1
echo "$TARGET" > "$XDG_RUNTIME_DIR/bg_path"

然后还有一些其他玩法:

1
2
3
4
# 显示当前壁纸原图的位置
cat "$XDG_RUNTIME_DIR/bg_path"
# 在桌面环境打开原图
xdg-open $(cat "$XDG_RUNTIME_DIR/bg_path")