Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 227 additions & 0 deletions rs/crates/app/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions rs/crates/app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ qrcode = { version = "0.14", default-features = false }
# — lifted from spike-tearoff. Bumped 0.58 -> 0.62 to unify with wgpu-hal 29 / gpu-allocator and
# avoid two `windows` crate versions in the graph (which breaks wgpu-hal's d3d12 backend).
# Target-gated so Linux/macOS builds never pull the Win32 bindings.
# AccessKit → AT-SPI, Linux only. The workspace drops Slint's `accessibility` feature because
# accesskit pins `windows 0.58` against wgpu-hal 29's `0.62` — a conflict that only exists
# when building for Windows. Requesting the feature per-target keeps Windows resolution
# untouched while letting the terminal grid (drawn to a texture, invisible to AT-SPI
# otherwise) expose its text to screen readers and assistive automation on Linux.
[target.'cfg(target_os = "linux")'.dependencies]
slint = { git = "https://github.com/slint-ui/slint", rev = "9463a107aeb5f5021c162e82c55977c5333229ae", default-features = false, features = ["accessibility"] }

[target.'cfg(windows)'.dependencies]
# Native Open/Save dialogs via the COM IFileDialog (`windows-sys`, separate from the
# `windows` crate below so it doesn't perturb the pinned 0.62 graph); no backend feature
Expand Down
28 changes: 28 additions & 0 deletions rs/crates/app/src/paneview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,28 @@ fn replay_cursor_pos(_app: &AppWindow, _link_active: bool) {}
/// Build a model row for pane `i`. `editing` flags the pane whose label is being renamed
/// inline; `show_frame`/`show_dot` are the GLOBAL Appearance prefs, folded here over each
/// pane's per-pane override (a clean new pane resolves OFF, a git-project pane ON).
/// Whether an assistive client is listening. The terminal grid is drawn to a texture, so AT-SPI
/// sees an empty rectangle unless we hand it the screen as text — but extracting that text on
/// every model rebuild is wasted work when nobody is reading it. Checking once per process is
/// enough to decide: AccessKit only builds a tree after a client connects anyway.
fn a11y_wanted() -> bool {
use std::sync::OnceLock;
static WANTED: OnceLock<bool> = OnceLock::new();
*WANTED.get_or_init(|| {
if std::env::var("HYPERPANES_A11Y").is_ok_and(|v| v == "1") {
return true;
}
if std::env::var("NO_AT_BRIDGE").is_ok_and(|v| v == "1") {
return false;
}
std::process::Command::new("gsettings")
.args(["get", "org.gnome.desktop.interface", "toolkit-accessibility"])
.output()
.map(|o| String::from_utf8_lossy(&o.stdout).trim() == "true")
.unwrap_or(false)
})
}

fn pane_item(
ps: &PaneState,
focused: bool,
Expand Down Expand Up @@ -265,6 +287,12 @@ fn pane_item(
PaneItem {
surface: ps.surface.clone(),
title: ps.title.clone(),
// The pane's visible text for AT-SPI; empty (and free) when nothing is listening.
a11y_text: if a11y_wanted() {
ps.pane.screen_text().into()
} else {
SharedString::new()
},
subtitle: ps.subtitle.clone().unwrap_or_default(),
ai_subtitle,
// The cached shell-type badge (computed once at pane creation; "" → not shown).
Expand Down
2 changes: 2 additions & 0 deletions rs/crates/app/ui/paneview.slint
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,8 @@ export component PaneView inherits Rectangle {
width: parent.width - 4px;
height: parent.height - 4px;
surface: pane.surface;
title: pane.title;
a11y-text: pane.a11y-text;
accent: pane.accent;
chrome: false;
// clickable-path hover overlay (controller-driven after hit-testing)
Expand Down
3 changes: 3 additions & 0 deletions rs/crates/app/ui/types.slint
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import { HiRect } from "@widgets";
export struct PaneItem {
surface: image,
title: string,
// Visible screen text, for assistive tech (AT-SPI). Empty unless an
// accessibility client is connected — see paneview::a11y_wanted().
a11y-text: string,
// optional secondary line under the label (user subtitle / ambient-AI line).
subtitle: string,
// ambient-AI summary line, already truncated to the typewriter-revealed prefix by the
Expand Down
8 changes: 8 additions & 0 deletions rs/crates/terminal-widget/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ arboard = "3"
# core's feature set so the runtime has time/sync/macros available.
tokio = { version = "1", features = ["rt-multi-thread", "sync", "time", "macros"] }

# AccessKit → AT-SPI, Linux only. The workspace drops Slint's `accessibility` feature because
# accesskit pins `windows 0.58` against wgpu-hal 29's `0.62` — a conflict that only exists
# when building for Windows. Requesting the feature per-target keeps Windows resolution
# untouched while letting the terminal grid (drawn to a texture, invisible to AT-SPI
# otherwise) expose its text to screen readers and assistive automation on Linux.
[target.'cfg(target_os = "linux")'.dependencies]
slint = { git = "https://github.com/slint-ui/slint", rev = "9463a107aeb5f5021c162e82c55977c5333229ae", default-features = false, features = ["accessibility"] }

[dev-dependencies]
# PNG encode for the headless font-fallback before/after verification bin only.
png = "0.17"
Expand Down
8 changes: 8 additions & 0 deletions rs/crates/terminal-widget/ui/widget.slint
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,17 @@ component SearchBtn inherits Rectangle {
}

export component TerminalPane inherits Rectangle {
accessible-role: text;
accessible-label: root.title;
accessible-value: root.a11y-text;
accessible-read-only: true;
// --- inputs (the controller / parent layout drive these) ---
in property <image> surface;
in property <string> title: "";
// What assistive tech reads instead of the rendered pixels: the terminal
// screen as text. The grid is drawn to a texture, so without this the pane
// is a blank rectangle to AT-SPI.
in property <string> a11y-text: "";
in property <color> accent: #7aa2f7;
in property <bool> chrome: true;

Expand Down
Loading