xyproto/wallutils

[Wayland] setting the wallpaper from a systemd unit

cmacrae opened this issue ยท 7 comments

Hey @xyproto ๐Ÿ‘‹ Thanks very much for wallutils ๐ŸŽ‰

I'm trying to set up a systemd user service unit/timer combo to change the wallpaper in my sway session (testing every minute at the moment).

I'm doing so on NixOS using a collection of the following:

  • systemd user service unit (wallpaper.service)
[Unit]
Description=Change the wallpaper every minute
PartOf=graphical-session.target

[Service]
Environment="LOCALE_ARCHIVE=<snip>/lib/locale/locale-archive"
Environment="PATH=<snip>"

ExecStart=<snip>/bin/setrandom -v <snip>/share/backgrounds/elementary

Note: I've redacted the long Nix paths here, replaced with <snip> for legibility

  • systemd user service timer (wallpaper.timer)
[Unit]

[Timer]
OnCalendar=*:0/1
  • Reaching the sway-session.target with the final line of my sway config:
exec "systemctl --user import-environment; systemctl --user start sway-session.target"

According to sway's documentation for systemd integration, this last part should copy in the user environment for user scope systemd constructs to use. And indeed it does - checking the output of systemctl --user show-environment has everything from my shell's output of env.

The problem

Sadly it seems setrandom isn't able to set the wallpaper, complaining with the following in its output (from the triggered unit):

Setting background image to: <snip>/share/backgrounds/elementary/Jonas Nilsson Lee.j>
Found no working method for setting the desktop wallpaper.

So, I was just wondering if you might be able to shed some light on this ๐Ÿ™
What would setrandom need to be able to talk to the active compositor? Does it expect any environment variables or sockets?

To clarify, the command works perfectly from the shell once in the session, and also as an initial exec_always in my sway's config (to set it at start/reload).

Many thanks in advance for any help on this! ๐Ÿค—

For anyone interested that may stumble across this, here's the part of my NixOS configuration that handles this:

systemd.user = {
  targets.sway-session = {
    description = "sway compositor session";
    documentation = ["man:systemd.special(7)"];
    bindsTo = ["graphical-session.target"];
    wants = ["graphical-session-pre.target"];
    after = ["graphical-session-pre.target"];
  };

  services.wallpaper = {
    description = "Change the wallpaper every 1 minutes";
    wantedBy = ["sway-session.target"];
    partOf = ["graphical-session.target"];
    startAt = "*:0/1";
    serviceConfig = {
      ExecStart = ''
        ${pkgs.wallutils}/bin/setrandom -v ${pkgs.pantheon.elementary-wallpapers}/share/backgrounds/elementary
      '';
    };
  };
};

This will (once it's working!) randomly set a wallpaper from the pantheon.elementary-wallpapers package ๐Ÿ‘Œ

Hi, yes, currently setwallpaper and setrandom will look for certain environment variables and then try to communicate with the window manager as it is running. Setting the wallpaper in advance, before the window manager is running, would also be interesting!

A flag could be added to setwallpaper and setrandom to achieve this.

Thanks for reporting!

Thanks for your swift response ๐Ÿ˜„

Well, actually, in the above scenario, the windowmanager is actually running. The systemd unit set to trigger is executed only once the sway-session.target is reached (executed at the end of sway's config: exec "systemctl --user import-environment; systemctl --user start sway-session.target").

That said, I decided to try and implement this as a native feature of setrandom, with an -interval flag. So you could do: setrandom -interval 30m path/to/wallpapers

I've written the code, but can't build because I don't know where to get all the Wayland header files from ๐Ÿ˜…

If you have advice on where I can get all the headers for Wayland from, I'd appreciate it ๐Ÿ™
I pulled down the source, but I seem to be missing some header files after running ./autogen.sh and make from the Wayland repo, I still seem to be missing some:

ฯ€ wallutils/cmd/setrandom on_interval โœ— โฏ go build -v
github.com/xyproto/wallutils
# github.com/xyproto/wallutils
In file included from ./wayinfo.h:8,
                 from ../../wayinfo.go:4:
./wayland-client.h:40:10: fatal error: wayland-client-protocol.h: No such file or directory
 #include "wayland-client-protocol.h"
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.

Once I've got it building, I'll submit a PR and you can see what you think about the feature :)

Hi, sorry for the late reply. On my system, /usr/include/wayland-client-protocol.h comes with the wayland package (currently at version 1.17.0). This is on Arch Linux.

On NixOS, I assume that wayland-client-protocol.h either comes with the wayland or wayland-protocols package, but I have no easy way to check this (that I could find, at least).

Did this work out?

Ah! Sorry @xyproto, I missed your response! Thanks for getting back to me ๐Ÿ‘
I haven't tried working on this recently, so I'll have a go when I get some time :) If you'd rather close this issue off, please feel free to do so