3.6 KiB
AT-SPI lifecycle and notebook flat review
Adapter shutdown removes event subscriptions, the foreground timer and pending
capture sources on the GLib owner thread before releasing callback data and its
Go handle. Incoming owned event copies are freed after the Go callback returns.
Only one adapter may own the process-global AT-SPI loop at a time.
Sequential adapters reuse the library connection: upstream documents
atspi_exit()
as a process-exit operation. Process termination releases that connection.
GTK notebook focus is resolved to the selected tab. This lets ordinary duplicate focus suppression handle the notebook/tab focus replay after an X11 reader-key grab, without suppressing real tab changes or returning from a page control.
Run the lifecycle regressions on a disposable display and accessibility bus:
python3 tests/native_test_session.py env CTHULHU_NATIVE_LIFECYCLE=1 go test -race ./internal/atspi -run '^TestNative(SequentialAdapterLifecycle|AdapterPendingCaptureShutdown|CanceledAdapterStart|AdapterStopRetry)$' -count=1 -v
These cover a live GTK provider across adapter replacement and restart, concurrent
adapter rejection, canceled startup, a canceled capture left pending at shutdown,
and a Stop retry after its caller times out. The original sequential test crashed
with runtime/cgo: misuse of an invalid Handle before the fix.
AddressSanitizer also runs these cases with -asan in place of -race.
The sequential GTK case previously reported 360 bytes in eight allocations
after three repeated fixture runs. Focused-descendant lookup freed the Collection
result array without releasing its owned accessible references. It now releases
every result while preserving a separate reference for the returned target.
The array does not have an element cleanup function in
libatspi's Collection implementation.
The earlier incoming-event-copy leaks were fixed in the callback wrapper.
To check the original reproduction, use the lifecycle command above with
-asan, -run '^TestNativeSequentialAdapterLifecycle$' and -count=3;
keep leak detection enabled. A passing Go test followed by a LeakSanitizer
failure is a failed check. This focused check does not establish leak freedom
for the whole reader or its native dependencies.
Build a separate binary and run the full reader/preferences regression:
go build -o /tmp/cthulhu-lifecycle-review ./cmd/cthulhu
CTHULHU_BINARY=/tmp/cthulhu-lifecycle-review CTHULHU_PREFS_FLAT_REVIEW_ONLY=1 /usr/bin/python3 tests/native_preferences.py
This uses private Xvfb, D-Bus and recorded SSIP speech. It checks line, word and character review on the General tab, absence of following tab announcements, real tab changes, Tab into the page and Shift+Tab back to the tab strip. Evidence is retained in the printed temporary directory. It does not replace listening or physical keyboard/Braille checks.
For live acceptance with a user-started updated build, focus the General tab header and review several lines, words and characters in both directions. Each review response should finish without “page tab list / General / page tab”. Use Left/Right to change tabs, Tab into a page and Shift+Tab back: those genuine focus changes should still speak. Check another application's notebook and a browser tab strip, plus ordinary menus and single/multiple table selections, because they share focus-target selection. Confirm Braille review stays at the review position until genuine navigation changes focus.