// 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 ( "time" "git.stormux.org/storm/cthulhu/internal/messaging" ) // Only Mumble's named, read-only Activity log supplies message history. The // bounded walk copies its owning window; no native handles survive the callback. func (adapter *Adapter) mumbleMessage(event *C.AtspiEvent) *messaging.Message { if canonicalObjectChangeEventType(C.GoString(event._type)) != TextInsertedEvent || adapter.applicationProcess(event.source) != "mumble" { return nil } role := C.atspi_accessible_get_role(event.source, nil) if role != C.ATSPI_ROLE_TEXT && role != C.ATSPI_ROLE_LABEL { return nil } name := C.atspi_accessible_get_name(event.source, nil) activityLog := C.GoString(name) == "Activity log" C.g_free(C.gpointer(name)) if !activityLog { return nil } states := C.atspi_accessible_get_state_set(event.source) if states == nil { return nil } valid := C.atspi_state_set_contains(states, C.ATSPI_STATE_EDITABLE) == 0 && C.atspi_state_set_contains(states, C.ATSPI_STATE_DEFUNCT) == 0 C.g_object_unref(C.gpointer(states)) if !valid { return nil } id := nativeObjectID(event.source) message := &messaging.Message{Provider: id.BusName, Conversation: id.Path, RoomName: "Mumble"} current := C.atspi_accessible_get_parent(event.source, nil) deadline := time.Now().Add(50 * time.Millisecond) for depth := 0; current != nil && depth < 32 && time.Now().Before(deadline); depth++ { if isWindowRole(C.atspi_accessible_get_role(current, nil)) { window := nativeObjectID(current) if window.BusName == id.BusName { message.Window = window.Path } C.g_object_unref(C.gpointer(current)) current = nil break } parent := C.atspi_accessible_get_parent(current, nil) C.g_object_unref(C.gpointer(current)) current = parent } if current != nil { C.g_object_unref(C.gpointer(current)) } if !id.Valid() || message.Window == "" { return nil } payload := C.cthulhu_event_payload(event) message.Text = mumbleMessageText(sanitizeTextContext(C.GoString(payload))) C.g_free(C.gpointer(payload)) return message }