xyproto / wallutils

:city_sunset: Utilities for handling monitors, resolutions, wallpapers and timed wallpapers
BSD 3-Clause "New" or "Revised" License
463 stars 17 forks source link

[Wayland] setting the wallpaper from a systemd unit #12

Closed cmacrae closed 4 years ago

cmacrae commented 4 years ago

Hey @xyproto :wave: Thanks very much for wallutils :tada:

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:

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

ExecStart=/bin/setrandom -v /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](https://github.com/swaywm/sway/wiki/Systemd-integration) 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: /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 :pray:   
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! :hugs: 
cmacrae commented 4 years ago

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 :ok_hand:

xyproto commented 4 years ago

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!

cmacrae commented 4 years ago

Thanks for your swift response :smile:

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 :sweat_smile:

cmacrae commented 4 years ago

If you have advice on where I can get all the headers for Wayland from, I'd appreciate it :pray:
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 :)

xyproto commented 4 years ago

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).

xyproto commented 4 years ago

Did this work out?

cmacrae commented 4 years ago

Ah! Sorry @xyproto, I missed your response! Thanks for getting back to me :+1:
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