#!/bin/bash # start-swayidle.sh — canonical swayidle startup for the Sway session. # # Single source of truth for the swayidle command. Invoked from: # 1. ~/.config/sway/config: exec $HOME/.config/sway/start-swayidle.sh # 2. ~/.config/sway/caffeine.sh: after killall swayidle, to re-arm # # Why a wrapper instead of inlining the command in sway/config? Because # caffeine.sh needs to RESTART swayidle after killing it, and the restart # must use the same timeouts and lock command as the original. Hardcoding # it twice drifts (see git log — swayidle line in caffeine.sh got out of # sync with the one in sway/config, so toggling caffeine off would # silently change your lock command and timeout values). # # Env: this script is run by: # - sway at session start, with the full Wayland/Sway env (correct) # - caffeine.sh from waybar's on-click, with NO Wayland env (broken — see below) # When run from caffeine.sh, swayidle needs WAYLAND_DISPLAY to talk to the # compositor. We probe /proc for the env of an already-running Wayland client # (mako, swaybar, foot, etc.) and inherit WAYLAND_DISPLAY / DISPLAY / # DBUS_SESSION_BUS_ADDRESS / XDG_RUNTIME_DIR from it. This is the same # trick `dbus-update-activation-environment` uses internally, just per-process. # # Returns: never. Runs as the foreground process; sway's exec replaces the # shell with this script, and swayidle takes over. When started from # caffeine.sh, the script is backgrounded (&) and this function returns. set -e # --- 1. Restore Wayland env if missing ----------------------------------- # The bug we're fixing: clicking the caffeine button runs this script # from waybar's on-click context, which doesn't inherit sway's env. # swayidle and lock-fancy.sh both call swaymsg/grim which need # WAYLAND_DISPLAY — without it, swayidle silently exits and the user # has NO idle lock at all (the worst possible failure mode: looks normal # in the bar, but auto-lock is silently dead). if [[ -z "$WAYLAND_DISPLAY" && -z "$SWAYSOCK" ]]; then # Find any running Wayland client and steal its env. mako (notification # daemon) is always present and always has the right env. for pid in /proc/[0-9]*; do [[ -r "$pid/environ" ]] || continue candidate=$(tr '\0' '\n' < "$pid/environ" 2>/dev/null | grep -E '^(WAYLAND_DISPLAY|DBUS_SESSION_BUS_ADDRESS|XDG_RUNTIME_DIR|DISPLAY)=' || true) if [[ -n "$candidate" ]]; then export $candidate break fi done fi # --- 2. Start swayidle ---------------------------------------------------- # If invoked from sway's `exec` line (config), swayidle replaces this shell # and runs forever. If invoked from caffeine.sh (backgrounded with &), it # runs as a child of the parent shell and caffeine.sh returns immediately. exec swayidle -w \ timeout 300 "$HOME/.config/sway/lock-fancy.sh" \ timeout 600 'swaymsg "output * power off"' \ resume 'swaymsg "output * power on"' \ before-sleep "$HOME/.config/sway/lock-fancy.sh"