Add the announcement of switched workspaces from Niri.

I haven't tested this with Braille support; I don't remember what I did with the cable.
This commit is contained in:
hjozwiak committed 2026-10-31 15:27:40 -04:00
1 parent 702894ee4a
commit 1780afccba
14 files changed
+393 -2

No files matched your search

+64
View File
@@ -0,0 +1,64 @@
# AT-SPI announcements
Providers can ask the reader to speak a message without moving focus by
emitting the AT-SPI `object:announcement` event. The event's `any_data`
carries the text and `detail1` carries the politeness (`AtspiLive`: 1 is
polite, 2 is assertive). Orca presents the text verbatim; Cthulhu now does
the same, with a Braille flash through the system-role output queue.
The motivating provider is the Niri compositor (25.08+), which exposes its
own UI through AccessKit. A capture from Niri 26.04 on 2026-10-31 shows a
workspace switch emits `object:property-change:accessible-name` and then
`object:announcement` (polite) with text such as `Workspace 2 Mistworld` on
a label in the `niri` application, about 10 ms before the newly focused
window activates. Niri alternates live-node identities (and may append a
space) so repeated messages still emit; Cthulhu trims the payload and
dedupes one provider's repeat inside 300 ms.
Announcements bypass background-event filtering and foreground epochs: the
provider explicitly requested speech and may never own focus. They do not
move focus, review, or reading state. Screen-lock and secure-input gates
still suppress them. Assertive announcements interrupt; polite ones append.
Payload text is bounded by the adapter's existing snapshot sanitization.
## Automated checks
Run from the repository root with the normal native build dependencies:
```sh
go test ./internal/atspi ./internal/app -run Announcement -count=1
python3 tests/native_test_session.py env CTHULHU_NATIVE_ANNOUNCEMENT=1 go test ./internal/atspi -run '^TestNativeAnnouncementEventDelivered$' -count=1 -v -timeout=40s
```
The native check uses `tests/gtk_announce.py`, a GTK4 fixture whose
`announce` calls must arrive as adapter events with the exact payload and
politeness (medium priority arrives polite, high arrives assertive).
On hosts without a systemd user manager, D-Bus activation of the AT-SPI
registry can fail inside the private session (the pre-existing native
checks fail the same way). Starting the a11y bus and registry manually
inside the session works around it:
```sh
python3 tests/native_test_session.py env CTHULHU_NATIVE_ANNOUNCEMENT=1 sh -c '/usr/lib/at-spi-bus-launcher & sleep 1; ADDR=$(busctl --user call org.a11y.Bus /org/a11y/bus org.a11y.Bus GetAddress | sed "s/^s //;s/\"//g"); AT_SPI_BUS_ADDRESS=$ADDR /usr/lib/at-spi2-registryd & sleep 1; go test ./internal/atspi/ -run "^TestNativeAnnouncementEventDelivered$" -count=1 -v -timeout=40s'
```
## Live acceptance (Niri)
Requires the maintainer's authorization to replace the running reader.
Report automated, audible-speech, and physical-Braille results separately.
1. Start the built reader in a full Niri session (started via a display
manager or `niri-session`, so Niri exposes its accessibility tree).
2. Switch between named, unnamed, and the trailing empty workspace with
Niri's own binds. Each switch speaks the workspace label once, before
the newly focused window, and focus presentation still follows.
3. Burst-switch several times quickly. Only settled announcements speak;
no duplicates from the paired accessible-name change.
4. Cycle the AltTab switcher and open the exit dialog (`Super+Shift+E`)
and the hotkeys list (`Super+Shift+/`). Selected windows and dialog
text are announced as with Orca on the same session.
5. Introduce a temporary config parse error and reload. The error is
announced.
6. Lock the screen and switch workspaces. Nothing is spoken or flashed
until unlock.
+2 -1
View File
@@ -12,7 +12,8 @@ correlation before content capture. Lifecycle invalidation still runs, but a
background provider no longer clears another provider's cached document lines.
Window creation, activation, deactivation, destruction and defunct events keep
their existing handling. Native alerts, notification daemons and supported
their existing handling. Announcement events are explicit requests to speak
and also bypass the filter; see [announcements](announcements.md). Native alerts, notification daemons and supported
Steam toasts retain their notification paths. Menu popups retain existing
foreground checks. Verified active/showing `mate-panel` menu windows may pass
across provider boundaries, including over an empty desktop; ordinary panel