Skip to main content

Lock, Idle, and DPMS somewm-only

Session locking, idle detection, and display power management APIs. These live on the awesome global and are unique to SomeWM (AwesomeWM has no lock API).

Lock, Idle, and DPMS are tightly coupled: idle timeouts can trigger DPMS and lock, and user activity wakes DPMS and resets idle state. They are documented together to show how they interact.

Lock API

Methods

MethodArgumentsReturnDescription
awesome.lock()nonebooleanLock the session. Returns true on success, false if already locked, no lock surface registered, or ext-session-lock is active
awesome.unlock()nonebooleanUnlock the session. Returns true on success. Only succeeds if awesome.authenticate() was called with a correct password first
awesome.authenticate(password)stringnoneVerify password via PAM. On success, marks session as authenticated. On failure, emits lock::auth_failed
awesome.set_lock_surface(wibox)wiboxnoneRegister the interactive lock surface (receives keyboard input when locked)
awesome.clear_lock_surface()nonenoneUnregister the lock surface. If called while locked, forces unlock
awesome.add_lock_cover(wibox)wiboxnoneRegister a cover surface for multi-monitor support (max 16). Idempotent
awesome.remove_lock_cover(wibox)wiboxnoneUnregister a specific cover surface
awesome.clear_lock_covers()nonenoneUnregister all cover surfaces

Properties

PropertyTypeDescription
awesome.lockedboolean (read-only)True if session is locked via the Lua lock API
awesome.lock_surfacedrawin or nil (read-only)Currently registered interactive lock surface
awesome.lock_mechanismstring or nil (read-only)"lua" if locked via Lua API, nil if not locked

Signals

SignalArgumentsDescription
lock::activatesource (string)Session locked. Source is "user"
lock::deactivatenoneSession unlocked
lock::auth_failednonePassword authentication failed

Security Model

Authentication is enforced at the C level, not in Lua. This means:

  • C-enforced auth: awesome.unlock() checks an internal C flag set only by a successful awesome.authenticate() call. Lua code cannot bypass this.
  • Input routing: When locked, only the registered lock surface and covers receive input. All other surfaces are blocked.
  • Force-unlock safety: If the lock surface is destroyed while locked, the compositor automatically unlocks to prevent a deadlocked session.
  • PAM memory clearing: Passwords are copied to a local buffer, verified via PAM, then securely zeroed using a volatile pointer to prevent compiler optimization.
  • Auth reset: The authenticated flag is reset on every new awesome.lock() call.

Example

-- Minimal lock flow
awesome.lock()

-- In your keygrabber callback:
awesome.authenticate(password)
awesome.unlock()

Idle API

Methods

MethodArgumentsReturnDescription
awesome.set_idle_timeout(name, seconds, callback)string, number, functionnoneCreate or update a named idle timeout (max 32). Callback fires after seconds of inactivity
awesome.clear_idle_timeout(name)stringnoneRemove a named idle timeout. No-op if not found
awesome.clear_all_idle_timeouts()nonenoneRemove all active idle timeouts

Properties

PropertyTypeDescription
awesome.idleboolean (read-only)True when the user has been idle long enough to fire at least one timeout
awesome.idle_inhibitboolean (read/write)Set to true to suppress idle timeouts from Lua. OR-ed with protocol-level inhibitors
awesome.idle_inhibitedboolean (read-only)True if idle is inhibited by any source (protocol inhibitors OR idle_inhibit)
awesome.inhibitorstable (read-only)Array of {client = <client or nil>, visible = bool} for each active Wayland protocol inhibitor
awesome.inhibitor_countinteger (read-only)Number of active Wayland protocol idle inhibitors
awesome.idle_timeoutstable (read-only)Table of {name = {seconds = N, fired = bool}, ...} for all active timeouts

Signals

SignalArgumentsDescription
idle::startnoneUser became idle (first timeout fired)
idle::stopnoneUser activity detected after being idle
property::idle_inhibitednoneCombined idle inhibition state changed (read awesome.idle_inhibited for new value)

Example

-- Dim after 2 minutes, lock after 5 minutes
awesome.set_idle_timeout("dim", 120, function()
-- dim your screens
awesome.dpms_off()
end)

awesome.set_idle_timeout("lock", 300, function()
awesome.lock()
end)

-- Remove a specific timeout
awesome.clear_idle_timeout("dim")

-- Inhibit idle when any client is fullscreen
client.connect_signal("property::fullscreen", function()
local dominated = false
for _, c in ipairs(client.get()) do
if c.fullscreen then dominated = true; break end
end
awesome.idle_inhibit = dominated
end)

-- Reactive wibar icon that shows idle inhibition state
local idle_icon = wibox.widget.textbox()
local function update_idle_icon()
idle_icon.text = awesome.idle_inhibited and " " or " "
end
update_idle_icon()
awesome.connect_signal("property::idle_inhibited", update_idle_icon)

-- Inspect which apps are inhibiting
for _, inh in ipairs(awesome.inhibitors) do
if inh.client then
print(inh.client.class .. " is inhibiting idle (visible: " .. tostring(inh.visible) .. ")")
end
end

DPMS API

Methods

MethodArgumentsReturnDescription
awesome.dpms_off()nonenoneTurn off all displays (sleep mode)
awesome.dpms_on()nonenoneWake all displays

Properties

PropertyTypeDescription
awesome.dpms_statetable (read-only)Table of {output_name = "on"/"off", ...} showing power state per output

Signals

SignalArgumentsDescription
dpms::offnoneAt least one display entered sleep mode
dpms::onnoneAt least one display woke up

Displays automatically wake on user activity (keyboard/mouse input).

See Also