Fix document retention and helper retry regressions

Keep failed cursor trials and native recapture anchored to the original document, and restore the requested cached root before LRU eviction. Base braille retry resets on established connection time rather than stalled startup. Poll private AT-SPI daemon ownership without triggering service activation and clean up partial startup failures. Add focused regressions and update browser testing notes.
This commit is contained in:
Storm Dragon committed 2026-11-03 11:37:36 -05:00
1 parent a4d427099e
commit 4da61465b0
11 files changed
+282 -132

No files matched your search

+6 -46
View File
@@ -21,52 +21,12 @@ func (adapter *Adapter) captureDesktop(ctx context.Context, reviewFocus ObjectID
trace := capture_diagnostics(ctx)
trace.begin_stage("root-selection", reviewFocus, "")
root, err := adapter.nativeDocumentRoot(ctx, reviewFocus)
adapter.treeMutex.Lock()
retainedRoots := make(map[ObjectID]bool, 1+len(adapter.stashedDocumentIDs))
if adapter.documentSlotRoot.Valid() && adapter.documentTree != nil {
retainedRoots[adapter.documentSlotRoot] = true
}
for _, id := range adapter.stashedDocumentIDs {
retainedRoots[id] = true
}
adapter.treeMutex.Unlock()
if (errors.Is(err, ErrObjectNotFound) || errors.Is(err, ErrStaleObject)) && len(retainedRoots) != 0 && len(adapter.nativeFocus) != 0 {
// Dynamic pages can remove the browse cursor without sending a new
// focus event. Recover only from the newest retained native focus in
// the same document. A chrome or other-tab focus is not a fallback.
for i := len(adapter.nativeFocus) - 1; i >= 0; i-- {
latest := adapter.nativeFocus[i]
if latest.id.BusName != reviewFocus.BusName {
break
}
C.atspi_accessible_clear_cache_single(latest.source)
states := C.atspi_accessible_get_state_set(latest.source)
if states == nil {
continue
}
dead := C.atspi_state_set_contains(states, C.ATSPI_STATE_DEFUNCT) != 0
C.g_object_unref(C.gpointer(states))
if dead {
continue
}
// A removed browse target can retain a non-defunct proxy after
// Chromium has dropped its accessible object. Its role is then
// invalid; try the preceding real focus instead.
if C.atspi_accessible_get_role(latest.source, nil) == C.ATSPI_ROLE_INVALID {
continue
}
candidate, candidateErr := adapter.nativeDocumentRoot(ctx, latest.id)
if candidateErr != nil {
continue
}
if retainedRoots[nativeObjectID(candidate)] {
root, err = candidate, nil
break
}
// The newest live focus can sit in browser chrome or a tab
// whose document was never retained; older focus history in
// the retained document may still resolve.
C.g_object_unref(C.gpointer(candidate))
if errors.Is(err, ErrObjectNotFound) || errors.Is(err, ErrStaleObject) {
// A removed focus may still belong to a retained capture. Recover
// through that document's root, never through another tab's focus
// history merely because it shares the application's bus.
if owner := adapter.retainedDocumentRoot(reviewFocus); owner.Valid() && owner != reviewFocus {
root, err = adapter.nativeDocumentRoot(ctx, owner)
}
}
if err != nil {