diff --git a/ROADMAP.md b/ROADMAP.md index 070552d07..ae2c5c6f2 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,7 +2,7 @@ **Stage: alpha** · next: beta, ~25 points of "ready for real work" and ~160–240 h away -> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-12 · **Change:** minor (rows auto-fit oversized fonts on open and whole-row/column formatting) · **Target:** Microsoft Excel (Microsoft 365) +> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-19 · **Change:** trivial (desktop theme watcher survives a portal that never answers) · **Target:** Microsoft Excel (Microsoft 365) GridCraft aims at full Microsoft Excel parity, and at being better in places: faster, open (XLSX is the native format), fully scriptable by agents (MCP, control channel, CLI), and on the web. @@ -132,6 +132,7 @@ Ranked; estimates in Opus 5.5 agent-hours. Detail and the full beta-gate list in | Date | What landed | |---|---| +| 2026-10-19 | Linux: "Use system setting" for the theme keeps following the desktop when the XDG Desktop Portal stops answering: each read gives up after 2 s and the next poll reconnects, where one unanswered call stalled the watcher for the rest of the session | | 2026-10-12 | Rows auto-fit oversized fonts: opening a file and whole-row/column formatting grow non-custom rows to their tallest font (#833) | | 2026-10-12 | Number formats: parsing a format code is linear in its length (long runs of `[`, `,` or `/` no longer take quadratic time), and an unclosed `[` is a literal when splitting sections as well as when tokenizing (#810) | | 2026-10-12 | Number formats: a fraction denominator with 65,536 zeros no longer crashes; format codes are capped at 255 characters like Excel (longer codes display as General, `TEXT` gives `#VALUE!`) (#807) | @@ -193,6 +194,7 @@ Ranked; estimates in Opus 5.5 agent-hours. Detail and the full beta-gate list in | Date | Change | Summary | |---|---|---| +| 2026-10-19 | trivial | Progress log: desktop theme portal read timeout | | 2026-10-12 | minor | Rows auto-fit oversized fonts on open and whole-row/column formatting (#833); progress log row | | 2026-10-12 | minor | Progress log: multi-area row/column delete (#758) | | 2026-10-12 | trivial | Progress log: XLSX chart sheets kept on save (#727) | diff --git a/crates/ui-egui/src/desktop_theme.rs b/crates/ui-egui/src/desktop_theme.rs index 9d67c337a..63cf8d3e4 100644 --- a/crates/ui-egui/src/desktop_theme.rs +++ b/crates/ui-egui/src/desktop_theme.rs @@ -12,6 +12,12 @@ use std::time::Duration; /// round trip every few seconds is cheap and reacts soon enough after a theme switch. const POLL: Duration = Duration::from_secs(4); +/// How long one read waits for the portal's reply. Without it a portal that never answers blocks +/// the watcher for good, and the theme stops following the desktop. Shorter than [`POLL`]: a read +/// that times out drops the connection, and the next poll asks again on a fresh one. +#[cfg(target_os = "linux")] +const REPLY: Duration = Duration::from_secs(2); + /// Whether the desktop asks applications to draw dark. `None` when it says nothing, and when /// there is no session bus or no portal to ask (a bare X server, a container), so the caller /// keeps whatever it chose itself. @@ -82,7 +88,7 @@ fn read(link: &mut Link) -> Option { const SETTINGS: &str = "org.freedesktop.portal.Settings"; const SCHEMAS: [(&str, &str); 2] = [("org.gnome.desktop.interface", "color-scheme"), ("org.freedesktop.interface.color-scheme", "color-scheme")]; if link.is_none() { - *link = Some(zbus::blocking::Connection::session().ok()?); + *link = Some(zbus::blocking::connection::Builder::session().ok()?.method_timeout(REPLY).build().ok()?); } let connection = link.as_ref()?; for (schema, key) in SCHEMAS {