104 lines
3.5 KiB
Go
104 lines
3.5 KiB
Go
// 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"
|
|
|
|
import "strings"
|
|
|
|
// Sheet names are unique within a Calc document. Conservatively retire choices
|
|
// for this window when sheet tabs are added, removed or renamed, so a
|
|
// deleted/recreated name cannot inherit an old sheet's choice. Switching tabs
|
|
// only changes selected state and does not retire choices.
|
|
func (adapter *Adapter) retireLibreOfficeHeaders(source *C.AtspiAccessible, eventType string, origin ObjectID) {
|
|
if eventType == WindowDestroyedEvent || eventType == DefunctStateEvent {
|
|
adapter.libreOfficeHeaders.forget(origin)
|
|
}
|
|
if (eventType != AccessibleNameEvent && !strings.HasPrefix(eventType, ChildrenChangedEvent)) ||
|
|
!adapter.libreOfficeHeaders.hasBus(origin.BusName) {
|
|
return
|
|
}
|
|
role := C.atspi_accessible_get_role(source, nil)
|
|
if eventType == AccessibleNameEvent && role == C.ATSPI_ROLE_PAGE_TAB ||
|
|
strings.HasPrefix(eventType, ChildrenChangedEvent) && role == C.ATSPI_ROLE_PAGE_TAB_LIST {
|
|
window := C.cthulhu_window_ancestor(source)
|
|
if window != nil {
|
|
adapter.libreOfficeHeaders.forget(nativeObjectID(window))
|
|
C.g_object_unref(C.gpointer(window))
|
|
}
|
|
}
|
|
}
|
|
|
|
// GLib owner only: at most two direct cell lookups, with no sheet enumeration
|
|
// or retained native references. Read fresh text on each accepted snapshot so
|
|
// edits to a heading are reflected when the user next visits a data cell.
|
|
func (adapter *Adapter) captureLibreOfficeHeaders(source *C.AtspiAccessible, snapshot *Snapshot, window ObjectID) {
|
|
key, valid := libreOfficeHeaderIdentity(*snapshot, window)
|
|
if !valid {
|
|
return
|
|
}
|
|
choice := adapter.libreOfficeHeaders.get(key)
|
|
if !choice.rowSet && !choice.columnSet {
|
|
return
|
|
}
|
|
cell := C.atspi_accessible_get_table_cell(source)
|
|
if cell == nil {
|
|
return
|
|
}
|
|
defer C.g_object_unref(C.gpointer(cell))
|
|
accessible := C.atspi_table_cell_get_table(cell, nil)
|
|
if accessible == nil {
|
|
return
|
|
}
|
|
defer C.g_object_unref(C.gpointer(accessible))
|
|
if nativeObjectID(accessible) != NewObjectID(snapshot.BusName, snapshot.TablePath) {
|
|
return
|
|
}
|
|
table := C.atspi_accessible_get_table_iface(accessible)
|
|
if table == nil {
|
|
return
|
|
}
|
|
defer C.g_object_unref(C.gpointer(table))
|
|
if choice.columnSet && choice.column != snapshot.TableColumnIndex {
|
|
snapshot.TableRowHeaders = libreOfficeHeaderText(table, snapshot.TableRowIndex, choice.column)
|
|
}
|
|
if choice.rowSet && choice.row != snapshot.TableRowIndex {
|
|
snapshot.TableColumnHeaders = libreOfficeHeaderText(table, choice.row, snapshot.TableColumnIndex)
|
|
}
|
|
}
|
|
|
|
func libreOfficeHeaderText(table *C.AtspiTable, row, column int) string {
|
|
cell := C.atspi_table_get_accessible_at(table, C.gint(row), C.gint(column), nil)
|
|
if cell == nil {
|
|
return ""
|
|
}
|
|
defer C.g_object_unref(C.gpointer(cell))
|
|
if C.atspi_accessible_get_role(cell, nil) != C.ATSPI_ROLE_TABLE_CELL {
|
|
return ""
|
|
}
|
|
C.atspi_accessible_clear_cache_single(cell)
|
|
states := C.atspi_accessible_get_state_set(cell)
|
|
if states == nil {
|
|
return ""
|
|
}
|
|
defunct := C.atspi_state_set_contains(states, C.ATSPI_STATE_DEFUNCT) != 0
|
|
C.g_object_unref(C.gpointer(states))
|
|
if defunct {
|
|
return ""
|
|
}
|
|
text := C.atspi_accessible_get_text_iface(cell)
|
|
if text == nil {
|
|
return ""
|
|
}
|
|
defer C.g_object_unref(C.gpointer(text))
|
|
length := max(0, min(int(C.atspi_text_get_character_count(text, nil)), maxSnapshotFieldLength))
|
|
content := C.atspi_text_get_text(text, 0, C.gint(length), nil)
|
|
defer C.g_free(C.gpointer(content))
|
|
return sanitizeSnapshotField(C.GoString(content))
|
|
}
|