# swayaway

a drop-in replacement for [`swayidle(1)`](https://github.com/swaywm/swayidle) for Wayland compositors, written in C99, with no elogind dependency and no libsystemd.

the only dependencies are `libwayland-client` and `libdbus-1`.

this exports `org.freedesktop.ScreenSaver` (plus the `org.gnome.ScreenSaver` alias) so browsers, media players, and any other app that calls `Inhibit()`/`Uninhibit()` can suppress idle timeouts.

it also listens for logind's `PrepareForSleep` signal to run `before-sleep` / `after-resume` commands. if no logind is running, these events simply never fire.

## usage

```
swayaway [options] [events...]
```

options:

| option      | meaning                                                                  |
|-------------|--------------------------------------------------------------------------|
| `-C <path>` | config file (default: see below)                                         |
| `-d`        | debug output                                                             |
| `-w`        | wait for commands to finish (useful with `before-sleep` + swaylock `-f`) |
| `-S <seat>` | pick a specific seat                                                     |
| `-h`        | help                                                                     |

events:

```
timeout <seconds> <command> [resume <command>]
resume <command> # legacy: run on every activity
before-sleep <command>
after-resume <command>
```

all commands will be executed via `/bin/sh -c`. this means you can use env vars, pipes, and wildcards in your command. because of this, you should quote the entire command string if it contains spaces, both on the command line and in the config file

example (the classic sway setup):

```sh
swayaway -w \
    timeout 300 'swaylock -f -c 000000' \
    timeout 600 'swaymsg "output * power off"' \
    resume 'swaymsg "output * power on"' \
    before-sleep 'swaylock -f -c 000000'
```

the `timeout ... resume ...` two-command form is the swayidle 1.8+/1.9 syntax; `timeout N resume CMD` (old pre-1.8 mode syntax) is also accepted

the top-level `resume CMD` event (used by the famous sway wiki example) works too.

swayidle's `lock`, `unlock` and `idlehint` events are *not* supported (they go through the logind Session interface), swayaway rejects them with an error, same as swayidle built without systemd/elogind

### config file

without `-C`, swayaway checks, in order:

1. `$XDG_CONFIG_HOME/swayaway/config`
2. `$HOME/.config/swayaway/config`
3. `$XDG_CONFIG_HOME/swayidle/config`
4. `$HOME/.config/swayidle/config`
5. `$HOME/.swayidle/config`

so an existing swayidle config works unchanged. Config lines are the same
events as the command line; `#` starts a comment and shell expansion applies
(quote commands with spaces: `timeout 300 "swaylock -f"`).

## how it works

this basically polls 4 fds, wayland fd, session bus fd, system bus fd, and a signalfd like so:
```
poll( [ wayland_fd, session_bus_fd, system_bus_fd, signalfd ], timeout )
```

- wayland fd is a single `ext-idle-notify-v1` notification with timeout 0 tracks idle/activity; the compositor sends `idled` as soon as the seat is idle and `resumed` on the first input.
- monotonic clock `CLOCK_MONOTONIC` records when idle started; all timeout deadlines are computed from it, and the next deadline becomes the `poll()` timeout.
- the session bus fd is the ScreenSaver service. `Inhibit` returns a cookie, `Uninhibit` releases it; cookies are released automatically if their client disconnects. while any inhibitor is held, timeouts are frozen (and idle counting restarts when the last inhibitor is released, mirroring swayidle re-registering its timers).
- system bus fd `PrepareForSleep`: run `before-sleep`, then release the logind "delay" sleep lock so suspend actually happens; on resume run `after-resume` and re-acquire the lock. the lock is a plain dbus `Inhibit` call (returns a unix fd) and is best-effort.
- the signalfd handles `SIGTERM`/`SIGINT` and runs pending resume commands before then exit, and also `SIGUSR1` forces the idle state immediately (like swayidle).

idle detection via `get_idle_notification` also respects Wayland-level idle inhibitors (`zwp_idle_inhibitor_v1`), exactly like swayidle's default.

## building

requires `libwayland-dev`, `libdbus-1-dev`, `wayland-protocols` and `wayland-scanner`

```sh
make
doas make install # will install to /usr/local/bin by default, change PREFIX if you want
```

you can also make the manpages (this requires scdoc):

```sh
make man
doas make man-install
```
