// 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 ( "context" ) func (adapter *Adapter) SetSecureInputActive(active bool) { adapter.secureMutex.Lock() defer adapter.secureMutex.Unlock() if adapter.secureCancel != nil { adapter.secureCancel() } adapter.secureContext, adapter.secureCancel = context.WithCancel(context.Background()) if active { adapter.secureCancel() } adapter.secure.Store(active) adapter.echoFocus.Store(nil) adapter.secureEpoch.Add(1) adapter.secureReset.Store(true) if !active { adapter.secureResync.Store(true) } for { select { case <-adapter.events: default: return } } } func (adapter *Adapter) applySecureReset() { if !adapter.secureReset.Swap(false) { return } C.cthulhu_clear_selection(adapter.callbackData) adapter.deferredLiveRegions = nil adapter.invalidateTree() adapter.treeMutex.Lock() adapter.tree, adapter.documentTree, adapter.documentTextTree = nil, nil, nil adapter.treeMutex.Unlock() adapter.clearStashedDocuments() adapter.clearNativeDocument() adapter.clearNativeReview() adapter.clearMouseApplication() for _, focus := range adapter.nativeFocus { C.g_object_unref(C.gpointer(focus.source)) } adapter.nativeFocus = nil for id := range adapter.documentWindows { adapter.forgetDocumentWindow(id) } adapter.activeDocument, adapter.selectedTabWindow = ObjectID{}, ObjectID{} adapter.foregroundWindow, adapter.promptRefreshWindow = ObjectID{}, ObjectID{} adapter.promptScannedWindow = ObjectID{} clear(adapter.navigationEcho) } // Lock transitions cancel captures already in progress as well as later ones. func (adapter *Adapter) secureRequestContext(ctx context.Context) (context.Context, context.CancelFunc) { adapter.secureMutex.Lock() defer adapter.secureMutex.Unlock() if adapter.secureContext == nil { adapter.secureContext, adapter.secureCancel = context.WithCancel(context.Background()) } requestContext, cancel := context.WithCancel(ctx) if adapter.secure.Load() { cancel() } stop := context.AfterFunc(adapter.secureContext, cancel) return requestContext, func() { stop(); cancel() } } // Serialize final delivery with lock queue retirement, including callbacks // that began snapshotting before the lock name appeared. func (adapter *Adapter) enqueueSecureEvent(event Event, epoch uint64) { adapter.secureMutex.Lock() defer adapter.secureMutex.Unlock() if adapter.secure.Load() || epoch != adapter.secureEpoch.Load() { return } adapter.observeEchoFocus(event) // Editable transitions refresh key echo without adding a spoken state. if event.Type == "object:state-changed:editable" { return } select { case adapter.events <- event: default: adapter.overflow.Add(1) } }