feat(lid-guard): add lid-close suspension inhibitor (#30)
* feat(lid-guard): add lid-close suspension inhibitor * docs(lid-guard): replace plugin thumbnail
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
--!nonstrict
|
||||
-- Owns the systemd 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({
|
||||
`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 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 revision = 0
|
||||
|
||||
local function publish(errorMessage)
|
||||
revision += 1
|
||||
noctalia.state.set("lid_guard_status", {
|
||||
active = active,
|
||||
busy = busy,
|
||||
available = available,
|
||||
error = errorMessage or "",
|
||||
revision = revision,
|
||||
})
|
||||
end
|
||||
|
||||
local function refresh(callback)
|
||||
if not available then
|
||||
active = false
|
||||
publish(noctalia.tr("error.missing_dependencies"))
|
||||
if callback then callback(false) end
|
||||
return
|
||||
end
|
||||
|
||||
noctalia.runAsync(CHECK_COMMAND, function(result)
|
||||
active = result.exitCode == 0
|
||||
publish()
|
||||
if callback then callback(active) end
|
||||
end)
|
||||
end
|
||||
|
||||
local function finishToggle(expectedActive, result)
|
||||
if result.exitCode ~= 0 then
|
||||
busy = false
|
||||
local detail = noctalia.string.trim(result.stderr or "")
|
||||
if detail == "" then detail = noctalia.tr("error.command_failed") end
|
||||
publish(detail)
|
||||
noctalia.notifyError(noctalia.tr("title"), detail)
|
||||
return
|
||||
end
|
||||
|
||||
refresh(function(currentActive)
|
||||
busy = false
|
||||
active = currentActive
|
||||
publish()
|
||||
|
||||
if currentActive ~= expectedActive then
|
||||
noctalia.notifyError(noctalia.tr("title"), noctalia.tr("error.state_mismatch"))
|
||||
elseif currentActive then
|
||||
noctalia.notify(noctalia.tr("notification.enabled.title"), noctalia.tr("notification.enabled.body"))
|
||||
else
|
||||
noctalia.notify(noctalia.tr("notification.disabled.title"), noctalia.tr("notification.disabled.body"))
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function setActive(nextActive)
|
||||
if busy or not available then return end
|
||||
busy = true
|
||||
publish()
|
||||
|
||||
if nextActive then
|
||||
noctalia.runAsync(START_COMMAND, function(result)
|
||||
finishToggle(true, result)
|
||||
end)
|
||||
else
|
||||
noctalia.runAsync(STOP_COMMAND, function(result)
|
||||
finishToggle(false, result)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
noctalia.state.watch("lid_guard_command", function(command)
|
||||
if type(command) ~= "table" then return end
|
||||
|
||||
if command.action == "toggle" then
|
||||
refresh(function(currentActive)
|
||||
setActive(not currentActive)
|
||||
end)
|
||||
elseif command.action == "enable" then
|
||||
setActive(true)
|
||||
elseif command.action == "disable" then
|
||||
setActive(false)
|
||||
elseif command.action == "refresh" then
|
||||
refresh()
|
||||
end
|
||||
end)
|
||||
|
||||
noctalia.setUpdateInterval(5000)
|
||||
refresh()
|
||||
|
||||
function update()
|
||||
if not busy then refresh() end
|
||||
end
|
||||
|
||||
function onIpc(event, _payload)
|
||||
if event == "toggle" then
|
||||
refresh(function(currentActive)
|
||||
setActive(not currentActive)
|
||||
end)
|
||||
elseif event == "enable" then
|
||||
setActive(true)
|
||||
elseif event == "disable" then
|
||||
setActive(false)
|
||||
elseif event == "refresh" or event == "status" then
|
||||
refresh()
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user