Suspend Desktop PC in Sway?

I’m very confused how to make my desktop machine suspend after inactivity. I run swayidle and swaylock, and I can get the computer screen to go dark and lock the session, but overnight - the fans and keyboard never shut off.

When I use any other DE this is configured automatically, but when I google this issue, I can’t find a damn thing. I feel like I’m missing a keyword in my search. Does everyone else just suspend their machines manually at the end of every day?

Recently the community Sway spin was configured to just let systemd handle suspend events. If you use swayidle to drop an idle hint in your config, systemd will take it from there; it will honor whatever suspend config you have set up in /etc/systemd/logind.conf.

This drop-in for /etc/systemd/logind.conf.d/ sets a default behavior of suspend after ten minutes:

Obviously that can be more deeply configured; logind.conf has a lot of available options.

https://man.archlinux.org/man/logind.conf.5.en

If you want to set up full-on suspend, you can use sleep.conf in addition (for example, if you want to set up suspend-then-hibernate and set it for less than the somewhat lengthy two hour default).

https://man.archlinux.org/man/systemd-sleep.conf.5.en

You can use tools like swayidle and set up configuration for triggering suspend and resume events within Sway itself, but at the end of the day it’s just a window manager; it doesn’t natively provide detailed power management tools. The tooling systemd offers is more comprehensive.

After all, systemd is specifically designed to manage low-level system states. Since EndeavourOS is already using systemd anyway, it just seems like a better option to let systemd handle this like it does in other DEs.

Thank you, this is super helpful. I haven’t got it to work yet, but I am still dealing with a bit of a mish-mash of configs because I had my own Sway config from a laptop that I built a while back, and it’s config is fighting with the config.d files from the community Sway github dotfiles.

Do you know if I have to reboot the machine to get the systemd.d changes to work? I tried with my original swayidle config block in my .config/sway/config, but it didn’t work, so I swapped that for the code block you posted, and it still didn’t work. So I am going to reboot and see if anything works.

All you really need is this one line somewhere in your Sway config:

exec swayidle idlehint 1

You need to log out and log back in after adding this line since it is exec (instead of exec_always).

The two lines after this one in the community repo are for triggering swaylock before it goes to suspend, in case you want to set that up. Also, if you still have the default “suspend” script in your Sway config (timeout 600 'swaymsg "output * dpms off"', etc, etc), you can comment it out or delete it if you want.

After sending an idlehint event, systemd will take over suspend events automatically using the configuration specified in /etc/systemd/logind.conf. However, the default logind.conf configuration doesn’t actually do anything by default for an idle config; the defaults are like this:

#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it under the
#  terms of the GNU Lesser General Public License as published by the Free
#  Software Foundation; either version 2.1 of the License, or (at your option)
#  any later version.
#
# Entries in this file show the compile time defaults. Local configuration
# should be created by either modifying this file (or a copy of it placed in
# /etc/ if the original file is shipped in /usr/), or by creating "drop-ins" in
# the /etc/systemd/logind.conf.d/ directory. The latter is generally
# recommended. Defaults can be restored by simply deleting the main
# configuration file and all drop-ins located in /etc/.
#
# Use 'systemd-analyze cat-config systemd/logind.conf' to display the full config.
#
# See logind.conf(5) for details.

[Login]
#NAutoVTs=6
#ReserveVT=6
#KillUserProcesses=no
#KillOnlyUsers=
#KillExcludeUsers=root
#InhibitDelayMaxSec=5
#UserStopDelaySec=10
#SleepOperation=suspend-then-hibernate suspend
#HandlePowerKey=poweroff
#HandlePowerKeyLongPress=ignore
#HandleRebootKey=reboot
#HandleRebootKeyLongPress=poweroff
#HandleSuspendKey=suspend
#HandleSuspendKeyLongPress=hibernate
#HandleHibernateKey=hibernate
#HandleHibernateKeyLongPress=ignore
#HandleLidSwitch=suspend
#HandleLidSwitchExternalPower=suspend
#HandleLidSwitchDocked=ignore
#PowerKeyIgnoreInhibited=no
#SuspendKeyIgnoreInhibited=no
#HibernateKeyIgnoreInhibited=no
#LidSwitchIgnoreInhibited=yes
#RebootKeyIgnoreInhibited=no
#HoldoffTimeoutSec=30s
#IdleAction=ignore
#IdleActionSec=30min
#RuntimeDirectorySize=10%
#RuntimeDirectoryInodesMax=
#RemoveIPC=yes
#InhibitorsMax=8192
#SessionsMax=8192
#StopIdleSessionSec=infinity

All those commented lines define the default behavior. You can either uncomment a line and change the value it is set to (easy method), or leave this file alone altogether and create a drop-in file in /etc/systemd/logind.conf.d/ with whatever settings you want to override (recommended method).

Notice these two lines in the default config:

#IdleAction=ignore
#IdleActionSec=30min

