Login UX
- Enumerate human accounts from /etc/passwd (UID_MIN..UID_MAX per
/etc/login.defs, real login shell, minus nobody) and skip the
username field: one account goes straight to the password prompt
with the name shown, several get a picker. Zero found falls back to
typing. New [user] config: `name` pins one account, `prompt = true`
restores the type-it flow.
- The greeter opens the greetd conversation at startup in auto mode so
it lands directly on the password prompt (AutoStart).
- reset_to_username -> reset_auth: auto mode re-opens the password
prompt for the same account on error/Escape rather than showing a
username field it never had.
Typography fix
- bind_window_auto re-broadcasts the shared component sheet (incl. its
`* { font-size }` base rule) at USER-10, which outranks the
APPLICATION-priority provider apply_app_css uses regardless of
selector specificity -- so the hero clock and every other type
override silently collapsed to base size. Ride breadgreet's sheet
through bind_window_auto_with_app_css instead (USER-9), matching
breadbar.
Polish
- Accent rule between the clock and card, drawn in via scaleX with a
glow halo; card gradient + top highlight + deep shadow, bg-pop
overshoot entrance, slow bg-breathe idle pulse; layered accent focus
glow on the entry; gradient session/user pills. Entrance/idle motion
is CSS @keyframes now (setup_entrance removed).
- Errors pinned to a legible red -- BOS's default @red slot is a warm
ochre, unreadable as a warning.
- Drop the duplicate prompt text (placeholder + status line both said
"Password:").
Preview harness
- scripts/preview.sh + scripts/mock-greetd.py run the real greeter in a
nested Weston window against a stand-in greetd, so the whole flow
(spinner, wrong-password shake, success) is drivable without a
reboot. $BREADGREET_CONFIG overrides the config search path so a
preview never touches /etc/greetd/breadgreet.toml.
breadgreet's stylesheet was a crude subset of what `design/sketch.html`
specifies for `.greetoverlay`. Ported it faithfully so the greeter and
the lock screen read as one visual identity:
- Card: proper elevation (`box-shadow: 0 6px 28px`), a hairline
`alpha(@overlay, 0.09)` border, 10px radius, 300px min-width.
- Entry: recessed `shade(@surface, 1.5)` fill, and an accent focus ring
(`border-color: @accent` + `box-shadow: 0 0 0 2px alpha(@accent, .28)`)
matching the sketch's `.gentry:focus`.
- Clock/date over the wallpaper get a soft text-shadow for legibility on
any background; sizes match the sketch (46 / 14).
- Session picker styled as a surface pill (button + popover), not a bare
GtkDropDown.
- A CSS-animated ring shown while a greetd request is in flight
(`sync_busy`, driven from the single `update` exit point).
- Shake on a failed attempt (`flash_error`), matching the lock screen's
wrong-password motion — fired from both `AppInput::Error` and a PAM
`AuthPrompt::Error`.
Uses the shared `@define-color` palette (`@surface`, `@overlay`,
`@accent`, `@red`) so it recolours with the theme, same as breadbar.
`cargo test --workspace --all-targets` (157) / `clippy --all-targets -D
warnings` / `fmt --check` all clean. Visual pass still wanted — the CSS
is a direct translation of the mockup, not screenshot-verified.
Addresses the deep codebase audit:
- Center the static wallpaper cover-fit crop so the software (wl_shm)
path agrees with the GPU path and the greeter, instead of anchoring
the crop top-left.
- Desktop-entry Exec tokenizer: respect single quotes and proper
backslash escaping per the freedesktop spec.
- Greeter: dispatch CancelSession whenever the UI resets to the
username stage so the error path can't leave greetd holding a stale
PAM conversation; add a per-roundtrip timeout so a wedged greetd peer
can't strand the "Working" spinner.
- start_locker: return an error instead of spawning a child that
expect()-panics when WAYLAND_DISPLAY is unset.
- Bound in-flight PAM checks with a concurrency cap, since libpam
cannot be cancelled and a stuck module would otherwise leak one
uncancellable thread per retry.
- Expand unit/regression tests (157 total): tokenizer edge cases and a
pseudo-fuzz, blit offset/clamp cases, horizontal+vertical cover
centering, greetd roundtrip-timeout and connection-recovery.
- Reformat the workspace to rustfmt-clean and add a Forgejo CI gate
(fmt --check, clippy -D warnings, all-target tests, locked release
build) — previously the only workflow was an Arch package builder.
greetd only launches the session after the greeter process exits. Quit
on successful StartSession instead of sitting on "Starting session…"
until SIGTERM.
Empty Secret/Visible answers are Some("") (not PAM cancel). The greetd
actor stays up across connect failure and reconnects. Escape cancels
the conversation. Session env sets XDG_SESSION_TYPE/DESKTOP. .desktop
parsing honors Hidden/NoDisplay/TryExec and quoted Exec=. Invalid TOML
warns instead of failing silent. Font, date, and Ken Burns config match
what the greeter actually draws.
The greeter previously ignored the configured background image and
rendered a static palette screen. Now the wallpaper is painted behind
the login card via a GtkDrawingArea draw callback (GTK4's GL pipeline),
with a Ken Burns pan driven by a tick callback and a veil gradient
matching breadlock's software renderer. The clock + card cluster fades
in and rises on entry.
Key bug avoided: the first attempt panned by resizing a GtkPicture,
which fed back into the window's minimum size and grew the window
unboundedly (17k x 11k). The draw-callback approach has no layout
feedback.
🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
List .desktop sessions from the existing scan, pre-select bos when
present (else the first entry), and pass the chosen Exec= argv to
greetd StartSession.
Pulls the fix for panels turning brown/off-hue when pywal extracts a light
or muddy background from the wallpaper — background/surface now stay BOS's
fixed dark constants regardless of what the wallpaper looks like.