Merge PR #2026: Linux: time out the desktop theme's portal read

ROADMAP.md: header line takes the newer date and mentions both changes; both progress-log rows and revision-history rows kept once, newest first.
This commit is contained in:
aiongg
2026-10-22 02:35:16 +00:00
2 changed files with 10 additions and 2 deletions
+3 -1
View File
@@ -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-16 · **Change:** trivial (progress log: web preferences kept between visits, #1562; previously 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; previously: web preferences kept between visits, #1562) · **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-16 | The web app keeps its preferences between visits (#1562): theme (dark mode), interface size, language, editing options and the rest of what the desktop app saves in `ui.json` and `prefs.json` are kept in the browser's `localStorage`, written as soon as they change |
| 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) |
@@ -194,6 +195,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-16 | trivial | Progress log: web preferences kept between visits (#1562) |
| 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) |
+7 -1
View File
@@ -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<bool> {
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 {