diff --git a/crates/pdfs-gui/src/app/pages/login.rs b/crates/pdfs-gui/src/app/pages/login.rs index 8200a8c..9c1151c 100644 --- a/crates/pdfs-gui/src/app/pages/login.rs +++ b/crates/pdfs-gui/src/app/pages/login.rs @@ -199,7 +199,13 @@ pub(crate) fn wire_login(ui: &Rc) { ui.login.login_status.set_text(""); ui.login.password.set_text(""); // Cache the new identity so `refresh` never hits the keyring. - *ui.session.borrow_mut() = auth::load().ok(); + // Read on a worker: a keyring that has to be unlocked first + // answers only once the user has, and the window must not + // freeze until then. + *ui.session.borrow_mut() = gio::spawn_blocking(|| auth::load().ok()) + .await + .ok() + .flatten(); // Enable+start the mount service now that we have a session. let _ = gio::spawn_blocking(service::enable_start).await; refresh(&ui); diff --git a/docs/BUGS.md b/docs/BUGS.md index ceb79e3..a964dc0 100644 --- a/docs/BUGS.md +++ b/docs/BUGS.md @@ -100,6 +100,7 @@ a live account since. | Entry | Title | |---|---| +| [B246](#b246--signing-in-with-a-locked-keyring-freezes-the-app-window) | Signing in with a locked keyring freezes the app window | | [B245](#b245--any-child-of-the-daemon-can-answer-the-watchdog-for-it) | Any child of the daemon can answer the watchdog for it | | [B244](#b244--photos-without-a-sidecar-or-a-dated-name-are-filed-under-the-upload-day) | Photos without a sidecar or a dated name are filed under the upload day | | [B243](#b243--a-hung-mount-freezes-the-app-when-a-file-is-opened) | A hung mount freezes the app when a file is opened | @@ -348,6 +349,26 @@ a live account since. Newest first. +### B246 — Signing in with a locked keyring freezes the app window + +**Status:** Fixed, not verified live +**Found:** 2026-10-16, architecture audit (`FINDINGS.md` 2.5.4). +**Where:** `sign_in` in `crates/pdfs-gui/src/app/pages/login.rs` + +**Repro:** Sign in from the app while the system keyring is locked. The keyring asks for its +password, and the app window stops redrawing until that prompt is answered. + +**Cause.** After a successful sign-in the app read the stored session back from the keyring on +the GTK main thread. A locked keyring answers that read only once it is unlocked. + +**Fix.** The read runs in `gio::spawn_blocking`. The read at startup was left as it is: it runs +before any window exists, and the launch actions (`--page`, `--confirm-stop`) need the window +built in the same turn. + +**Test:** none automated; the GUI tests run without a display. + +--- + ### B245 — Any child of the daemon can answer the watchdog for it **Status:** Fixed, not verified live