Fix greeter session start and login flow

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.
This commit is contained in:
Breadway 2026-08-23 14:21:29 +08:00
parent 6925e132fd
commit 495d7f8446
9 changed files with 763 additions and 168 deletions

View file

@ -80,14 +80,23 @@ impl Default for Font {
}
}
/// Reads and parses a TOML config file, falling back to `T::default()` if the
/// file is missing or malformed — every bread* app runs with sensible
/// defaults and no required config.
/// Reads and parses a TOML config file. A missing file is a silent
/// `T::default()`; a present but malformed file prints a warning (with the
/// path) and also falls back to `T::default()`.
pub fn load_or_default<T: serde::de::DeserializeOwned + Default>(path: &Path) -> T {
std::fs::read_to_string(path)
.ok()
.and_then(|s| toml::from_str(&s).ok())
.unwrap_or_default()
match std::fs::read_to_string(path) {
Ok(s) => match toml::from_str(&s) {
Ok(parsed) => parsed,
Err(err) => {
eprintln!(
"warning: failed to parse {}: {err} — using defaults",
path.display()
);
T::default()
}
},
Err(_) => T::default(),
}
}
#[cfg(test)]
@ -112,11 +121,27 @@ mod tests {
#[test]
fn parses_partial_toml_with_defaults_for_rest() {
let dir = std::env::temp_dir().join("breadlock-ui-test-partial.toml");
std::fs::write(&dir, "[clock]\nformat = \"%I:%M %p\"\n").unwrap();
let a: Appearance = load_or_default(&dir);
let path = std::env::temp_dir().join(format!(
"breadlock-ui-test-partial-{}.toml",
std::process::id()
));
std::fs::write(&path, "[clock]\nformat = \"%I:%M %p\"\n").unwrap();
let a: Appearance = load_or_default(&path);
assert_eq!(a.clock.format, "%I:%M %p");
assert_eq!(a.background.mode, BackgroundMode::Color);
std::fs::remove_file(&dir).ok();
std::fs::remove_file(&path).ok();
}
#[test]
fn invalid_toml_falls_back_to_default() {
let path = std::env::temp_dir().join(format!(
"breadlock-ui-test-invalid-{}.toml",
std::process::id()
));
std::fs::write(&path, "this is not = toml [[[").unwrap();
let a: Appearance = load_or_default(&path);
assert_eq!(a.clock.format, "%H:%M");
assert_eq!(a.font.family, "Varela Round");
std::fs::remove_file(&path).ok();
}
}