i3 Desktop Part 9: Power, Locking, and Battery Safety

Power behaviour is not glamorous, but it has to be trustworthy.

On a laptop especially, the desktop needs to lock quickly, suspend safely, stop media when appropriate, and warn before the battery gets too low. I do not need animation or a fancy lock screen. I need the basic path to work every time.

This setup has a few small scripts for that:

  • i3-power-menu
  • i3-lock-screen
  • i3-stop-playback
  • i3-start-xss-lock
  • i3-power-policy
  • i3-low-battery-monitor

Together they cover lock, suspend, logout, reboot, shutdown, idle locking, DPMS, and battery thresholds.

A plain lock screen

The lock screen is intentionally boring.

.local/bin/i3-lock-screen uses i3lock with a solid colour from the Catppuccin base colour. It runs in no-fork mode, ignores empty passwords, and forces the lock window.

Before locking, it calls i3-stop-playback.

That helper stops the custom radio process and pauses normal MPRIS media players through playerctl. It also refreshes the media and radio bar blocks.

This avoids one of the more annoying desktop behaviours: locking the screen while audio continues to play in the room.

Lock before suspend

Suspend goes through the same lock script.

When called with suspend, i3-lock-screen starts i3lock, waits briefly, then calls systemctl suspend.

i3-start-xss-lock connects this to xss-lock with --transfer-sleep-lock, so logind suspend behaviour and the screen lock are tied together. The i3 config starts that wrapper during session startup.

The important part is sequence. Lock first, then suspend. On resume, the session should already be protected.

The power menu

Mod+Shift+e opens .local/bin/i3-power-menu.

The menu offers:

  • lock
  • suspend
  • logout
  • reboot
  • shutdown

Logout, reboot, and shutdown ask for confirmation. Before those destructive session actions, playback is stopped.

This is a small example of why I like rofi menus for i3. I do not need a full power manager UI, but I do want a consistent confirmation prompt and one obvious place to do power actions.

Idle policy

.local/bin/i3-power-policy sets X idle behaviour with xset.

By default:

  • screen saver lock timing is set from I3_IDLE_LOCK_SECONDS, defaulting to 600 seconds
  • DPMS turns the display off after I3_IDLE_DPMS_SECONDS, defaulting to 900 seconds

The defaults are simple: lock after ten minutes, power the display down after fifteen.

Those values can be overridden with environment variables, which is enough flexibility for a personal setup.

Low battery monitor

The low battery monitor runs as a background process started from i3-autostart.

It reads battery state using upower when available, falling back to /sys/class/power_supply. It only acts while the battery is discharging.

The default thresholds are:

  • warn at 20 percent
  • critical at 12 percent
  • suspend at 7 percent

Those are configurable with environment variables.

The script stores marker files under the runtime directory so it does not spam notifications on every check. If the battery is charging again, the markers reset. At the suspend threshold, it sends a critical notification, waits briefly, then calls the lock screen suspend path.

That is exactly the kind of laptop safety net I want. Quiet until needed, then decisive.

Fast beats fancy

The theme across the power setup is speed and predictability.

The lock screen is a colour, not a screenshot blur. Suspend locks first. Shutdown asks for confirmation. Playback stops before the session goes away. Idle timing is explicit. Battery warnings have thresholds and do not repeat endlessly.

None of this is novel. It is just the kind of behaviour a full desktop environment usually gives you by default.

In a custom i3 desktop, I have to choose and wire those pieces myself. I would rather do that with small scripts I understand than depend on a large background component I barely use.