The default idle action is triggered after thirty minutes of idle time, but the idle action is actually set to “ignore” by default (so after thirty minutes, nothing happens). To get it to actually do something after the idle time, you need to set it to one of the other supported actions (see man logind.conf for the full list of possible settings).

That’s where the other file in the repo comes in. If you want to use that as a starting point, create a new file in /etc/systemd/logind.conf.d/ with an editor, for example nano.

sudo nano /etc/systemd/logind.conf.d/suspend.conf

It doesn’t have to be called suspend.conf, it can be called anything you want as long as it ends in “.conf”.

Add whatever settings from logind.conf you want to override.

[Login]
IdleAction=suspend
IdleActionSec=10min

This will suspend the computer after 10 minutes of idle time. Don’t forget the bracketed [Login] line at the top; it won’t work without that.

Save and exit out of the file, then restart the systemd-logind service to apply the changes.

sudo systemctl restart systemd-logind

After ten minutes, the computer should go to suspend.

If you want to set IdleActionSec=1min to test (so you don’t have to wait ten minutes to see if it works or not), that’s fine but just make sure you restart the systemd-logind service again after every time you make an edit to the service files to apply the changes.

Damn dude, this is extremely thorough. I appreciate you walking me through it. I ended up rebooting because I couldn’t seem to get it to work, but once it rebooted (now I know it just needed a logout/login cycle) it worked as expected. I also ended up reading the logind.conf page in the arch wiki. I love that wiki. I’ve realized that I’ve been at it long enough that I actually understand some of the stuff in there now, and it is amazingly thorough.

My last question is: if I set my IdleActionSec=30min, I can still use idlesway to do a lock and screen black at 5 and 10 mins respectively, right?

This was my previous settings in .config/sway/config - and I liked it, but it didn’t trigger the suspend.conf:

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

So I tried to slap

exec swayidle idlehint 1

in there, and it broke the whole thing. I need to dig into the swayidle docs because I stole this block of code from somewhere, and I don’t understand the indentation portion of this whole deal.

Thanks so much for taking the time to explain this whole deal. I’m absolutely LOVING EndeavorOS, and getting Sway on there is making it 10x better.

If you run more than one swayidle command at the same time they can interfere with each other. If you want to keep that swayidle block, try incorporating the idlehint into it like this:

exec swayidle -w \
    timeout 300 'swaylock -f -c 000000' \
    timeout 600 'swaymsg "output * power off"' resume 'swaymsg "output * power on"' \
    before-sleep 'swaylock -f -c 000000' \
    idlehint 1

In this case the indentation is just making that block of code more readable. It is easy to see what each piece is doing because the actions have been broken out into separate lines.

Technically you could put that whole exec swayidle block on one super long line and it would work exactly the same, it would just be a little clunkier to work with.

Ah! I got it.
I wasn’t escaping one of the linebreaks in that indented block. Everything is working as expected! incredible. Not the smoothest operation, but I absolutely learned something. I wish there was a bit more about this in the swayidle docs. I looked back at them, and I see now it’s pointing in the right direction, but just not enough there for someone like me to follow the breadcrumbs.

One final question: the number after ‘idlehint’ is the number of seconds to wait before sending this command? So ‘idlehint 1’ sends the idlehint command after 1 second of inactivity?

Thanks again, this has been quite informative.

Yes, that’s right. The idea was to immediately send the idlehint so systemd takes over tracking idle time right when Sway starts. It’s set to one second because it doesn’t accept 0 as an argument for some reason.

Honestly, I probably wouldn’t go to all the bother of setting up all the systemd configs if you are just going to keep that whole swayidle block anyway, with all the manual commands for shutting off the displays and locking the session and stuff. You can just add a direct call to systemctl suspend with the timeout you want in there, and forget about the idlehint and logind.conf and all that.

exec swayidle -w \
          timeout 300 'swaylock -f -c 000000' \
          timeout 600 'swaymsg "output * power off"' \
          timeout 1800 'systemctl suspend' \
          resume 'swaymsg "output * power on"' \
          before-sleep 'swaylock -f -c 000000'

The timeout 1800 'systemctl suspend' line will run systemctl suspend after thirty minutes.

The motivation for setting up the idlehint and the systemd drop-in was to facilitate dropping all the swayidle scripting from the Sway config and just let systemd handle this stuff instead. Probably you don’t need to deeply configure both your swayidle script and your systemd config; I would probably just set up one or the other for simplicity’s sake.

Yeah, probably a good call. I guess I need to decide what is actually useful. I really doubt having the screen lock, screen off, then suspend in order makes any difference. I pretty much find myself frustrated every time I need to log back in after stepping away for less than 10 mins.

If I just call ‘idlehint 1’ instead of all the other timeout junk, will it require login after I wake from suspended?

It’s only going to lock if you explicitly tell it to lock.

exec swayidle idlehint 1
exec_always swayidle -w before-sleep "$lock"
set $lock swaylock -C ~/.config/swaylock/config

Here it is the second line which runs swaylock before a suspend event. If you leave that off, it will just suspend without locking.