128 lines
7.4 KiB
Markdown
128 lines
7.4 KiB
Markdown
# Background accessibility events
|
||
|
||
On Xorg, Cthulhu rejects known background control updates before resolving
|
||
selected descendants or capturing their text, values, attributes and geometry.
|
||
The native adapter owns this decision on the GLib thread. It uses the existing
|
||
foreground window and epoch; there is no additional window ownership cache.
|
||
|
||
Events from another provider first resolve their containing window: GTK socket
|
||
children can belong to the foreground host while using a different provider
|
||
bus. Unrelated providers are then rejected using the resolved window and copied
|
||
bus identities, before any content queries.
|
||
Events from another window on the same provider undergo the existing window
|
||
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. 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. Embedded panel
|
||
controls use their host's normal X11 correlation; unrelated panel windows and
|
||
hidden menus remain filtered. See [MATE desktop](mate-desktop.md).
|
||
Same-provider autocomplete relations and tooltip candidates
|
||
continue through the existing event-loop ownership checks; they do not acquire
|
||
focus merely by passing the early filter.
|
||
|
||
When notification metadata or a detached document's containing window is
|
||
unknown, the adapter retains the existing validation path. The optimization
|
||
does not introduce an X11 ownership requirement for native Wayland sessions.
|
||
|
||
Orca's `src/orca/event_manager.py` was used as a reference for keeping global
|
||
window monitoring and filtering noisy content events before presentation.
|
||
|
||
## Automated checks
|
||
|
||
Run from the repository root with the normal native build dependencies:
|
||
|
||
```sh
|
||
go test ./... -count=1
|
||
go test -race ./internal/atspi ./internal/app ./internal/review -count=1
|
||
python3 tests/native_test_session.py env CTHULHU_NATIVE_BACKGROUND_EVENTS=1 CTHULHU_NATIVE_WAYLAND_POLICY=1 go test -race ./internal/atspi -run '^TestNative(BackgroundEventFiltering|WaylandForegroundPolicy)$' -count=1 -v -timeout=40s
|
||
python3 tests/native_webscripts.py
|
||
CTHULHU_NATIVE_BROWSER_TESTS=browser,tabs,live,tooltips python3 tests/native_browser.py
|
||
go build -o /tmp/cthulhu-background-events ./cmd/cthulhu
|
||
CTHULHU_BINARY=/tmp/cthulhu-background-events python3 tests/native_ownership.py
|
||
```
|
||
|
||
The flood regression uses two real GTK providers, then two windows on one
|
||
provider. Each burst changes the table selection 300 times. A private D-Bus
|
||
monitor asserts that the rejected updates cause no Selection, Table, Text or
|
||
Value interface calls. The explicit alert used as a completion marker is
|
||
excluded from this content-query assertion. Returning to the noisy window must
|
||
deliver its current table selection. The separate cache regression verifies
|
||
that invalidation preserves other providers' document lines.
|
||
|
||
All native checks use disposable X servers and private D-Bus/runtime sockets.
|
||
They do not replace the active desktop reader. Browser checks cover address
|
||
suggestions, page controls, tabs, live regions and tooltips. Ownership checks
|
||
cover GTK/Qt menus, a GTK menu popup, dialogs, same-process windows, empty
|
||
workspaces and Brave window recovery. Notification checks preserve Steam toast
|
||
capture while rejecting ordinary background Chromium text changes.
|
||
|
||
## Live acceptance
|
||
|
||
Private fixtures do not establish audible speech, physical Braille or actual
|
||
FastSMRW update latency. After reviewing the diff, preserve the current debug
|
||
log and rebuild/start the candidate through the normal local launcher when
|
||
ready to replace the reader.
|
||
|
||
1. Read headings and lines in Brave while FastSMRW receives new items. Compare
|
||
responsiveness with quiet periods. Background selection changes should not
|
||
delay reading or take speech/focus ownership.
|
||
2. Switch to FastSMRW and move through results. Confirm the current selection
|
||
is spoken; open its Open Links popup, move between links, and close it.
|
||
3. Switch between two windows from the same application. Open and close a
|
||
dialog and a menu; confirm speech follows the active control.
|
||
4. In Brave, type into the address bar and move through suggestions. Return to
|
||
the page, switch tabs, and verify normal editing and reading still work.
|
||
5. Check supported background notifications. If using Braille, confirm it
|
||
follows the foreground control and still displays supported notifications.
|
||
|
||
Preserve a fresh log if lag or a missing announcement remains, with the time
|
||
and the key or update that triggered it. Debug logs can contain private text.
|
||
|
||
## Window frame geometry
|
||
|
||
GTK can report the window manager's enclosing frame while X11's active client
|
||
reports only its content area. Slint/i3 exposed this as an active, showing
|
||
1916×994 accessible frame at (0,0) rejected against a 1912×974 client at (2,18).
|
||
Missing or stale `_NET_FRAME_EXTENTS` can make the advertised outer bounds
|
||
identical to those client bounds.
|
||
|
||
Foreground matching also accepts the actual immediate enclosing X11 frame.
|
||
It must contain the client, have bounded decoration edges, and contain no other
|
||
managed client. The desktop root, a parent that is itself a managed client,
|
||
and shared containers are excluded. Existing process, active/showing state,
|
||
iconification, foreground epoch and same-process sibling checks still apply.
|
||
This covers frame/client discrepancies across applications; arbitrary incorrect
|
||
AT-SPI geometry still requires diagnosis. Rejected activation diagnostics now
|
||
include `x_frame_bounds` alongside client and advertised outer bounds.
|
||
|
||
i3 marks its decoration frames `override_redirect`; these frames must pass
|
||
the same tree and containment checks. Rejecting that flag discarded the real
|
||
frame even after frame lookup was added. A later Slint log showed the Run
|
||
dialog and application menu at (0,24), 1916×989, against a client at (2,24),
|
||
1912×987, with no recorded frame. This caused control events to be filtered,
|
||
while explicit suggestion-count announcements still passed.
|
||
|
||
```sh
|
||
python3 tests/native_test_session.py env CTHULHU_NATIVE_FRAME_FOREGROUND=1 CTHULHU_NATIVE_GRAB_FOREGROUND=1 go test ./internal/platform/xorg -run '^TestNative(ReparentedFrameForeground|InputOnlyGrabForeground)$' -count=1 -v
|
||
```
|
||
|
||
The frame fixture covers i3 override-redirect frames (including the reported
|
||
Run dialog geometry), missing, zero and stale extents, borders, moving,
|
||
resizing, switching to a sibling frame, shared containers and empty workspaces.
|
||
On Slint, listen while switching between two windows from one application,
|
||
another application's window, dialogs and menus. Move and resize them, switch
|
||
away to an empty workspace and return, and check preferences again. Confirm
|
||
speech and Braille follow the foreground control and background activity does
|
||
not take focus. Keep the first rejected activation from a fresh debug log if a
|
||
window remains silent; private X11 results do not prove affected-host acceptance.
|
||
|
||
On Slint/I38, open the Run dialog, type a command, and use Left/Right, Home/End
|
||
and Control+Left/Right to review it. Check suggestion navigation as well as
|
||
counts. Open Alt+F1 and move through categories and applications, then close
|
||
it and verify speech returns to the previous window.
|