|
|
|
@ -2,19 +2,51 @@ using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.IO; |
|
|
|
using System.Linq; |
|
|
|
using System.Threading; |
|
|
|
using System.Threading.Tasks; |
|
|
|
using Avalonia.Logging; |
|
|
|
using Tmds.DBus.Protocol; |
|
|
|
using Tmds.DBus.SourceGenerator; |
|
|
|
|
|
|
|
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor.
|
|
|
|
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
|
|
|
|
|
|
|
namespace Avalonia.FreeDesktop.AtSpi; |
|
|
|
|
|
|
|
internal class EventObject(Connection connection) : OrgA11yAtspiEventObject |
|
|
|
{ |
|
|
|
public override Connection Connection => connection; |
|
|
|
protected override ValueTask OnDummyAsync() |
|
|
|
{ |
|
|
|
return default; |
|
|
|
} |
|
|
|
|
|
|
|
public void EmitOnPropertyChange(string? @property, int arg1, int arg2, Variant value, |
|
|
|
Dictionary<string, Variant>? properties) |
|
|
|
=> EmitPropertyChange(@property, arg1, arg2, value, |
|
|
|
properties); |
|
|
|
|
|
|
|
public void EmitOnChildrenChange(string? operation, int indexInParent, int arg2, Variant child, |
|
|
|
Dictionary<string, Variant>? properties) => |
|
|
|
EmitChildrenChanged(operation, indexInParent, arg2, child, properties); |
|
|
|
} |
|
|
|
|
|
|
|
enum GtkAccessibleChildState |
|
|
|
{ |
|
|
|
GTK_ACCESSIBLE_CHILD_STATE_ADDED, |
|
|
|
GTK_ACCESSIBLE_CHILD_STATE_REMOVED |
|
|
|
}; |
|
|
|
|
|
|
|
enum GtkAccessibleChildChange |
|
|
|
{ |
|
|
|
GTK_ACCESSIBLE_CHILD_CHANGE_ADDED = 1 << GtkAccessibleChildState.GTK_ACCESSIBLE_CHILD_STATE_ADDED, |
|
|
|
GTK_ACCESSIBLE_CHILD_CHANGE_REMOVED = 1 << GtkAccessibleChildState.GTK_ACCESSIBLE_CHILD_STATE_REMOVED |
|
|
|
}; |
|
|
|
|
|
|
|
internal abstract class Accessible : OrgA11yAtspiAccessible |
|
|
|
{ |
|
|
|
private readonly Accessible? _internalParent; |
|
|
|
private PathHandler? _pathHandler; |
|
|
|
protected PathHandler? _pathHandler; |
|
|
|
public Guid InternalGuid { get; protected init; } |
|
|
|
public CacheEntry InternalCacheEntry { get; } = new(); |
|
|
|
public string DbusPath { get; } |
|
|
|
@ -22,16 +54,16 @@ internal abstract class Accessible : OrgA11yAtspiAccessible |
|
|
|
public override Connection Connection { get; } |
|
|
|
public Accessible? InternalParent => _internalParent; |
|
|
|
|
|
|
|
|
|
|
|
protected Accessible(string serviceName, Accessible? internalParent, Connection? connection = null) |
|
|
|
{ |
|
|
|
|
|
|
|
if (connection is null && internalParent is not null) |
|
|
|
{ |
|
|
|
_internalParent = internalParent; |
|
|
|
|
|
|
|
Parent = internalParent.Convert(); |
|
|
|
ServiceName = serviceName; |
|
|
|
InternalGuid = Guid.NewGuid(); |
|
|
|
|
|
|
|
DbusPath = Path.Combine(AtSpiConstants.AvaloniaPathPrefix, InternalGuid.ToString("N")); |
|
|
|
|
|
|
|
InternalCacheEntry.Accessible = (serviceName, DbusPath); |
|
|
|
@ -43,16 +75,32 @@ internal abstract class Accessible : OrgA11yAtspiAccessible |
|
|
|
_pathHandler = new PathHandler(DbusPath); |
|
|
|
_pathHandler.Add(this); |
|
|
|
Connection = internalParent.Connection; |
|
|
|
|
|
|
|
internalParent.Connection.AddMethodHandler(_pathHandler); |
|
|
|
_eventObject = new EventObject(Connection); |
|
|
|
Connection.AddMethodHandler(_pathHandler); |
|
|
|
|
|
|
|
internalParent.AddChild(this); |
|
|
|
} |
|
|
|
else if(connection is not null && this.Connection is null) |
|
|
|
else if (connection is not null && this.Connection is null) |
|
|
|
{ |
|
|
|
|
|
|
|
InternalCacheEntry.Accessible = (serviceName, AtSpiContext.RootPath)!; |
|
|
|
InternalCacheEntry.Application = (serviceName, AtSpiContext.RootPath)!; |
|
|
|
InternalCacheEntry.ApplicableInterfaces = ["org.a11y.atspi.Accessible", "org.a11y.atspi.Application"]; |
|
|
|
InternalCacheEntry.Role = AtSpiConstants.Role.Application; |
|
|
|
InternalCacheEntry.Name = Application.Current?.Name ?? "Avalonia Application"; |
|
|
|
InternalCacheEntry.Description = string.Empty; |
|
|
|
InternalCacheEntry.ChildCount = 0; //TODO
|
|
|
|
InternalCacheEntry.ApplicableStates = [0, 0]; |
|
|
|
this.InternalGuid = Guid.Empty; |
|
|
|
|
|
|
|
Connection = connection; |
|
|
|
DbusPath = AtSpiContext.RootPath; |
|
|
|
ServiceName = serviceName; |
|
|
|
_pathHandler = new PathHandler(DbusPath); |
|
|
|
_eventObject = new EventObject(Connection); |
|
|
|
_pathHandler.Add(this); |
|
|
|
_pathHandler.Add(_eventObject); |
|
|
|
Connection.AddMethodHandler(_pathHandler); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -60,22 +108,31 @@ internal abstract class Accessible : OrgA11yAtspiAccessible |
|
|
|
|
|
|
|
|
|
|
|
private readonly List<Accessible> _internalChildren = new(); |
|
|
|
private readonly EventObject _eventObject; |
|
|
|
|
|
|
|
public void AddChild(Accessible accessible) |
|
|
|
{ |
|
|
|
if (AtSpiContext.Cache != null && AtSpiContext.Cache.TryAddEntry(accessible)) |
|
|
|
{ |
|
|
|
_internalChildren.Add(accessible); |
|
|
|
ChildCount = _internalChildren.Count; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
Logger.TryGet(LogEventLevel.Error, LogArea.FreeDesktopPlatform)?.Log(this, |
|
|
|
$"Unable to add Accessible object to the root AT-SPI cache. {accessible.InternalGuid}"); |
|
|
|
|
|
|
|
} |
|
|
|
_internalChildren.Add(accessible); |
|
|
|
ChildCount = _internalChildren.Count; |
|
|
|
InternalCacheEntry.ChildCount = ChildCount; |
|
|
|
AtSpiContext.Cache.TryAddEntry(accessible); |
|
|
|
|
|
|
|
var k = new Struct<string, ObjectPath>(ServiceName, accessible.DbusPath); |
|
|
|
|
|
|
|
// new Thread(async () =>
|
|
|
|
// {
|
|
|
|
// for (int i = 0; i < 10; i++)
|
|
|
|
// {
|
|
|
|
// await Task.Delay(2000);
|
|
|
|
// _eventObject.EmitOnPropertyChange("accessible-childcount", 0, 0, new Variant($"test{i}"), null);
|
|
|
|
// }
|
|
|
|
// }).Start();
|
|
|
|
|
|
|
|
_eventObject.EmitOnChildrenChange("add", _internalChildren.IndexOf(accessible), 0, |
|
|
|
k , null); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void RemoveChild(Accessible accessible) |
|
|
|
{ |
|
|
|
_internalChildren.Remove(accessible); |
|
|
|
@ -92,7 +149,7 @@ internal abstract class Accessible : OrgA11yAtspiAccessible |
|
|
|
return accessible.Convert(); |
|
|
|
} |
|
|
|
|
|
|
|
return ("", "/org/a11y/atspi/accessible/null"); |
|
|
|
return ("", "/org/a11y/atspi/null"); |
|
|
|
} |
|
|
|
|
|
|
|
protected override async ValueTask<(string, ObjectPath)[]> OnGetChildrenAsync() |
|
|
|
@ -120,12 +177,12 @@ internal abstract class Accessible : OrgA11yAtspiAccessible |
|
|
|
|
|
|
|
protected override async ValueTask<string> OnGetRoleNameAsync() |
|
|
|
{ |
|
|
|
return InternalCacheEntry.RoleName; |
|
|
|
return AtSpiConstants.RoleNames[(int)InternalCacheEntry.Role]; |
|
|
|
} |
|
|
|
|
|
|
|
protected override async ValueTask<string> OnGetLocalizedRoleNameAsync() |
|
|
|
{ |
|
|
|
return InternalCacheEntry.LocalizedName; |
|
|
|
return AtSpiConstants.RoleNames[(int)InternalCacheEntry.Role]; |
|
|
|
} |
|
|
|
|
|
|
|
protected override async ValueTask<uint[]> OnGetStateAsync() |
|
|
|
@ -148,5 +205,3 @@ internal abstract class Accessible : OrgA11yAtspiAccessible |
|
|
|
return InternalCacheEntry.ApplicableInterfaces; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|