Emit bread.lock.locked when ext-session-lock-v1 is accepted and bread.lock.unlocked after PAM success. Fail-silent if breadd is down. No command verbs (no pin/blur stubs). breadgreet is not on the bus. Note that Forgejo Arch registry packages are unsigned (SigLevel=Never on BOS) without changing the package.yml registry.
6.9 KiB
breadlock
Session locker and graphical greetd greeter for Hyprland on Wayland — the bread-ecosystem replacement for hyprlock and tuigreet. BOS already ships both binaries: breadgreet under cage via greetd, and breadlock via hypridle (SUPER+L is loginctl lock-session).
Two binaries, one workspace:
breadlock— locks the already running Hyprland session viaext-session-lock-v1. Drop-in forhyprlock.breadgreet— a graphical greeter that speaksgreetd's own IPC protocol (the same architecture asgtkgreet/regreet).greetdkeeps owning PAM auth, VT switching, and session launching;breadgreetonly draws the login UI and relays the conversation. This is a deliberate choice over reimplementing a display manager from scratch —greetdis already installed and battle-tested.
Both use bread-theme for palette loading, matching the rest of the bread* ecosystem (breadbar, breadbox, bos-settings).
bread event integration
breadlock works the same with or without breadd. When breadd is
running, it publishes bread.lock.locked / bread.lock.unlocked. See
EVENTS.md for the bus contract. breadgreet is not on the
bus. There is no bakery.toml (PAM / pacman exception).
Architecture
breadlock/
├── breadlock-ui/ shared: bread-theme wrapper, TOML config, .desktop parsing,
│ software-rendering primitives (tiny-skia + cosmic-text,
│ behind the "paint" feature — only breadlock needs them)
├── breadlock/ the locker (SCTK + PAM)
└── breadgreet/ the greeter (GTK4 + relm4 + greetd_ipc)
breadlock
- Protocol:
ext-session-lock-v1viasmithay-client-toolkit— GTK has no session-lock support, so this is a raw Wayland client, not a layer-shell surface like breadbar. - Rendering: fully software —
tiny-skiacomposites each frame (background, rounded password pill, clock, status line) into awl_shmbuffer;cosmic-textshapes and rasterizes text (loads "Varela Round" by family name). No EGL/GL. - Background: a solid palette color or a static PNG (cover-fit).
background.bluris not implemented — the key is accepted and logs a warning; the surface is drawn unblurred. Live blur-of-desktop (hyprlock-style) would need awlr-screencopycapture. - Auth:
pam-client2against thebreadlockPAM service (packaging/pam.d/breadlock, installed to/etc/pam.d/breadlockby the package). Runs on its own OS thread — libpam's conversation callback is blocking FFI — and reports back through acalloop::channelregistered on the render loop.
breadgreet
- Protocol:
greetd_ipc(greetd's own crate) over the Unix socket at$GREETD_SOCK:CreateSession→ answer eachAuthMessageviaPostAuthMessageResponse→StartSessionhands the resolved session command togreetd, which execs it and owns the VT switch away. - UI: GTK4 + relm4, matching breadbar's stack — without
gtk4-layer-shell.greetdhosts the greeter under a single-client kiosk compositor (cage -s), which already fullscreens its one client, so layer-shell's multi-surface/anchor semantics don't apply. Confirmed against ReGreet's real dependency list, which has no layer-shell dependency either. - Sessions: scans
/usr/share/wayland-sessionsand/usr/share/xsessionsfor.desktopentries and auto-selects the configured default (or the only one found). BOS ships one session today, so there's no picker UI in v1 — a natural v2 addition if that changes.
Config
Copy breadlock.example.toml to ~/.config/breadlock/breadlock.toml and breadgreet.example.toml to /etc/greetd/breadgreet.toml (or ~/.config/breadgreet/breadgreet.toml for local testing under a normal session — breadgreet checks the system path first since it typically runs as the dedicated greeter user). Every field is optional; both binaries run with sensible defaults and no config at all.
Building
cargo build --release --bin breadlock --bin breadgreet
cargo test --workspace
Requires GTK4 (≥ 4.12), libxkbcommon, and PAM development headers. On Arch:
sudo pacman -S gtk4 wayland libxkbcommon pam rust cargo
breadlock-auth-check is a third, dev-only binary in the breadlock package (see Verification below) — not installed by the package, build it explicitly with cargo build --bin breadlock-auth-check if you need it.
Packaging
packaging/arch/PKGBUILD builds and installs both binaries plus /etc/pam.d/breadlock, published to the [breadway] pacman repo by .forgejo/workflows/package.yml. breadlock is a deliberate pacman-only exception — there is no bakery.toml on purpose. A PAM service and greetd greeter need a root-owned install (/etc/pam.d/breadlock), which bakery has no privileged path for.
BOS already wires the packaged binaries (this repo still does not ship those system files):
# /etc/greetd/config.toml — BOS default
[default_session]
command = "cage -s -- breadgreet"
# hypridle lock_cmd (BOS). SUPER+L is loginctl lock-session, which hypridle picks up.
lock_cmd = breadlock
Verification (why this is safe to test without a lockout risk)
- PAM logic in isolation first:
cargo run --bin breadlock-auth-checkexercises the exact PAM flowbreadlockuses, against a typed password, with no Wayland surface at all. A bad/etc/pam.d/breadlockjust prints an error here — it can never lock a session. - Locker rendering/lock lifecycle nested, never against the live session: run
breadlockinside a nested Hyprland instance or undercage -- breadlock.ext-session-lock-v1only ever affects the compositor instance the client is connected to (scoped to$WAYLAND_DISPLAY), so a nested lock can never lock the real outer session. Verify the full type-password → PAM check → unlock cycle there, including the wrong-password path, before ever binding a real keybind. - If testing against a live session: keep a second TTY or SSH session open the whole time. Killing the
breadlockprocess is not a safe unlock path — per the protocol, an abnormally-terminated lock client is expected to leave the compositor still locked. The real recovery path is "kill it, then use the second session to restart Hyprland or switch VT." - breadgreet:
cargo test -p breadgreetruns thegreetd_ipcframing/state-machine tests against a mock Unix-socket server — no realgreetdor PAM involved. Manual testing against a realgreetdshould happen on a disposable VT, not by replacing the live BOScage -s -- breadgreetsession on VT1.
License
MIT