Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 29 additions & 8 deletions lid-guard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@ system-wide lid policy.

## Requirements

Install `systemctl`, `systemd-run`, and `systemd-inhibit` from systemd, plus
`sleep` from coreutils, on `PATH`. The active user session must use
`systemd-logind` and have a working user service manager.
One of these backends must be available:

- **Dinit:** `dinitctl`, `elogind-inhibit`, and `sleep`. The active user session
must have a working user Dinit manager and `elogind`.
- **systemd:** `systemctl`, `systemd-run`, `systemd-inhibit`, and `sleep`. The
active user session must use `systemd-logind` and have a working user service
manager.

Dinit is preferred automatically when both backends are installed.

## Usage

Expand All @@ -42,12 +48,26 @@ The `enable`, `disable`, and `toggle` events change the inhibitor state.
`refresh` and `status` re-check the transient user service without changing it.
IPC events take no payload.

## Dinit setup

For Dinit, install the included service description into the user service
directory:

```sh
mkdir -p "$XDG_CONFIG_HOME/dinit.d"
cp dinit/noctalia-lid-guard "$XDG_CONFIG_HOME/dinit.d/"
```

When installed from the Noctalia plugin store, copy the file from the plugin's
local directory. The service is not enabled at boot; the plugin starts and
stops it on demand.

## Notes

Lid Guard makes no network requests and writes no files. It spawns
`systemctl`, `systemd-run`, `systemd-inhibit`, and `sleep` as the current user.
When enabled, it creates the transient user service
`noctalia-lid-guard.service`; disabling the mode stops that service.
Lid Guard makes no network requests. It starts the inhibitor as the current
user. With Dinit it controls the persistent user service
`noctalia-lid-guard`; with systemd it creates the transient user service
`noctalia-lid-guard.service`; disabling the mode stops the selected service.

The inhibitor covers only `handle-lid-switch`. It does not prevent suspension
requested by an idle daemon, a power menu, or another explicit command, and it
Expand All @@ -56,5 +76,6 @@ service manager stops. If Noctalia is unavailable, restore the normal lid
behavior with:

```sh
systemctl --user stop noctalia-lid-guard.service
dinitctl --user stop noctalia-lid-guard # Dinit
systemctl --user stop noctalia-lid-guard.service # systemd
```
4 changes: 4 additions & 0 deletions lid-guard/dinit/noctalia-lid-guard
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Dinit backend for Noctalia Lid Guard.
type = process
command = /usr/bin/elogind-inhibit --what=handle-lid-switch --who="Noctalia Lid Guard" --why="Keep background jobs running while the laptop lid is closed" --mode=block /usr/bin/sleep infinity
restart = false
5 changes: 3 additions & 2 deletions lid-guard/plugin.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
id = "8bury/lid-guard"
name = "Lid Guard"
version = "1.0.0"
version = "1.0.1"
plugin_api = 3
author = "8bury"
license = "MIT"
icon = "shield-lock"
description = "Keep the laptop awake when its lid is closed, so background jobs can continue running."
tags = ["bar", "indicator", "productivity", "service", "shortcut", "system", "utility"]
dependencies = ["systemctl", "systemd-run", "systemd-inhibit", "sleep"]
# The plugin supports either Dinit + elogind or systemd + logind.
dependencies = []

[[service]]
id = "lid-guard-service"
Expand Down
31 changes: 22 additions & 9 deletions lid-guard/service.luau
Original file line number Diff line number Diff line change
@@ -1,25 +1,38 @@
--!nonstrict
-- Owns the systemd inhibitor. Widgets and shortcuts communicate with this
-- Owns the lid inhibitor. Widgets and shortcuts communicate with this
-- singleton through noctalia.state.

local UNIT = "noctalia-lid-guard.service"
local CHECK_COMMAND = `systemctl --user is-active --quiet {UNIT}`
local START_COMMAND = `systemctl --user reset-failed {UNIT} >/dev/null 2>&1 || true; ` .. table.concat({
local SYSTEMD_UNIT = "noctalia-lid-guard.service"
local DINIT_UNIT = "noctalia-lid-guard"
local hasDinit = noctalia.commandExists("dinitctl")
and noctalia.commandExists("elogind-inhibit")
and noctalia.commandExists("sleep")
local hasSystemd = noctalia.commandExists("systemctl")
and noctalia.commandExists("systemd-run")
and noctalia.commandExists("systemd-inhibit")
and noctalia.commandExists("sleep")
local backend = if hasDinit then "dinit" elseif hasSystemd then "systemd" else ""
local UNIT = if backend == "dinit" then DINIT_UNIT else SYSTEMD_UNIT
local CHECK_COMMAND = if backend == "dinit"
then `dinitctl --user is-started {UNIT}`
else `systemctl --user is-active --quiet {UNIT}`
local START_COMMAND = if backend == "dinit"
then `dinitctl --user start {UNIT}`
else `systemctl --user reset-failed {UNIT} >/dev/null 2>&1 || true; ` .. table.concat({
`systemd-run --user --quiet --collect --unit={UNIT}`,
`--description='Noctalia Lid Guard'`,
`systemd-inhibit --what=handle-lid-switch`,
`--who='Noctalia Lid Guard'`,
`--why='Keep background jobs running while the laptop lid is closed'`,
`--mode=block sleep infinity`,
}, " ")
local STOP_COMMAND = `systemctl --user stop {UNIT}`
local STOP_COMMAND = if backend == "dinit"
then `dinitctl --user stop {UNIT}`
else `systemctl --user stop {UNIT}`

local active = false
local busy = false
local available = noctalia.commandExists("systemctl")
and noctalia.commandExists("systemd-run")
and noctalia.commandExists("systemd-inhibit")
and noctalia.commandExists("sleep")
local available = backend ~= ""
local revision = 0

local function publish(errorMessage)
Expand Down
4 changes: 2 additions & 2 deletions lid-guard/translations/en.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"error": {
"command_failed": "The systemd command failed.",
"missing_dependencies": "systemctl, systemd-run, systemd-inhibit, and sleep are required.",
"missing_dependencies": "Dinit with elogind, or systemd with logind, is required.",
"state_mismatch": "The requested state could not be confirmed."
},
"notification": {
Expand All @@ -23,6 +23,6 @@
"active": "Lid Guard is on — closing the lid will not suspend the laptop",
"changing": "Changing Lid Guard state…",
"inactive": "Lid Guard is off — click to keep the laptop awake with the lid closed",
"unavailable": "Lid Guard requires systemd"
"unavailable": "Lid Guard requires Dinit + elogind or systemd"
}
}