Review and strengthen LibreOffice code so far.

This commit is contained in:
Storm Dragon committed 2026-10-15 21:32:44 -04:00
1 parent f885333520
commit 04e6c08fff
8 files changed
+180 -72

No files matched your search

+47 -50
View File
@@ -47,6 +47,12 @@ reorganizing unrelated reader code or building a speculative plugin framework.
- Calc active-cell events establish logical focus, including after editing
and when the sheet changes.
- LibreOffice frame activation and X11 foreground recovery establish window
ownership without the generic focused-descendant search. Calc's following
cell/editor events establish document focus. Searching the previous view
during workbook activation caused stale-object queries and timeouts on return;
leaving activation on the frame avoids that work. Dialogs retain normal
focused-control resolution.
- Cell contents and addresses are separate. Normal speech gives the value,
then the address; an empty value gives “blank.” Only-displayed-text mode
omits the address and the synthetic blank label.
@@ -185,17 +191,21 @@ checks. These slices do not establish complete Office support.
## Verification
```sh
GOCACHE=/tmp/cthulhu-go-cache go test -race ./internal/atspi ./internal/app ./internal/presentation ./internal/input ./internal/platform/xorg -count=1
dbus-run-session -- env GOCACHE=/tmp/cthulhu-go-cache go test -race ./... -count=1
dbus-run-session -- env GOCACHE=/tmp/cthulhu-go-cache go test -tags brlapi ./... -count=1
python3 tests/check_speech.py
/usr/bin/python3 tests/native_libreoffice.py
python3 tests/native_atspi.py --table-only
GOCACHE=/tmp/cthulhu-go-cache go build -o /tmp/cthulhu-libreoffice ./cmd/cthulhu
GOCACHE=/tmp/cthulhu-go-cache go test -c -o /tmp/cthulhu-libreoffice-xorg.test ./internal/platform/xorg
CTHULHU_BINARY=/tmp/cthulhu-libreoffice python3 tests/native_x11.py
CTHULHU_BINARY=/tmp/cthulhu-libreoffice CTHULHU_XRECORD_TEST=/tmp/cthulhu-libreoffice-xorg.test python3 tests/native_x11.py
xvfb-run -a env CTHULHU_NATIVE_X11=1 /tmp/cthulhu-libreoffice-xorg.test -test.run '^TestNativeDispatchBeforeRelease$' -test.v
```
The Calc harness launches installed LibreOffice with a disposable profile,
document, virtual X11 display, and private session/accessibility buses.
The Calc harness requires i3 as well as LibreOffice, Xvfb, xdotool, xprop,
the Python AT-SPI bindings and the normal native build dependencies. It launches
installed LibreOffice with a disposable profile, document, private i3 window
manager, virtual X11 display, and private session/accessibility buses.
It exercises the production native adapter and event loop; recorded speech
and Braille are asserted for cell movement and blanks, F2 typing, Escape
cancellation, Enter commit, caret movement inside an existing numeric cell,
@@ -210,8 +220,11 @@ The native listener tests check the desktop formula shortcut before key release;
the Calc harness sends semantic requests through the production event loop.
Dynamic-header checks exercise both axes, automatic axis-change speech,
Where Am I, complete Braille context, heading edits, independent clearing,
sheet round trips, and a second workbook with matching sheet names. Returning
to the original workbook is a separate pending acceptance check below.
sheet round trips, and both return directions between workbooks with matching
sheet names and different headings, using normal navigation without Ctrl+F6
recovery. Recorded speech, Where Am I and Braille must retain each workbook's
own headings. Find and Replace typing and
cancellation check the ordinary focused-control path and return to the sheet.
Header command bindings are checked through
the shared binding resolver in both layouts.
No active reader is replaced and no normal Office profile is changed.
@@ -260,49 +273,31 @@ physical Braille. Before submission, review the diff and test a rebuilt binary:
Human review and testing remain required by `CONTRIBUTING.md`. Passing this
fixture alone is not sufficient for submission or live accessibility acceptance.
Initial verification against LibreOffice 26.2.6.3 passed the Calc harness,
affected-package race tests, vet/build, GTK table/multiselection checks, and
Xorg input checks. Browser tab and table checks also passed. Browser editing
failed on an extra title announcement both here and on untouched commit
`8e76d23`. Browser modes initially failed to focus a heading after reload,
then passed on the baseline and on a rerun here; the cause of that first
failure was not established. Physical acceptance remains pending.
The tightening pass against LibreOffice 26.2.6.3 verifies the existing cell,
editor, formula, selection and dynamic-header slices and adds workbook return
coverage. Returning to the original workbook previously reproduced stale-object
timeouts through the production adapter. Keeping LibreOffice frame activation
out of the generic descendant search makes the recorded return checks pass;
header choices remain independent in both workbooks. Foreground recovery uses
the same policy, preventing raw sheet-state chatter before the first cell event.
The virtual-display driver uses window-manager activation and waits for the
heading cell before editing it.
Formula-slice verification passed the isolated real Calc harness, focused
race tests, vet/build, ordinary GTK table/multiselection checks, and the rebuilt
reader's Xorg smoke test. A separate private X11 listener test verified the
formula shortcut with both release orders. The broader app race run exposed
`TestRunReachesSoundStopAfterEarlierServiceStopError`: it can cancel during
startup and receive `context canceled` instead of its expected shutdown error.
The same failure reproduced on unchanged commit `e0c8c61` with
`GOMAXPROCS=8 go test -race ./internal/app -run '^TestRunReachesSoundStopAfterEarlierServiceStopError$' -count=100`.
The remaining app race tests passed with that one test excluded.
The broader native listener suite also has an existing C helper link failure
for missing xkbcommon symbols; the formula shortcut was tested directly using
the command above. Audible formula speech, physical input/Braille, and real
workbook acceptance remain pending.
Full default, race and BrlAPI-tagged Go suites, the speech regression gate,
vet/build, parity-ledger validation, ordinary GTK table/multiselection checks,
and the isolated X11 reader/listener harness pass. The former shutdown test
failure is fixed by waiting for completed runtime startup before cancellation.
A process-cleanup assertion also now accepts ESRCH when a killed task disappears
during a procfs read. Neither correction skips the underlying shutdown checks.
The earlier native probe linker failure no longer reproduces with the current
listener harness.
Selection-slice verification passed the isolated real Calc harness (including
disjoint and capped selections), focused race tests, vet/build, parity-ledger
validation, and ordinary GTK table/multiselection checks. The full affected-package
race run again hit the startup timing test above; all remaining affected-package
race tests passed with
`go test -race ./internal/atspi ./internal/app ./internal/presentation -skip '^TestRunReachesSoundStopAfterEarlierServiceStopError$' -count=1`.
The whole-row/column contraction event gaps described above were independently
observed without the reader. Audible output, physical input/Braille, and
independent-workbook acceptance remain pending.
Dynamic-header verification passed focused race checks, the full affected-package
race run in a private D-Bus session, vet/build, parity-ledger validation and
ordinary GTK table/multiselection checks. Recorded Calc checks cover both axes,
heading edits, independent clearing, sheet round trips and isolation in a second
workbook with identical sheet names. A synthetic return to the original workbook
produced stale/timed-out accessibility objects after window activation, even
with Ctrl+F6 and explicit window raising. Its cause was not established, and
baseline behavior was not compared. This is not evidence of working workbook
return; verify that workflow separately. Tab rename/add/remove event delivery,
physical speech, physical input/Braille and independent real-workbook acceptance
remain pending.
These results establish recorded private-session behavior. Audible output,
physical input/Braille, normal-profile workbook return, tab rename/add/remove
event delivery, merged/structurally edited headings, large-sheet responsiveness
and independent real-workbook acceptance still need their own checks. Earlier
browser checks recorded an editing-title failure and one non-reproducible mode
failure; this pass does not establish current live browser acceptance.
## Calc startup focus diagnosis
@@ -323,9 +318,11 @@ LibreOffice documents this shortcut in its
Automatic focus stealing would interfere with intentional toolbar use and
is not part of the reader's handling.
The native Calc test focuses its window once and uses ordinary key sequences
afterward. It also checks F6 followed by Ctrl+F6 and resumed cell speech/Braille.
Its fresh-profile virtual display does not cover this normal-profile startup
The native Calc test activates its initial window, establishes document focus
with F6 followed by Ctrl+F6, and uses ordinary key sequences within each document.
Explicit window-manager activation switches workbooks and focuses the dialog.
It also checks later F6/Ctrl+F6 recovery and resumed cell speech/Braille.
Its fresh-profile private i3 display does not cover this normal-profile startup
failure. The same production test also passed under private i3 with the copied
normal profile after Ctrl+F6 recovery, asserting recorded cell speech and
Braille along with editing and sheet switching. Verify startup and recovery
+63 -9
View File
@@ -130,12 +130,16 @@ func TestNativeLibreOfficeCalc(t *testing.T) {
}
}
}
// Focus once. Refocusing before every key sequence can hide failures
// to retain or recover Calc's document focus during normal keyboard use.
if err := exec.CommandContext(ctx, "xdotool", "windowfocus", window).Run(); err != nil {
activate := func(window string) {
t.Helper()
if err := exec.CommandContext(ctx, "xdotool", "windowactivate", "--sync", window).Run(); err != nil {
t.Fatal(err)
}
press("Escape", "ctrl+Home", "Right")
}
// Focus once. Refocusing before every key sequence can hide failures
// to retain or recover Calc's document focus during normal keyboard use.
activate(window)
press("Escape", "F6", "ctrl+F6", "ctrl+Home", "Right")
waitSpeech("42, B1")
waitFrame("42 B1")
press("Down")
@@ -277,7 +281,9 @@ func TestNativeLibreOfficeCalc(t *testing.T) {
press("ctrl+Page_Up", "ctrl+Home", "Right", "Down")
waitSpeech("y row header, Beta, B2")
// A heading edit is visible on the next cell snapshot, without a cache.
press("Up", "8", "Return")
press("Up")
waitSpeech("Alpha row header, 42, B1")
press("8", "Return")
waitSpeech("y row header, Beta, B2")
waitFrame("y 8 Beta B2")
commands <- input.WhereAmI
@@ -320,10 +326,7 @@ func TestNativeLibreOfficeCalc(t *testing.T) {
if secondWindow == "" {
t.Fatal("second private workbook window missing")
}
// A virtual display without a window manager does not focus new windows.
if err := exec.CommandContext(ctx, "xdotool", "windowfocus", secondWindow).Run(); err != nil {
t.Fatal(err)
}
activate(secondWindow)
press("ctrl+F6", "ctrl+Page_Down", "ctrl+Home", "Down")
waitSpeech("blank, A2")
commands <- input.WhereAmI
@@ -338,4 +341,55 @@ func TestNativeLibreOfficeCalc(t *testing.T) {
waitSpeech("blank, A2")
commands <- input.WhereAmI
waitSpeech("d column header, blank, A2")
// Return to the first workbook, then back again: identical sheet names
// must retain independent choices and fresh cells in both directions.
// Use normal navigation here, without the Ctrl+F6 recovery shortcut.
activate(window)
press("ctrl+Home", "Down")
waitSpeech("blank, A2")
commands <- input.WhereAmI
waitSpeech("Gamma column header, blank, A2")
waitFrame("Gamma A2")
activate(secondWindow)
press("ctrl+Home", "Down")
waitSpeech("blank, A2")
commands <- input.WhereAmI
waitSpeech("d column header, blank, A2")
waitFrame("d A2")
// Dialog activation still resolves its focused control. Cancelling it
// must leave the document navigable with the same header choices.
press("ctrl+h")
dialogWindow := ""
deadline = time.Now().Add(5 * time.Second)
for dialogWindow == "" && time.Now().Before(deadline) {
output, _ := exec.CommandContext(ctx, "xdotool", "search", "--onlyvisible", "--name", "^Find and Replace$").Output()
if candidates := strings.Fields(string(output)); len(candidates) == 1 {
dialogWindow = candidates[0]
} else {
time.Sleep(20 * time.Millisecond)
}
}
if dialogWindow == "" {
t.Fatal("private Find and Replace dialog window missing")
}
activate(dialogWindow)
press("x")
waitSpeech("x")
press("Escape")
deadline = time.Now().Add(5 * time.Second)
for {
output, _ := exec.CommandContext(ctx, "xdotool", "search", "--onlyvisible", "--name", "^Find and Replace$").Output()
if len(strings.Fields(string(output))) == 0 {
break
}
if time.Now().After(deadline) {
t.Fatal("private Find and Replace dialog did not close")
}
time.Sleep(20 * time.Millisecond)
}
activate(secondWindow)
press("ctrl+F6", "ctrl+Home", "Down")
waitSpeech("blank, A2")
commands <- input.WhereAmI
waitSpeech("d column header, blank, A2")
}
+14 -4
View File
@@ -174,12 +174,18 @@ func TestRunReachesSoundStopAfterEarlierServiceStopError(t *testing.T) {
}
sounds := &recordingSound{started: make(chan struct{})}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
completed := make(chan error, 1)
// Sound starts first; cancellation there races later service startup.
// The startup callback runs only once the complete runtime is ready.
runtimeStarted := make(chan struct{})
go func() {
completed <- Run(ctx, Options{
Logger: slog.New(slog.DiscardHandler),
Settings: &settings,
OpenPreferences: true,
onPreferences: func() { close(runtimeStarted) },
newSound: func() soundService { return sounds },
newCommands: func() commandListener {
return silentCommands{}
@@ -190,9 +196,9 @@ func TestRunReachesSoundStopAfterEarlierServiceStopError(t *testing.T) {
}()
select {
case <-sounds.started:
case <-runtimeStarted:
case <-time.After(time.Second):
t.Fatal("sound service did not start")
t.Fatal("runtime did not finish startup")
}
cancel()
select {
@@ -217,12 +223,16 @@ func TestRunReportsSoundStopError(t *testing.T) {
soundError := errors.New("stop cue failed")
sounds := &recordingSound{started: make(chan struct{}), stopError: soundError}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
completed := make(chan error, 1)
runtimeStarted := make(chan struct{})
go func() {
completed <- Run(ctx, Options{
Logger: slog.New(slog.DiscardHandler),
Settings: &settings,
OpenPreferences: true,
onPreferences: func() { close(runtimeStarted) },
newSound: func() soundService { return sounds },
newCommands: func() commandListener {
return silentCommands{}
@@ -235,9 +245,9 @@ func TestRunReportsSoundStopError(t *testing.T) {
}()
select {
case <-sounds.started:
case <-runtimeStarted:
case <-time.After(time.Second):
t.Fatal("sound service did not start")
t.Fatal("runtime did not finish startup")
}
cancel()
select {
+8 -1
View File
@@ -184,7 +184,11 @@ func (adapter *Adapter) recoverForeground() {
continue
}
if state.Epoch == adapter.Foreground().Epoch && adapter.matchesForeground(window, nativeObjectID(window)) {
target := C.cthulhu_focused_descendant(window)
target := adapter.libreOfficeFrameTarget(window)
officeFrame := target != nil
if target == nil {
target = C.cthulhu_focused_descendant(window)
}
if target == nil {
target = (*C.AtspiAccessible)(C.g_object_ref(C.gpointer(window)))
}
@@ -202,6 +206,9 @@ func (adapter *Adapter) recoverForeground() {
target = child
}
snapshot := snapshotFromNativeWithCaret(target, true, false, false, adapter.captureSound.Load(), adapter.captureTextAttributes.Load())
if officeFrame {
snapshot.ApplicationProcess = adapter.applicationProcess(target)
}
event := NewEvent(WindowActivatedEvent, snapshot)
event.Window = nativeObjectID(window)
name := C.atspi_accessible_get_name(window, nil)
+20 -4
View File
@@ -11,15 +11,19 @@ import "C"
import "unsafe"
// libreOfficeFocusTarget resolves a Calc editor's direct text children and
// preserves the sheet source for selection events. F2 focuses its temporary
// panel; the paragraph can appear later, on typing.
// libreOfficeFocusTarget keeps Office frame activation separate from document
// focus, resolves a Calc editor's direct text children, and preserves the sheet
// source for selection events. F2 focuses its temporary panel; the paragraph
// can appear later, on typing.
// The callback owns and releases the returned reference. No sheet is walked.
func (adapter *Adapter) libreOfficeFocusTarget(event *C.AtspiEvent, eventType string) *C.AtspiAccessible {
if eventType != FocusEvent && eventType != FocusedStateEvent && eventType != SelectionChangedEvent ||
if eventType != FocusEvent && eventType != FocusedStateEvent && eventType != SelectionChangedEvent && eventType != WindowActivatedEvent ||
!IsLibreOfficeProcess(adapter.applicationProcess(event.source)) {
return nil
}
if eventType == WindowActivatedEvent {
return adapter.libreOfficeFrameTarget(event.source)
}
role := C.atspi_accessible_get_role(event.source, nil)
if eventType == SelectionChangedEvent {
// Keep the sheet as the selection source. Its first selected cell
@@ -79,6 +83,18 @@ func (adapter *Adapter) libreOfficeFocusTarget(event *C.AtspiEvent, eventType st
return nil
}
// Both real activation events and X11 foreground recovery must avoid searching
// Calc's previous view while it rebuilds controls on workbook return. Own the
// frame and let the following cell/editor events establish document focus.
// Dialogs retain ordinary focused-control resolution. The caller owns the ref.
func (adapter *Adapter) libreOfficeFrameTarget(source *C.AtspiAccessible) *C.AtspiAccessible {
if !IsLibreOfficeProcess(adapter.applicationProcess(source)) ||
C.atspi_accessible_get_role(source, nil) != C.ATSPI_ROLE_FRAME {
return nil
}
return (*C.AtspiAccessible)(C.g_object_ref(C.gpointer(source)))
}
func captureLibreOfficeContext(source *C.AtspiAccessible, snapshot *Snapshot) {
if !IsLibreOfficeProcess(snapshot.ApplicationProcess) || snapshot.Defunct {
return
+3 -1
View File
@@ -11,6 +11,7 @@ import (
"strconv"
"strings"
"sync"
"syscall"
"testing"
"time"
@@ -540,13 +541,14 @@ func TestDisableKillsGroupDescendantsAndJoinsPipes(t *testing.T) {
wait_signal(t, session.Done())
// SIGKILL delivery/reaping is scheduled by the kernel; wait for /proc to
// report disappearance or zombie state, not an arbitrary sleep duration.
// A task that exits during ReadFile can return ESRCH rather than ENOENT.
deadline := time.NewTimer(2 * time.Second)
defer deadline.Stop()
ticker := time.NewTicker(time.Millisecond)
defer ticker.Stop()
for {
data, err := os.ReadFile("/proc/" + strconv.Itoa(pid) + "/stat")
if os.IsNotExist(err) {
if os.IsNotExist(err) || errors.Is(err, syscall.ESRCH) {
break
}
if err != nil {
+1 -1
View File
@@ -54,6 +54,6 @@ web-browse-selection,src/cthulhu/scripts/web/script.py;src/cthulhu/script_utilit
web-browse-braille-line,src/cthulhu/caret_navigation.py;src/cthulhu/scripts/web/script.py;src/cthulhu/scripts/web/braille_generator.py,braille,Follow accepted browse-caret and structural navigation with the current native text line and virtual cursor,,internal/atspi internal/review internal/app,implemented,"go test -race ./internal/app ./internal/review ./internal/atspi ./internal/braille -count=1; CTHULHU_NATIVE_BROWSER_TESTS=modes,tables,keys python3 tests/native_browser.py",Private Brave/Xvfb mode/table/key checks pass on 2026-10-02; physical Xorg pending.,,Existing browse speech assertions pass in the private fixture.,Queued native line and cursor frames pass; physical HumanWare NLS eReader acceptance pending.,Reads run on the bounded navigation worker only while braille is enabled; preserve spaces and Unicode offsets. Table frames retain existing cell presentation. Complete cross-object visual-line assembly and virtual-caret routing remain open. See docs/testing/braille.md.
web-explicit-link-names,src/cthulhu/scripts/web/script_utilities.py:_treatObjectAsWhole,web,Read explicitly named links as whole objects without losing descendant badges or ordinary link navigation,Storm Dragon,internal/atspi internal/review internal/app,in-progress,"go test -race ./...; CTHULHU_NATIVE_BROWSER_TESTS=namedlinks,browser,live,keys python3 tests/native_browser.py",Private Brave/Xorg named-link and key checks passed,,Fixture speech verified; real Steam listening pending,Named-link browse braille uses the full accessible label; physical check pending,docs/testing/steam-browser.md; actual Steam explicit-name exposure and game-card acceptance remain live gates
steam-notifications,src/cthulhu/scripts/apps/steamwebhelper/script.py;tests/test_steam_notification_regressions.py,web,Coalesce verified Steam background toasts and present once through speech braille and notification history,Storm Dragon,internal/webscripts internal/atspi internal/app,in-progress,go test -race ./...; python3 tests/native_webscripts.py,Private GTK/AT-SPI process matching and alert-root capture passed,,Event-loop background delivery and Chromium isolation passed; real Steam toast pending,Event-loop flash verified; physical Steam toast display pending,docs/testing/steam-browser.md; independent root and bus queues deliberately prevent unrelated toast timestamps from merging
libreoffice-calc-basic,Orca src/orca/scripts/apps/soffice/script.py; Orca src/orca/ax_utilities_table.py; Orca src/orca/speech_generator.py,libreoffice,Present Calc cells and recover logical focus around editing and sheet changes,Storm Dragon,internal/app internal/atspi internal/presentation,in-progress,GOCACHE=/tmp/cthulhu-go-cache go test -race ./internal/atspi ./internal/app ./internal/presentation -count=1; /usr/bin/python3 tests/native_libreoffice.py,Private real LibreOffice Calc 26.2.6.3 on Xvfb and a private AT-SPI bus validates cell movement blanks F2 typing Escape Enter and sheet changes.,,Recorded speech assertions pass; audible and physical-input acceptance pending.,Recorded value and coordinate frames pass; physical Braille and editor routing acceptance pending.,Current Orca is the primary Office reference. Dedicated application policy follows verified process identity after foreground/security gates; native capture remains bounded. Formula presence and explicit formula/basic Where Am I speech are implemented with bounded uncached cell attributes and recorded real-Calc checks; physical acceptance remains pending. Bounded selection deltas for small ranges and row/column selections plus count summaries for large selections and Select All are implemented. Real Calc checks cover disjoint cells and huge selections; physical speech/input/Braille acceptance remains pending. Dynamic row and column headers now use session choices scoped by provider bus document view window and exact sheet name; native reads are bounded to two cells. Four assignable commands preserve existing shortcuts. Real Calc checks cover heading edits independent axis clearing and sheet round trips; physical speech/input/Braille acceptance remains pending. Full-row reading Writer workflows and full topology reporting for large selections remain open. See LIBREOFFICE_SUPPORT.md.
libreoffice-calc-basic,Orca src/orca/scripts/apps/soffice/script.py; Orca src/orca/ax_utilities_table.py; Orca src/orca/speech_generator.py,libreoffice,Present Calc cells and recover logical focus around editing and sheet changes,Storm Dragon,internal/app internal/atspi internal/presentation,in-progress,GOCACHE=/tmp/cthulhu-go-cache go test -race ./internal/atspi ./internal/app ./internal/presentation -count=1; /usr/bin/python3 tests/native_libreoffice.py,Private real LibreOffice Calc 26.2.6.3 on Xvfb and a private AT-SPI bus validates cell movement blanks F2 typing Escape Enter and sheet changes.,,Recorded speech assertions pass; audible and physical-input acceptance pending.,Recorded value and coordinate frames pass; physical Braille and editor routing acceptance pending.,Current Orca is the primary Office reference. Dedicated application policy follows verified process identity after foreground/security gates; native capture remains bounded. Formula presence and explicit formula/basic Where Am I speech are implemented with bounded uncached cell attributes and recorded real-Calc checks; physical acceptance remains pending. Bounded selection deltas for small ranges and row/column selections plus count summaries for large selections and Select All are implemented. Real Calc checks cover disjoint cells and huge selections; physical speech/input/Braille acceptance remains pending. Dynamic row and column headers now use session choices scoped by provider bus document view window and exact sheet name; native reads are bounded to two cells. Four assignable commands preserve existing shortcuts. Private i3 Calc checks cover heading edits independent axis clearing sheet round trips both workbook-return directions with distinct headings and Find and Replace typing/cancellation. Frame activation and X11 foreground recovery avoid stale descendant searches; physical speech/input/Braille acceptance remains pending. Full-row reading Writer workflows and full topology reporting for large selections remain open. See LIBREOFFICE_SUPPORT.md.
steam-shader-progress,Steam shader dialog AT-SPI events,web,Report Steam Vulkan shader percentages through shared progress output,,internal/webscripts internal/app,in-progress,go test ./internal/app ./internal/webscripts ./internal/presentation ./internal/sound -count=1; python3 tests/native_progress.py; CTHULHU_NATIVE_BROWSER_TESTS=progress python3 tests/native_browser.py,Private GTK and Brave HTML/ARIA progress checks passed.,,Tone requests verified; live Steam listening pending.,Unrelated Braille ownership covered by unit tests; physical check pending.,English static shader-status name changes only; verified steamwebhelper identity; see PROGRESS_BARS.md.
wayland-shared-keyboard-access,src/cthulhu/input_event_manager.py,input,Monitor keys and grab reader shortcuts through the shared accessibility keyboard interface,Storm Dragon,internal/platform/wayland internal/app internal/sessionbus,in-progress,Private dbus-run-session race tests cover wire protocol runtime dispatch configuration rollback secure transitions and cleanup; go test ./... -count=1; python3 tests/check_speech.py,Existing native_x11.py keyboard harness passed; browser tabs and editing passed; browser modes passed on isolated rerun after one failure whose cause was not established.,Shared D-Bus fixture passed without an X display. Live niri and physical key suppression remain unverified.,Pending live listening on Wayland,Pending physical Braille on Wayland,No compositor-specific code. See WAYLAND_SUPPORT.md for supported commands limitations and live acceptance. X11 production listeners are unchanged; the suspension probe now links its existing xkbcommon dependency.
1 id python_source subsystem behavior owner go_destination status automated_evidence x11_evidence wayland_evidence speech_evidence braille_evidence notes
54 web-browse-braille-line src/cthulhu/caret_navigation.py;src/cthulhu/scripts/web/script.py;src/cthulhu/scripts/web/braille_generator.py braille Follow accepted browse-caret and structural navigation with the current native text line and virtual cursor internal/atspi internal/review internal/app implemented go test -race ./internal/app ./internal/review ./internal/atspi ./internal/braille -count=1; CTHULHU_NATIVE_BROWSER_TESTS=modes,tables,keys python3 tests/native_browser.py Private Brave/Xvfb mode/table/key checks pass on 2026-10-02; physical Xorg pending. Existing browse speech assertions pass in the private fixture. Queued native line and cursor frames pass; physical HumanWare NLS eReader acceptance pending. Reads run on the bounded navigation worker only while braille is enabled; preserve spaces and Unicode offsets. Table frames retain existing cell presentation. Complete cross-object visual-line assembly and virtual-caret routing remain open. See docs/testing/braille.md.
55 web-explicit-link-names src/cthulhu/scripts/web/script_utilities.py:_treatObjectAsWhole web Read explicitly named links as whole objects without losing descendant badges or ordinary link navigation Storm Dragon internal/atspi internal/review internal/app in-progress go test -race ./...; CTHULHU_NATIVE_BROWSER_TESTS=namedlinks,browser,live,keys python3 tests/native_browser.py Private Brave/Xorg named-link and key checks passed Fixture speech verified; real Steam listening pending Named-link browse braille uses the full accessible label; physical check pending docs/testing/steam-browser.md; actual Steam explicit-name exposure and game-card acceptance remain live gates
56 steam-notifications src/cthulhu/scripts/apps/steamwebhelper/script.py;tests/test_steam_notification_regressions.py web Coalesce verified Steam background toasts and present once through speech braille and notification history Storm Dragon internal/webscripts internal/atspi internal/app in-progress go test -race ./...; python3 tests/native_webscripts.py Private GTK/AT-SPI process matching and alert-root capture passed Event-loop background delivery and Chromium isolation passed; real Steam toast pending Event-loop flash verified; physical Steam toast display pending docs/testing/steam-browser.md; independent root and bus queues deliberately prevent unrelated toast timestamps from merging
57 libreoffice-calc-basic Orca src/orca/scripts/apps/soffice/script.py; Orca src/orca/ax_utilities_table.py; Orca src/orca/speech_generator.py libreoffice Present Calc cells and recover logical focus around editing and sheet changes Storm Dragon internal/app internal/atspi internal/presentation in-progress GOCACHE=/tmp/cthulhu-go-cache go test -race ./internal/atspi ./internal/app ./internal/presentation -count=1; /usr/bin/python3 tests/native_libreoffice.py Private real LibreOffice Calc 26.2.6.3 on Xvfb and a private AT-SPI bus validates cell movement blanks F2 typing Escape Enter and sheet changes. Recorded speech assertions pass; audible and physical-input acceptance pending. Recorded value and coordinate frames pass; physical Braille and editor routing acceptance pending. Current Orca is the primary Office reference. Dedicated application policy follows verified process identity after foreground/security gates; native capture remains bounded. Formula presence and explicit formula/basic Where Am I speech are implemented with bounded uncached cell attributes and recorded real-Calc checks; physical acceptance remains pending. Bounded selection deltas for small ranges and row/column selections plus count summaries for large selections and Select All are implemented. Real Calc checks cover disjoint cells and huge selections; physical speech/input/Braille acceptance remains pending. Dynamic row and column headers now use session choices scoped by provider bus document view window and exact sheet name; native reads are bounded to two cells. Four assignable commands preserve existing shortcuts. Real Calc checks cover heading edits independent axis clearing and sheet round trips; physical speech/input/Braille acceptance remains pending. Full-row reading Writer workflows and full topology reporting for large selections remain open. See LIBREOFFICE_SUPPORT.md. Current Orca is the primary Office reference. Dedicated application policy follows verified process identity after foreground/security gates; native capture remains bounded. Formula presence and explicit formula/basic Where Am I speech are implemented with bounded uncached cell attributes and recorded real-Calc checks; physical acceptance remains pending. Bounded selection deltas for small ranges and row/column selections plus count summaries for large selections and Select All are implemented. Real Calc checks cover disjoint cells and huge selections; physical speech/input/Braille acceptance remains pending. Dynamic row and column headers now use session choices scoped by provider bus document view window and exact sheet name; native reads are bounded to two cells. Four assignable commands preserve existing shortcuts. Private i3 Calc checks cover heading edits independent axis clearing sheet round trips both workbook-return directions with distinct headings and Find and Replace typing/cancellation. Frame activation and X11 foreground recovery avoid stale descendant searches; physical speech/input/Braille acceptance remains pending. Full-row reading Writer workflows and full topology reporting for large selections remain open. See LIBREOFFICE_SUPPORT.md.
58 steam-shader-progress Steam shader dialog AT-SPI events web Report Steam Vulkan shader percentages through shared progress output internal/webscripts internal/app in-progress go test ./internal/app ./internal/webscripts ./internal/presentation ./internal/sound -count=1; python3 tests/native_progress.py; CTHULHU_NATIVE_BROWSER_TESTS=progress python3 tests/native_browser.py Private GTK and Brave HTML/ARIA progress checks passed. Tone requests verified; live Steam listening pending. Unrelated Braille ownership covered by unit tests; physical check pending. English static shader-status name changes only; verified steamwebhelper identity; see PROGRESS_BARS.md.
59 wayland-shared-keyboard-access src/cthulhu/input_event_manager.py input Monitor keys and grab reader shortcuts through the shared accessibility keyboard interface Storm Dragon internal/platform/wayland internal/app internal/sessionbus in-progress Private dbus-run-session race tests cover wire protocol runtime dispatch configuration rollback secure transitions and cleanup; go test ./... -count=1; python3 tests/check_speech.py Existing native_x11.py keyboard harness passed; browser tabs and editing passed; browser modes passed on isolated rerun after one failure whose cause was not established. Shared D-Bus fixture passed without an X display. Live niri and physical key suppression remain unverified. Pending live listening on Wayland Pending physical Braille on Wayland No compositor-specific code. See WAYLAND_SUPPORT.md for supported commands limitations and live acceptance. X11 production listeners are unchanged; the suspension probe now links its existing xkbcommon dependency.
+24 -2
View File
@@ -2,6 +2,7 @@
"""Real Calc through the production reader, in a private X11/AT-SPI session."""
import os
from contextlib import ExitStack
from pathlib import Path
import shutil
import signal
@@ -26,8 +27,29 @@ def run_inside():
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
with tempfile.TemporaryDirectory(prefix="cthulhu-libreoffice-") as temporary:
with tempfile.TemporaryDirectory(prefix="cthulhu-libreoffice-") as temporary, ExitStack() as cleanup:
root = Path(temporary)
# Workbook and modal-dialog activation need a window manager's focus
# protocol, rather than bare XSetInputFocus on a virtual display.
wmConfig = root / "i3.config"
wmConfig.write_text(
'font pango:monospace 10\nfocus_follows_mouse no\n'
f'ipc-socket {root / "i3.sock"}\n', encoding="utf-8",
)
windowManager = subprocess.Popen(
["i3", "-a", "-c", str(wmConfig)],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
)
def stop_window_manager():
if windowManager.poll() is None:
windowManager.terminate()
windowManager.wait(timeout=5)
cleanup.callback(stop_window_manager)
wait_for(lambda: "0x" in subprocess.check_output(
["xprop", "-root", "_NET_SUPPORTING_WM_CHECK"], text=True),
"Private i3 window manager missing")
profile = root / "profile" / "user"
profile.mkdir(parents=True)
(profile / "registrymodifications.xcu").write_text(
@@ -142,7 +164,7 @@ def main():
environment = dict(os.environ, XDG_SESSION_TYPE="x11",
XDG_CONFIG_HOME=temporary, XDG_CACHE_HOME=temporary,
XDG_DATA_HOME=temporary)
for name in ("DBUS_SESSION_BUS_ADDRESS", "AT_SPI_BUS_ADDRESS", "WAYLAND_DISPLAY"):
for name in ("DBUS_SESSION_BUS_ADDRESS", "AT_SPI_BUS_ADDRESS", "WAYLAND_DISPLAY", "I3SOCK"):
environment.pop(name, None)
subprocess.run(
["xvfb-run", "-a", "dbus-run-session", "--", sys.executable,