From beca19ee5092a394362d628af4b3db2c64e50734 Mon Sep 17 00:00:00 2001
From: Jumar Macato <16554748+jmacato@users.noreply.github.com>
Date: Wed, 18 Mar 2026 19:54:47 +0800
Subject: [PATCH] add InitializePeerAsync to AtSpiServer for P2P automation
mode
---
src/Avalonia.FreeDesktop.AtSpi/AtSpiServer.cs | 45 +++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/src/Avalonia.FreeDesktop.AtSpi/AtSpiServer.cs b/src/Avalonia.FreeDesktop.AtSpi/AtSpiServer.cs
index 16d36eb590..d831fc2d35 100644
--- a/src/Avalonia.FreeDesktop.AtSpi/AtSpiServer.cs
+++ b/src/Avalonia.FreeDesktop.AtSpi/AtSpiServer.cs
@@ -15,6 +15,11 @@ namespace Avalonia.FreeDesktop.AtSpi
{
///
/// Manages the AT-SPI D-Bus connection, node registration, and event emission.
+ /// Can operate in two modes:
+ ///
+ /// - — connects to the Linux accessibility bus (screen reader mode).
+ /// - — accepts an existing peer-to-peer D-Bus connection (automation mode).
+ ///
///
internal sealed class AtSpiServer : IAsyncDisposable
{
@@ -82,6 +87,46 @@ namespace Avalonia.FreeDesktop.AtSpi
_ = InitializeRegistryTrackerAsync(_registryTracker);
}
+ ///
+ /// Initializes the AT-SPI server on an existing peer-to-peer D-Bus connection.
+ /// Unlike , this does not connect to the accessibility bus
+ /// or embed with the AT-SPI registry — the caller supplies the connection directly.
+ /// Suitable for automation scenarios where the transport is a named pipe or socket.
+ ///
+ /// An already-connected peer-to-peer .
+ ///
+ /// A unique name for this server instance (e.g. ":auto.1234").
+ /// Used in AT-SPI object references returned to the client.
+ ///
+ ///
+ /// Optional synchronization context for marshaling handler calls.
+ /// Pass the UI thread's context when requires dispatcher access.
+ /// When , an is created automatically.
+ ///
+ internal async Task InitializePeerAsync(
+ DBusConnection connection,
+ string uniqueName,
+ SynchronizationContext? syncContext = null)
+ {
+ ArgumentNullException.ThrowIfNull(connection);
+ ArgumentException.ThrowIfNullOrEmpty(uniqueName);
+
+ _a11yConnection = connection;
+ _uniqueName = uniqueName;
+ _syncContext = syncContext ?? new AvaloniaSynchronizationContext(DispatcherPriority.Normal);
+
+ _appRoot = new ApplicationAtSpiNode(null);
+ _cacheHandler = new AtSpiCacheHandler();
+
+ await BuildAndRegisterAppRootAsync();
+ await RegisterCachePathAsync();
+
+ // No registry embedding or event tracker in peer-to-peer mode —
+ // the client is the only consumer and receives all signals directly.
+ lock (_embedSync)
+ _isEmbedded = true;
+ }
+
///
/// Adds a window to the AT-SPI tree.
///