Session locking
Gnoblin uses the standard ext-session-lock-v1 Wayland protocol in the
Gnoblin session. The compositor owns the security boundary: it covers every
output, stops normal input, replaces desktop capture with its lock scene, and
stays locked if a locker exits. The locker owns its appearance and
authentication. See the protocol XML.
The lock screen is a separate client. Bingux is one shell project with its own lock client.
Third-party lockers such as hyprlock, swaylock, gtklock and waylock can connect
directly to the same standard protocol. Any client with access to this user's
Wayland socket can request the lock; Gnoblin does not filter requests by
process. The first request owns the lock, and concurrent requests receive
finished.
In Bingux, use its Lock action or run bingux-lock. With another locker
installed, run its command (for example, hyprlock) in your Gnoblin session.
Your shell or idle daemon decides when to run that command; Gnoblin does not
set a timeout or launch a locker for you.
The protocol is enabled by default in Gnoblin. To hide its global, set
ext_session_lock = false under gnoblin.configure.protocols, then log out and
back in; protocol globals are registered at compositor startup. See the
protocol setting reference.
Request a lock
A lock request asks your shell to show its lock screen. Gnoblin sends the
request as the gnoblin.session.lock-requested event to every shell client
that subscribed to it, and to the Lua configuration when it listens for the
event. The shell starts its locker, and the locker takes the lock with
ext-session-lock-v1. Gnoblin binds no key and starts no locker.
These sources send the request:
gnoblinctl session lockgnoblin.session.lock()in the Lua configurationorg.freedesktop.ScreenSaver.Lock, orSetActive(true), on the session busloginctl lock-sessionfor your graphical session, and a lid or idle policy that asks logind to lock it
A request does not prove the session is locked. The call reports whether a
shell received the request. Read lock_state in gnoblinctl status or
gnoblin.session.status() to see the real state.
If no shell is subscribed, the call fails and says so. gnoblinctl exits with
an error, and ScreenSaver.Lock returns the error
no session-lock client is subscribed to lock requests. A logind request writes
the same message to the journal. Gnoblin leaves the session unlocked in this
case.
A request while the session is already locked succeeds and sends no second
event. SetActive(false) returns NotSupported, because only the locker can
unlock.
ScreenSaver.GetActive returns false for unlocked and true for
covering, locked, or failsafe. These are the compositor's
lock states; only locked confirms the
lock transition.
Subscribe to org.freedesktop.ScreenSaver.ActiveChanged on the session bus at
/org/freedesktop/ScreenSaver to receive that boolean when it changes. Read
GetActive for the initial value. Changes between active lock states do not
send duplicate signals. Use gnoblin.session.lock-state-changed when you need
the individual state transitions.
If the compositor connection is interrupted, Gnoblin sends no unlock signal.
It reconnects and reports a changed boolean from the current state. After the
idle service restarts, read GetActive again for its initial value.
To lock with a key of your choice, bind a key in the Lua configuration:
gnoblin.configure {
keybindings = {
keyboard = {
lock_screen = {
binding = "<Super>l",
callback = function()
gnoblin.session.lock()
end,
},
},
},
}To receive the request in your Lua configuration, listen for the event and
start the locker. This handler starts swaylock on each request and logs when
the lock does not take effect:
gnoblin.on("gnoblin.session.lock-requested", function(event)
gnoblin.process.spawn({"swaylock", "-f"})
event.request:finished():on_complete(function(outcome)
if outcome ~= "locked" then
print("swaylock did not lock the session")
end
end)
end)event.request is a Request of kind "lock". Its
finished() Operation reports one of two outcomes:
"locked": the session locked."timeout": the session did not lock within 30 seconds.
A shell process that connects to the compositor bridge subscribes to the same event.
Check the result from a terminal:
gnoblinctl session lock
gnoblinctl statuslock_state changes from unlocked to locked after the locker takes the
lock.
Portal and remote access while locked
Remote and portal streams are routed by the selected portal backend. While the session is locked, a monitor stream that is already running receives the compositor lock scene rather than normal desktop content.
Remote keyboard and pointer input is available after locked and lock-scene
presentation, and is routed only to the active lock surface. It is refused
during the transition and failsafe states. No lock-specific portal setting is
required.
Locker requirements
A locker binds ext_session_lock_manager_v1 and sends lock. The compositor
then sends locked or finished on the new lock object. finished means the
request was not granted; do not show an authentication UI for that lock.
After requesting the lock, create one wl_surface per output and pass each to
get_lock_surface before attaching or committing a buffer. An output can have
only one lock surface for this lock. For every configure(serial, width, height), acknowledge its serial before committing a non-null buffer with those
exact surface-local dimensions. If multiple configures arrive before a commit,
acknowledging the last one is sufficient.
| Interface | Request or event | Contract |
|---|---|---|
ext_session_lock_manager_v1 |
destroy |
Release the manager object; existing lock objects remain valid. |
ext_session_lock_manager_v1 |
lock |
Create a lock request; it later receives locked or finished. |
ext_session_lock_v1 |
destroy |
Cancel or retire a lock only before locked; destroy its lock surfaces too. |
ext_session_lock_v1 |
get_lock_surface(surface, output) |
Create the output's lock surface before the wl_surface has a role or buffer. |
ext_session_lock_v1 |
locked |
The lock scene has been presented and it is safe to treat the session as locked. |
ext_session_lock_v1 |
finished |
The compositor did not grant this lock request. |
ext_session_lock_v1 |
unlock_and_destroy |
After authentication succeeds and locked was received, release the session lock. |
ext_session_lock_surface_v1 |
ack_configure(serial) |
Acknowledge a configure before committing its buffer. |
ext_session_lock_surface_v1 |
configure(serial, width, height) |
Resize to the exact output-local dimensions, acknowledge serial, then commit a matching buffer. |
ext_session_lock_surface_v1 |
destroy |
Retire the lock surface. Removing one for an active output before unlock makes Gnoblin show a solid color there. |
After locked, only the owner calls unlock_and_destroy; destroying the lock
object instead is a protocol error. If the client exits immediately after
unlocking, send wl_display.sync and wait for its callback before disconnecting
so the compositor processes the request. A locker crash leaves the compositor
covered and locked; another client may acquire the lock afterwards.
The protocol rejects a null lock-surface buffer, a commit before the first configure is acknowledged, a buffer with the wrong dimensions, duplicate output surfaces, and destroying the active lock without unlocking. See the protocol XML for the complete error enums.