Code review and cleanup.

This commit is contained in:
ak47 committed 2026-11-01 22:01:32 -05:00
1 parent bbe931335f
commit 92d6ad3cc4
23 files changed
+1497 -886

No files matched your search

@@ -507,69 +507,13 @@ func cthulhuAtspiEventCallback(event *C.AtspiEvent, userData unsafe.Pointer) {
return
}
snapshotStarted := time.Now()
target := returnedMenuItem
ownedTarget := false
if target == nil {
target = adapter.libreOfficeFocusTarget(event, eventType)
ownedTarget = target != nil
}
if target == nil {
target, ownedTarget = selectNativeEventTarget(event, eventType)
}
target, ownedTarget := adapter.resolveNativeEventTarget(event, eventType, returnedMenuItem)
if target == nil {
return
}
if (eventType == FocusEvent || eventType == FocusedStateEvent) &&
C.atspi_accessible_get_role(target, nil) == C.ATSPI_ROLE_MENU_ITEM {
// Qt menus can change their checked state without a state-change
// event. Reopening the menu must capture the current provider state.
C.atspi_accessible_clear_cache_single(target)
}
if (eventType == SelectedStateEvent || eventType == SelectionChangedEvent) &&
C.atspi_accessible_get_role(target, nil) == C.ATSPI_ROLE_PAGE_TAB {
// Firefox can emit selected-state events from the previous tab;
// query the current state/name before using either event path.
C.atspi_accessible_clear_cache_single(target)
}
if eventType == WindowDeactivatedEvent {
// Match Python's key-grab churn check against fresh window state rather
// than an AT-SPI cache entry from before the deactivation event.
C.atspi_accessible_clear_cache_single(event.source)
}
payload := C.cthulhu_event_payload(event)
snapshot, popupFor := adapter.captureNativeEventSnapshot(event, target, eventType, originID, live)
if completeLive {
text := C.cthulhu_live_content(event.source)
snapshot.Text = sanitizeSnapshotField(C.GoString(text))
snapshot.LiveAtomic = true
C.g_free(C.gpointer(payload))
payload = text
}
// Shared Qt actions can report focus through their original, hidden menu
// even while another menu emits focus-gained for that very accessible.
// The explicit event establishes focus; the queried state may disagree.
// Do not transfer this evidence to a redirected descendant or a dead item.
if snapshot.ID() == originID && !snapshot.Defunct &&
(eventType == FocusEvent || eventType == FocusedStateEvent && C.cthulhu_event_detail1(event) == 1) {
switch snapshot.Role {
case "menu item", "check menu item", "radio menu item":
snapshot.Focused = true
}
}
var inlineMenuID ObjectID
if eventType == SelectedStateEvent && C.cthulhu_event_detail1(event) == 1 && !snapshot.Defunct &&
(snapshot.Role == "button" || snapshot.Role == "push button" || snapshot.Role == "toggle button" ||
snapshot.Role == "menu item" || snapshot.Role == "check menu item" || snapshot.Role == "radio menu item") {
if menu := C.cthulhu_inline_menu_container(target); menu != nil {
inlineMenuID = nativeObjectID(menu)
C.g_object_unref(C.gpointer(menu))
if inlineMenuID.Valid() && inlineMenuID.BusName == snapshot.BusName {
// The event's detail is authoritative even when libatspi still
// caches the previous SELECTED state on the first visit.
eventType, snapshot.Selected = ActiveDescendantEvent, true
}
}
}
refreshNativeEventTarget(event, target, eventType)
snapshot, popupFor, payload := adapter.captureNativeEventContent(event, target, eventType, originID, live, completeLive)
eventType, inlineMenuID := normalizeNativeMenuFocus(event, target, eventType, originID, &snapshot)
// Chromium can drop ACTIVE from its visible main frame while a tiny
// same-process sibling claims it. On X11, the correlated foreground
// window is the stronger ownership check performed below. Keep the
@@ -579,7 +523,6 @@ func cthulhuAtspiEventCallback(event *C.AtspiEvent, userData unsafe.Pointer) {
if webNotification == nil && !progressUpdate && !adapter.Foreground().Client.Known && eventType != WindowCreateEvent && eventType != WindowActivatedEvent &&
eventType != WindowDeactivatedEvent && eventType != WindowDestroyedEvent && eventType != AnnouncementEvent && !snapshot.AutocompletePopup &&
C.cthulhu_in_inactive_window(event.source) != 0 {
C.g_free(C.gpointer(payload))
if ownedTarget {
C.g_object_unref(C.gpointer(target))
}
@@ -593,7 +536,7 @@ func cthulhuAtspiEventCallback(event *C.AtspiEvent, userData unsafe.Pointer) {
focusEvent := NewEventWithPayload(
eventType,
snapshot,
C.GoString(payload),
payload,
)
if eventType != nativeEventType {
focusEvent.NativeType = nativeEventType
@@ -636,7 +579,6 @@ func cthulhuAtspiEventCallback(event *C.AtspiEvent, userData unsafe.Pointer) {
if eventType == ActiveDescendantEvent && inlineMenuID.Valid() {
focusEvent.OriginPath = inlineMenuID.Path
}
C.g_free(C.gpointer(payload))
if ownedTarget {
C.g_object_unref(C.gpointer(target))
}
@@ -0,0 +1,96 @@
// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
package atspi
/*
#include "adapter_native.h"
*/
import "C"
// resolveNativeEventTarget runs on the GLib owner. The returned menu item is
// borrowed from the callback; LibreOffice and selected descendants can return
// owned references. The caller releases an owned target after event capture.
func (adapter *Adapter) resolveNativeEventTarget(event *C.AtspiEvent, eventType string, returnedMenuItem *C.AtspiAccessible) (*C.AtspiAccessible, bool) {
target := returnedMenuItem
ownedTarget := false
if target == nil {
target = adapter.libreOfficeFocusTarget(event, eventType)
ownedTarget = target != nil
}
if target == nil {
target, ownedTarget = selectNativeEventTarget(event, eventType)
}
return target, ownedTarget
}
// Refresh only the established provider caches, in query order, before capture.
// Both accessibles are borrowed and stay on the GLib owner thread.
func refreshNativeEventTarget(event *C.AtspiEvent, target *C.AtspiAccessible, eventType string) {
if (eventType == FocusEvent || eventType == FocusedStateEvent) &&
C.atspi_accessible_get_role(target, nil) == C.ATSPI_ROLE_MENU_ITEM {
// Qt menus can change their checked state without a state-change
// event. Reopening the menu must capture the current provider state.
C.atspi_accessible_clear_cache_single(target)
}
if (eventType == SelectedStateEvent || eventType == SelectionChangedEvent) &&
C.atspi_accessible_get_role(target, nil) == C.ATSPI_ROLE_PAGE_TAB {
// Firefox can emit selected-state events from the previous tab;
// query the current state/name before using either event path.
C.atspi_accessible_clear_cache_single(target)
}
if eventType == WindowDeactivatedEvent {
// Match Python's key-grab churn check against fresh window state rather
// than an AT-SPI cache entry from before the deactivation event.
C.atspi_accessible_clear_cache_single(event.source)
}
}
// captureNativeEventContent borrows event/target and owns all payload buffers.
// A completed atomic live region replaces the event payload before copying it.
// No native references escape this helper; all calls remain on the GLib owner.
func (adapter *Adapter) captureNativeEventContent(event *C.AtspiEvent, target *C.AtspiAccessible, eventType string, originID ObjectID, live nativeLiveProperties, completeLive bool) (Snapshot, ObjectID, string) {
payload := C.cthulhu_event_payload(event)
defer func() { C.g_free(C.gpointer(payload)) }()
snapshot, popupFor := adapter.captureNativeEventSnapshot(event, target, eventType, originID, live)
if completeLive {
text := C.cthulhu_live_content(event.source)
snapshot.Text = sanitizeSnapshotField(C.GoString(text))
snapshot.LiveAtomic = true
C.g_free(C.gpointer(payload))
payload = text
}
return snapshot, popupFor, C.GoString(payload)
}
// normalizeNativeMenuFocus applies provider evidence to this event's snapshot.
// It borrows target and releases the temporary inline-menu reference locally.
func normalizeNativeMenuFocus(event *C.AtspiEvent, target *C.AtspiAccessible, eventType string, originID ObjectID, snapshot *Snapshot) (string, ObjectID) {
// Shared Qt actions can report focus through their original, hidden menu
// even while another menu emits focus-gained for that very accessible.
// The explicit event establishes focus; the queried state may disagree.
// Do not transfer this evidence to a redirected descendant or a dead item.
if snapshot.ID() == originID && !snapshot.Defunct &&
(eventType == FocusEvent || eventType == FocusedStateEvent && C.cthulhu_event_detail1(event) == 1) {
switch snapshot.Role {
case "menu item", "check menu item", "radio menu item":
snapshot.Focused = true
}
}
var inlineMenuID ObjectID
if eventType == SelectedStateEvent && C.cthulhu_event_detail1(event) == 1 && !snapshot.Defunct &&
(snapshot.Role == "button" || snapshot.Role == "push button" || snapshot.Role == "toggle button" ||
snapshot.Role == "menu item" || snapshot.Role == "check menu item" || snapshot.Role == "radio menu item") {
if menu := C.cthulhu_inline_menu_container(target); menu != nil {
inlineMenuID = nativeObjectID(menu)
C.g_object_unref(C.gpointer(menu))
if inlineMenuID.Valid() && inlineMenuID.BusName == snapshot.BusName {
// The event's detail is authoritative even when libatspi still
// caches the previous SELECTED state on the first visit.
eventType, snapshot.Selected = ActiveDescendantEvent, true
}
}
}
return eventType, inlineMenuID
}