NOTE: This works in Fedora 21, but not in Fedora 22. Review this post for the fixes.
GNOME 3 has improved by leaps and bounds since its original release and it’s my daily driver window manager on my Linux laptop. Even with all of these improvements, there’s still no built-in way to rotate wallpaper (that I’ve found).
There are some extensions, like BackSlide, that enable background rotation on a time interval. Fedora 21 uses GNOME 3.14 and the current BackSlide version is incompatible. BackSlide’s interface is fairly useful but I wanted something different.
One of systemd’s handy features is the ability to set up systemd unit files on a per-user basis. Every user can create unit files in their home directory and tell systemd to begin using those.
We first need a script that can rotate the background based on files in a particular directory. All of my wallpaper images are in
~/Pictures/wallpapers. I adjusted this script that I found on GitHub so that it searches through files in my wallpaper directory and picks one at random to use:
#!/bin/bash walls_dir=$HOME/Pictures/Wallpapers selection=$(find $walls_dir -type f -name "*.jpg" -o -name "*.png" | shuf -n1) gsettings set org.gnome.desktop.background picture-uri "file://$selection"
I tossed this script into
~/bin/rotate_bg.sh and made it executable with
chmod +x ~/bin/rotate_bg.sh. Before you go any further, run the script manually in a terminal to verify that your background rotates to another image.
Preparing the systemd service unit file
You’ll need to create a user-level systemd service file directory if it doesn’t exist already:
Drop this file into
[Unit] Description=Rotate GNOME background [Service] Type=oneshot Environment=DISPLAY=:0 ExecStart=/usr/bin/bash /home/[USERNAME]/bin/rotate_bg.sh [Install] WantedBy=basic.target
This unit file tells systemd that we have a oneshot script that will exit when it’s finished. In addition, we also give the environment details to systemd so that it’s aware of our existing X session.
Don’t enable or start the service file yet. We will let our timer handle that part.
Setting a timer
Systemd’s concept of timers is pretty detailed. You have plenty of control over how and when you want a particular service to run. We need a simple calendar-based timer (much like cron) that will start up our service from the previous step.
Drop this into
[Unit] Description=Rotate GNOME wallpaper timer [Timer] OnCalendar=*:0/5 Persistent=true Unit=gnome-background-change.service [Install] WantedBy=gnome-background-change.service
We’re telling systemd that we want this timer to run every five minutes and we want to start our service unit file from the previous step. The
Persistent line tells systemd that we want this unit file run if the last run was missed. For example, if you log in at 7:02AM, we don’t want to wait until 7:05AM to rotate the background. We can rotate it immediately after login.
If you’d like a different interval, be sure to review systemd’s time syntax for the
OnCalendar line. It’s a little quirky if you’re used to working with crontabs but it’s very powerful once you understand it.
Now we can enable and start the timer:
systemctl --user enable gnome-background-change.timer systemctl --user start gnome-background-change.timer
Checking our work
You can use systemctl to query the timer we just activated:
$ systemctl --user list-timers NEXT LEFT LAST PASSED UNIT ACTIVATES Wed 2015-02-11 08:15:00 CST 3min 53s left Wed 2015-02-11 08:10:49 CST 16s ago gnome-background-change.timer gnome-background-change.service
In my case, this shows that the background rotation service last ran 16 seconds ago. It will run again in just under four minutes. If you find that the service runs but your wallpaper doesn’t change, try running
journalctl -xe to see if your service is throwing any errors.
This is just the tip of the iceberg of what systemd can do with user unit files and timers. the Arch Linux wiki has some awesome documentation about user unit files and timers. Check out the other timers that already exist on your system for more ideas.