diff --git a/.gitmodules b/.gitmodules index 16bc977251..2b899e8f5a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "Tmds.DBus"] path = src/Linux/Tmds.DBus url = https://github.com/affederaffe/Tmds.DBus +[submodule "src/tools/Tmds.DBus.SourceGenerator"] + path = src/tools/Tmds.DBus.SourceGenerator + url = https://github.com/affederaffe/Tmds.DBus.SourceGenerator diff --git a/Avalonia.Desktop.slnf b/Avalonia.Desktop.slnf index 72eb13d0a9..165245781b 100644 --- a/Avalonia.Desktop.slnf +++ b/Avalonia.Desktop.slnf @@ -38,6 +38,7 @@ "src\\Skia\\Avalonia.Skia\\Avalonia.Skia.csproj", "src\\tools\\DevAnalyzers\\DevAnalyzers.csproj", "src\\tools\\DevGenerators\\DevGenerators.csproj", + "src\\tools\\Tmds.DBus.SourceGenerator\\Tmds.DBus.SourceGenerator\\Tmds.DBus.SourceGenerator.csproj", "src\\Windows\\Avalonia.Direct2D1\\Avalonia.Direct2D1.csproj", "src\\Windows\\Avalonia.Win32.Interop\\Avalonia.Win32.Interop.csproj", "src\\Windows\\Avalonia.Win32\\Avalonia.Win32.csproj", diff --git a/Avalonia.sln b/Avalonia.sln index e399483896..47ed2b9140 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -233,6 +233,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUIDemo", "samples\R EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tmds.DBus.Protocol", "src\Linux\Tmds.DBus\src\Tmds.DBus.Protocol\Tmds.DBus.Protocol.csproj", "{29E25263-3CC3-4D55-A042-00BA136867D4}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tmds.DBus.SourceGenerator", "src\tools\Tmds.DBus.SourceGenerator\Tmds.DBus.SourceGenerator\Tmds.DBus.SourceGenerator.csproj", "{5E9C0032-E460-4BC1-BCC7-6448F34DD679}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -548,6 +550,10 @@ Global {29E25263-3CC3-4D55-A042-00BA136867D4}.Debug|Any CPU.Build.0 = Debug|Any CPU {29E25263-3CC3-4D55-A042-00BA136867D4}.Release|Any CPU.ActiveCfg = Release|Any CPU {29E25263-3CC3-4D55-A042-00BA136867D4}.Release|Any CPU.Build.0 = Release|Any CPU + {5E9C0032-E460-4BC1-BCC7-6448F34DD679}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5E9C0032-E460-4BC1-BCC7-6448F34DD679}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5E9C0032-E460-4BC1-BCC7-6448F34DD679}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E9C0032-E460-4BC1-BCC7-6448F34DD679}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -613,6 +619,7 @@ Global {90B08091-9BBD-4362-B712-E9F2CC62B218} = {9B9E3891-2366-4253-A952-D08BCEB71098} {75C47156-C5D8-44BC-A5A7-E8657C2248D6} = {9B9E3891-2366-4253-A952-D08BCEB71098} {29E25263-3CC3-4D55-A042-00BA136867D4} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B} + {5E9C0032-E460-4BC1-BCC7-6448F34DD679} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} diff --git a/src/Avalonia.FreeDesktop/AppMenuRegistrar.DBus.cs b/src/Avalonia.FreeDesktop/AppMenuRegistrar.DBus.cs deleted file mode 100644 index 75c8ce61a5..0000000000 --- a/src/Avalonia.FreeDesktop/AppMenuRegistrar.DBus.cs +++ /dev/null @@ -1,173 +0,0 @@ -using System; -using System.Threading.Tasks; -using Tmds.DBus.Protocol; - -namespace Avalonia.FreeDesktop -{ - internal class Registrar : AppMenuRegistrarObject - { - private const string Interface = "com.canonical.AppMenu.Registrar"; - - public Registrar(RegistrarService service, ObjectPath path) : base(service, path) { } - - public Task RegisterWindowAsync(uint windowId, ObjectPath menuObjectPath) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "uo", - member: "RegisterWindow", - flags: MessageFlags.NoReplyExpected); - writer.WriteUInt32(windowId); - writer.WriteObjectPath(menuObjectPath); - return writer.CreateMessage(); - } - } - - public Task UnregisterWindowAsync(uint windowId) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "u", - member: "UnregisterWindow"); - writer.WriteUInt32(windowId); - return writer.CreateMessage(); - } - } - - public Task<(string Service, ObjectPath MenuObjectPath)> GetMenuForWindowAsync(uint windowId) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_so(m, (AppMenuRegistrarObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "u", - member: "GetMenuForWindow"); - writer.WriteUInt32(windowId); - return writer.CreateMessage(); - } - } - } - - internal class RegistrarService - { - public RegistrarService(Connection connection, string destination) - => (Connection, Destination) = (connection, destination); - - public Connection Connection { get; } - public string Destination { get; } - public Registrar CreateRegistrar(string path) => new(this, path); - } - - internal class AppMenuRegistrarObject - { - protected AppMenuRegistrarObject(RegistrarService service, ObjectPath path) - => (Service, Path) = (service, path); - - protected RegistrarService Service { get; } - protected ObjectPath Path { get; } - protected Connection Connection => Service.Connection; - - protected MessageBuffer CreateGetPropertyMessage(string @interface, string property) - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ss", - member: "Get"); - writer.WriteString(@interface); - writer.WriteString(property); - return writer.CreateMessage(); - } - - protected MessageBuffer CreateGetAllPropertiesMessage(string @interface) - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "s", - member: "GetAll"); - writer.WriteString(@interface); - return writer.CreateMessage(); - } - - protected ValueTask WatchPropertiesChangedAsync(string @interface, - MessageValueReader> reader, Action> handler, - bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = Service.Destination, - Path = Path, - Interface = "org.freedesktop.DBus.Properties", - Member = "PropertiesChanged", - Arg0 = @interface - }; - return Connection.AddMatchAsync(rule, reader, static (ex, changes, _, hs) - => ((Action>)hs!).Invoke(ex, changes), - this, handler, emitOnCapturedContext); - } - - public ValueTask WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, - MessageValueReader reader, Action handler, bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = sender, - Path = path, - Member = signal, - Interface = @interface - }; - return Connection.AddMatchAsync(rule, reader, static (ex, arg, _, hs) => - ((Action)hs!).Invoke(ex, arg), this, handler, emitOnCapturedContext); - } - - public ValueTask WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, Action handler, - bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = sender, - Path = path, - Member = signal, - Interface = @interface - }; - return Connection.AddMatchAsync(rule, static (_, _) - => null!, static (ex, _, _, hs) - => ((Action)hs!).Invoke(ex), this, handler, emitOnCapturedContext); - } - - protected static (string, ObjectPath) ReadMessage_so(Message message, AppMenuRegistrarObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadString(); - var arg1 = reader.ReadObjectPath(); - return (arg0, arg1); - } - } -} diff --git a/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj b/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj index e80a90e38a..e1e0a636ea 100644 --- a/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj +++ b/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj @@ -17,10 +17,15 @@ + + + + + diff --git a/src/Avalonia.FreeDesktop/DBus.DBus.cs b/src/Avalonia.FreeDesktop/DBus.DBus.cs deleted file mode 100644 index 0f83ddaa4a..0000000000 --- a/src/Avalonia.FreeDesktop/DBus.DBus.cs +++ /dev/null @@ -1,641 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Tmds.DBus.Protocol; - -namespace Avalonia.FreeDesktop -{ - internal record DBusProperties - { - public string[] Features { get; set; } = default!; - public string[] Interfaces { get; set; } = default!; - } - - internal class DBus : DBusObject - { - private const string Interface = "org.freedesktop.DBus"; - - public DBus(DBusService service, ObjectPath path) : base(service, path) { } - - public Task HelloAsync() - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_s(m, (DBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "Hello"); - return writer.CreateMessage(); - } - } - - public Task RequestNameAsync(string a0, uint a1) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_u(m, (DBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "su", - member: "RequestName"); - writer.WriteString(a0); - writer.WriteUInt32(a1); - return writer.CreateMessage(); - } - } - - public Task ReleaseNameAsync(string a0) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_u(m, (DBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "ReleaseName"); - writer.WriteString(a0); - return writer.CreateMessage(); - } - } - - public Task StartServiceByNameAsync(string a0, uint a1) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_u(m, (DBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "su", - member: "StartServiceByName"); - writer.WriteString(a0); - writer.WriteUInt32(a1); - return writer.CreateMessage(); - } - } - - public Task UpdateActivationEnvironmentAsync(Dictionary a0) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "a{ss}", - member: "UpdateActivationEnvironment"); - writer.WriteDictionary(a0); - return writer.CreateMessage(); - } - } - - public Task NameHasOwnerAsync(string a0) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_b(m, (DBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "NameHasOwner"); - writer.WriteString(a0); - return writer.CreateMessage(); - } - } - - public Task ListNamesAsync() - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_as(m, (DBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "ListNames"); - return writer.CreateMessage(); - } - } - - public Task ListActivatableNamesAsync() - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_as(m, (DBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "ListActivatableNames"); - return writer.CreateMessage(); - } - } - - public Task AddMatchAsync(string a0) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "AddMatch"); - writer.WriteString(a0); - return writer.CreateMessage(); - } - } - - public Task RemoveMatchAsync(string a0) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "RemoveMatch"); - writer.WriteString(a0); - return writer.CreateMessage(); - } - } - - public Task GetNameOwnerAsync(string a0) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_s(m, (DBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "GetNameOwner"); - writer.WriteString(a0); - return writer.CreateMessage(); - } - } - - public Task ListQueuedOwnersAsync(string a0) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_as(m, (DBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "ListQueuedOwners"); - writer.WriteString(a0); - return writer.CreateMessage(); - } - } - - public Task GetConnectionUnixUserAsync(string a0) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_u(m, (DBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "GetConnectionUnixUser"); - writer.WriteString(a0); - return writer.CreateMessage(); - } - } - - public Task GetConnectionUnixProcessIDAsync(string a0) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_u(m, (DBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "GetConnectionUnixProcessID"); - writer.WriteString(a0); - return writer.CreateMessage(); - } - } - - public Task GetAdtAuditSessionDataAsync(string a0) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_ay(m, (DBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "GetAdtAuditSessionData"); - writer.WriteString(a0); - return writer.CreateMessage(); - } - } - - public Task GetConnectionSELinuxSecurityContextAsync(string a0) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_ay(m, (DBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "GetConnectionSELinuxSecurityContext"); - writer.WriteString(a0); - return writer.CreateMessage(); - } - } - - public Task ReloadConfigAsync() - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "ReloadConfig"); - return writer.CreateMessage(); - } - } - - public Task GetIdAsync() - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_s(m, (DBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "GetId"); - return writer.CreateMessage(); - } - } - - public Task> GetConnectionCredentialsAsync(string a0) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_aesv(m, (DBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "GetConnectionCredentials"); - writer.WriteString(a0); - return writer.CreateMessage(); - } - } - - public ValueTask WatchNameOwnerChangedAsync(Action handler, bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "NameOwnerChanged", static (m, s) => - ReadMessage_sss(m, (DBusObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchNameLostAsync(Action handler, bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "NameLost", static (m, s) => - ReadMessage_s(m, (DBusObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchNameAcquiredAsync(Action handler, bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "NameAcquired", static (m, s) => - ReadMessage_s(m, (DBusObject)s!), handler, emitOnCapturedContext); - - public Task SetFeaturesAsync(string[] value) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ssv", - member: "Set"); - writer.WriteString(Interface); - writer.WriteString("Features"); - writer.WriteSignature("as"); - writer.WriteArray(value); - return writer.CreateMessage(); - } - } - - public Task SetInterfacesAsync(string[] value) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ssv", - member: "Set"); - writer.WriteString(Interface); - writer.WriteString("Interfaces"); - writer.WriteSignature("as"); - writer.WriteArray(value); - return writer.CreateMessage(); - } - } - - public Task GetFeaturesAsync() => - Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "Features"), static (m, s) => - ReadMessage_v_as(m, (DBusObject)s!), this); - - public Task GetInterfacesAsync() => - Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "Interfaces"), static (m, s) => - ReadMessage_v_as(m, (DBusObject)s!), this); - - public Task GetPropertiesAsync() - { - return Connection.CallMethodAsync(CreateGetAllPropertiesMessage(Interface), static (m, _) => - ReadMessage(m), this); - - static DBusProperties ReadMessage(Message message) - { - var reader = message.GetBodyReader(); - return ReadProperties(ref reader); - } - } - - public ValueTask WatchPropertiesChangedAsync(Action> handler, bool emitOnCapturedContext = true) - { - return base.WatchPropertiesChangedAsync(Interface, static (m, _) => - ReadMessage(m), handler, emitOnCapturedContext); - - static PropertyChanges ReadMessage(Message message) - { - var reader = message.GetBodyReader(); - reader.ReadString(); // interface - List changed = new(); - return new PropertyChanges(ReadProperties(ref reader, changed), changed.ToArray(), ReadInvalidated(ref reader)); - } - - static string[] ReadInvalidated(ref Reader reader) - { - List? invalidated = null; - var headersEnd = reader.ReadArrayStart(DBusType.String); - while (reader.HasNext(headersEnd)) - { - invalidated ??= new List(); - var property = reader.ReadString(); - switch (property) - { - case "Features": - invalidated.Add("Features"); - break; - case "Interfaces": - invalidated.Add("Interfaces"); - break; - } - } - - return invalidated?.ToArray() ?? Array.Empty(); - } - } - - private static DBusProperties ReadProperties(ref Reader reader, List? changedList = null) - { - var props = new DBusProperties(); - var headersEnd = reader.ReadArrayStart(DBusType.Struct); - while (reader.HasNext(headersEnd)) - { - var property = reader.ReadString(); - switch (property) - { - case "Features": - reader.ReadSignature("as"); - props.Features = reader.ReadArray(); - changedList?.Add("Features"); - break; - case "Interfaces": - reader.ReadSignature("as"); - props.Interfaces = reader.ReadArray(); - changedList?.Add("Interfaces"); - break; - default: - reader.ReadVariant(); - break; - } - } - - return props; - } - } - - internal class DBusService - { - public DBusService(Connection connection, string destination) - => (Connection, Destination) = (connection, destination); - - public Connection Connection { get; } - public string Destination { get; } - public DBus CreateDBus(string path) => new(this, path); - } - - internal class DBusObject - { - protected DBusObject(DBusService service, ObjectPath path) - { - Service = service; - Path = path; - } - - public DBusService Service { get; } - public ObjectPath Path { get; } - protected Connection Connection => Service.Connection; - - protected MessageBuffer CreateGetPropertyMessage(string @interface, string property) - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ss", - member: "Get"); - writer.WriteString(@interface); - writer.WriteString(property); - return writer.CreateMessage(); - } - - protected MessageBuffer CreateGetAllPropertiesMessage(string @interface) - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "s", - member: "GetAll"); - writer.WriteString(@interface); - return writer.CreateMessage(); - } - - protected ValueTask WatchPropertiesChangedAsync(string @interface, - MessageValueReader> reader, Action> handler, - bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = Service.Destination, - Path = Path, - Interface = "org.freedesktop.DBus.Properties", - Member = "PropertiesChanged", - Arg0 = @interface - }; - return Connection.AddMatchAsync(rule, reader, static (ex, changes, _, hs) => - ((Action>)hs!).Invoke(ex, changes), this, handler, emitOnCapturedContext); - } - - public ValueTask WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, - MessageValueReader reader, Action handler, bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = sender, - Path = path, - Member = signal, - Interface = @interface - }; - return Connection.AddMatchAsync(rule, reader, static (ex, arg, _, hs) => - ((Action)hs!).Invoke(ex, arg), this, handler, emitOnCapturedContext); - } - - public ValueTask WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, Action handler, - bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = sender, - Path = path, - Member = signal, - Interface = @interface - }; - return Connection.AddMatchAsync(rule, static (_, _) => null!, static (ex, _, _, hs) => - ((Action)hs!).Invoke(ex), this, handler, emitOnCapturedContext); - } - - protected static string ReadMessage_s(Message message, DBusObject _) - { - var reader = message.GetBodyReader(); - return reader.ReadString(); - } - - protected static uint ReadMessage_u(Message message, DBusObject _) - { - var reader = message.GetBodyReader(); - return reader.ReadUInt32(); - } - - protected static bool ReadMessage_b(Message message, DBusObject _) - { - var reader = message.GetBodyReader(); - return reader.ReadBool(); - } - - protected static string[] ReadMessage_as(Message message, DBusObject _) - { - var reader = message.GetBodyReader(); - return reader.ReadArray(); - } - - protected static byte[] ReadMessage_ay(Message message, DBusObject _) - { - var reader = message.GetBodyReader(); - return reader.ReadArray(); - } - - protected static Dictionary ReadMessage_aesv(Message message, DBusObject _) - { - var reader = message.GetBodyReader(); - return reader.ReadDictionary(); - } - - protected static (string, string, string) ReadMessage_sss(Message message, DBusObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadString(); - var arg1 = reader.ReadString(); - var arg2 = reader.ReadString(); - return (arg0, arg1, arg2); - } - - protected static string[] ReadMessage_v_as(Message message, DBusObject _) - { - var reader = message.GetBodyReader(); - reader.ReadSignature("as"); - return reader.ReadArray(); - } - } -} diff --git a/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs b/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs index c7bf530cfd..08d2a0c219 100644 --- a/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs +++ b/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs @@ -60,7 +60,7 @@ namespace Avalonia.FreeDesktop.DBusIme { foreach (var name in _knownNames) { - var dbus = new DBusService(Connection, name).CreateDBus("/org/freedesktop/DBus"); + var dbus = new OrgFreedesktopDBus(Connection, name, "/org/freedesktop/DBus"); _disposables.Add(await dbus.WatchNameOwnerChangedAsync(OnNameChange)); var nameOwner = await dbus.GetNameOwnerAsync(name); OnNameChange(null, (name, null, nameOwner)); diff --git a/src/Avalonia.FreeDesktop/DBusIme/Fcitx/Fcitx.DBus.cs b/src/Avalonia.FreeDesktop/DBusIme/Fcitx/Fcitx.DBus.cs deleted file mode 100644 index f9e4497892..0000000000 --- a/src/Avalonia.FreeDesktop/DBusIme/Fcitx/Fcitx.DBus.cs +++ /dev/null @@ -1,627 +0,0 @@ -using System; -using System.Threading.Tasks; -using Tmds.DBus.Protocol; - -namespace Avalonia.FreeDesktop.DBusIme.Fcitx -{ - internal class InputContext : FcitxObject - { - private const string Interface = "org.fcitx.Fcitx.InputContext"; - - public InputContext(FcitxService service, ObjectPath path) : base(service, path) { } - - public Task FocusInAsync() - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "FocusIn"); - return writer.CreateMessage(); - } - } - - public Task FocusOutAsync() - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "FocusOut"); - return writer.CreateMessage(); - } - } - - public Task ResetAsync() - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "Reset"); - return writer.CreateMessage(); - } - } - - public Task SetCursorRectAsync(int x, int y, int w, int h) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "iiii", - member: "SetCursorRect"); - writer.WriteInt32(x); - writer.WriteInt32(y); - writer.WriteInt32(w); - writer.WriteInt32(h); - return writer.CreateMessage(); - } - } - - public Task SetCapacityAsync(uint caps) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "u", - member: "SetCapacity"); - writer.WriteUInt32(caps); - return writer.CreateMessage(); - } - } - - public Task SetSurroundingTextAsync(string text, uint cursor, uint anchor) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "suu", - member: "SetSurroundingText"); - writer.WriteString(text); - writer.WriteUInt32(cursor); - writer.WriteUInt32(anchor); - return writer.CreateMessage(); - } - } - - public Task SetSurroundingTextPositionAsync(uint cursor, uint anchor) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "uu", - member: "SetSurroundingTextPosition"); - writer.WriteUInt32(cursor); - writer.WriteUInt32(anchor); - return writer.CreateMessage(); - } - } - - public Task DestroyICAsync() - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "DestroyIC"); - return writer.CreateMessage(); - } - } - - public Task ProcessKeyEventAsync(uint keyval, uint keycode, uint state, int type, uint time) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_i(m, (FcitxObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "uuuiu", - member: "ProcessKeyEvent"); - writer.WriteUInt32(keyval); - writer.WriteUInt32(keycode); - writer.WriteUInt32(state); - writer.WriteInt32(type); - writer.WriteUInt32(time); - return writer.CreateMessage(); - } - } - - public ValueTask WatchCommitStringAsync(Action handler, bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "CommitString", static (m, s) => - ReadMessage_s(m, (FcitxObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchCurrentIMAsync(Action handler, - bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "CurrentIM", static (m, s) => - ReadMessage_sss(m, (FcitxObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchUpdateFormattedPreeditAsync(Action handler, - bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "UpdateFormattedPreedit", static (m, s) => - ReadMessage_arsizi(m, (FcitxObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchForwardKeyAsync(Action handler, - bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "ForwardKey", static (m, s) => - ReadMessage_uui(m, (FcitxObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchDeleteSurroundingTextAsync(Action handler, - bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "DeleteSurroundingText", static (m, s) => - ReadMessage_iu(m, (FcitxObject)s!), handler, emitOnCapturedContext); - } - - internal class InputMethod : FcitxObject - { - private const string Interface = "org.fcitx.Fcitx.InputMethod"; - - public InputMethod(FcitxService service, ObjectPath path) : base(service, path) { } - - public Task<(int Icid, bool Enable, uint Keyval1, uint State1, uint Keyval2, uint State2)> CreateICv3Async(string appname, int pid) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_ibuuuu(m, (FcitxObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "si", - member: "CreateICv3"); - writer.WriteString(appname); - writer.WriteInt32(pid); - return writer.CreateMessage(); - } - } - } - - internal class InputContext1 : FcitxObject - { - private const string Interface = "org.fcitx.Fcitx.InputContext1"; - - public InputContext1(FcitxService service, ObjectPath path) : base(service, path) { } - - public Task FocusInAsync() - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "FocusIn"); - return writer.CreateMessage(); - } - } - - public Task FocusOutAsync() - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "FocusOut"); - return writer.CreateMessage(); - } - } - - public Task ResetAsync() - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "Reset"); - return writer.CreateMessage(); - } - } - - public Task SetCursorRectAsync(int x, int y, int w, int h) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "iiii", - member: "SetCursorRect"); - writer.WriteInt32(x); - writer.WriteInt32(y); - writer.WriteInt32(w); - writer.WriteInt32(h); - return writer.CreateMessage(); - } - } - - public Task SetCapabilityAsync(ulong caps) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "t", - member: "SetCapability"); - writer.WriteUInt64(caps); - return writer.CreateMessage(); - } - } - - public Task SetSurroundingTextAsync(string text, uint cursor, uint anchor) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "suu", - member: "SetSurroundingText"); - writer.WriteString(text); - writer.WriteUInt32(cursor); - writer.WriteUInt32(anchor); - return writer.CreateMessage(); - } - } - - public Task SetSurroundingTextPositionAsync(uint cursor, uint anchor) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "uu", - member: "SetSurroundingTextPosition"); - writer.WriteUInt32(cursor); - writer.WriteUInt32(anchor); - return writer.CreateMessage(); - } - } - - public Task DestroyICAsync() - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "DestroyIC"); - return writer.CreateMessage(); - } - } - - public Task ProcessKeyEventAsync(uint keyval, uint keycode, uint state, bool type, uint time) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_b(m, (FcitxObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "uuubu", - member: "ProcessKeyEvent"); - writer.WriteUInt32(keyval); - writer.WriteUInt32(keycode); - writer.WriteUInt32(state); - writer.WriteBool(type); - writer.WriteUInt32(time); - return writer.CreateMessage(); - } - } - - public ValueTask WatchCommitStringAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "CommitString", static (m, s) => - ReadMessage_s(m, (FcitxObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchCurrentIMAsync(Action handler, - bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "CurrentIM", static (m, s) => - ReadMessage_sss(m, (FcitxObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchUpdateFormattedPreeditAsync(Action handler, - bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "UpdateFormattedPreedit", static (m, s) => - ReadMessage_arsizi(m, (FcitxObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchForwardKeyAsync(Action handler, - bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "ForwardKey", static (m, s) => - ReadMessage_uub(m, (FcitxObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchDeleteSurroundingTextAsync(Action handler, - bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "DeleteSurroundingText", static (m, s) => - ReadMessage_iu(m, (FcitxObject)s!), handler, emitOnCapturedContext); - } - - internal class InputMethod1 : FcitxObject - { - private const string Interface = "org.fcitx.Fcitx.InputMethod1"; - - public InputMethod1(FcitxService service, ObjectPath path) : base(service, path) { } - - public Task<(ObjectPath A0, byte[] A1)> CreateInputContextAsync((string, string)[] a0) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_oay(m, (FcitxObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "a(ss)", - member: "CreateInputContext"); - writer.WriteArray(a0); - return writer.CreateMessage(); - } - } - } - - internal class FcitxService - { - public FcitxService(Connection connection, string destination) - => (Connection, Destination) = (connection, destination); - - public Connection Connection { get; } - public string Destination { get; } - public InputContext CreateInputContext(string path) => new(this, path); - public InputMethod CreateInputMethod(string path) => new(this, path); - public InputContext1 CreateInputContext1(string path) => new(this, path); - public InputMethod1 CreateInputMethod1(string path) => new(this, path); - } - - internal class FcitxObject - { - protected FcitxObject(FcitxService service, ObjectPath path) - => (Service, Path) = (service, path); - - public FcitxService Service { get; } - public ObjectPath Path { get; } - protected Connection Connection => Service.Connection; - - protected MessageBuffer CreateGetPropertyMessage(string @interface, string property) - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ss", - member: "Get"); - writer.WriteString(@interface); - writer.WriteString(property); - return writer.CreateMessage(); - } - - protected MessageBuffer CreateGetAllPropertiesMessage(string @interface) - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "s", - member: "GetAll"); - writer.WriteString(@interface); - return writer.CreateMessage(); - } - - protected ValueTask WatchPropertiesChangedAsync(string @interface, - MessageValueReader> reader, Action> handler, - bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = Service.Destination, - Path = Path, - Interface = "org.freedesktop.DBus.Properties", - Member = "PropertiesChanged", - Arg0 = @interface - }; - return Connection.AddMatchAsync(rule, reader, static (ex, changes, _, hs) => - ((Action>)hs!).Invoke(ex, changes), - this, handler, emitOnCapturedContext); - } - - public ValueTask WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, - MessageValueReader reader, Action handler, bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = sender, - Path = path, - Member = signal, - Interface = @interface - }; - return Connection.AddMatchAsync(rule, reader, static (ex, arg, _, hs) => - ((Action)hs!).Invoke(ex, arg), this, handler, emitOnCapturedContext); - } - - public ValueTask WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, Action handler, - bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = sender, - Path = path, - Member = signal, - Interface = @interface - }; - return Connection.AddMatchAsync(rule, static (_, _) => - null!, static (ex, _, _, hs) => - ((Action)hs!).Invoke(ex), this, handler, emitOnCapturedContext); - } - - protected static int ReadMessage_i(Message message, FcitxObject _) - { - var reader = message.GetBodyReader(); - return reader.ReadInt32(); - } - - protected static string ReadMessage_s(Message message, FcitxObject _) - { - var reader = message.GetBodyReader(); - return reader.ReadString(); - } - - protected static (string, string, string) ReadMessage_sss(Message message, FcitxObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadString(); - var arg1 = reader.ReadString(); - var arg2 = reader.ReadString(); - return (arg0, arg1, arg2); - } - - protected static ((string, int)[], int) ReadMessage_arsizi(Message message, FcitxObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadArray<(string, int)>(); - var arg1 = reader.ReadInt32(); - return (arg0, arg1); - } - - protected static (uint, uint, int) ReadMessage_uui(Message message, FcitxObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadUInt32(); - var arg1 = reader.ReadUInt32(); - var arg2 = reader.ReadInt32(); - return (arg0, arg1, arg2); - } - - protected static (int, uint) ReadMessage_iu(Message message, FcitxObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadInt32(); - var arg1 = reader.ReadUInt32(); - return (arg0, arg1); - } - - protected static (int, bool, uint, uint, uint, uint) ReadMessage_ibuuuu(Message message, FcitxObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadInt32(); - var arg1 = reader.ReadBool(); - var arg2 = reader.ReadUInt32(); - var arg3 = reader.ReadUInt32(); - var arg4 = reader.ReadUInt32(); - var arg5 = reader.ReadUInt32(); - return (arg0, arg1, arg2, arg3, arg4, arg5); - } - - protected static bool ReadMessage_b(Message message, FcitxObject _) - { - var reader = message.GetBodyReader(); - return reader.ReadBool(); - } - - protected static (uint, uint, bool) ReadMessage_uub(Message message, FcitxObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadUInt32(); - var arg1 = reader.ReadUInt32(); - var arg2 = reader.ReadBool(); - return (arg0, arg1, arg2); - } - - protected static (ObjectPath, byte[]) ReadMessage_oay(Message message, FcitxObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadObjectPath(); - var arg1 = reader.ReadArray(); - return (arg0, arg1); - } - } -} diff --git a/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxICWrapper.cs b/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxICWrapper.cs index b71ca55cf8..b651f126fb 100644 --- a/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxICWrapper.cs +++ b/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxICWrapper.cs @@ -5,15 +5,15 @@ namespace Avalonia.FreeDesktop.DBusIme.Fcitx { internal class FcitxICWrapper { - private readonly InputContext1? _modern; - private readonly InputContext? _old; + private readonly OrgFcitxFcitxInputContext1? _modern; + private readonly OrgFcitxFcitxInputContext? _old; - public FcitxICWrapper(InputContext old) + public FcitxICWrapper(OrgFcitxFcitxInputContext old) { _old = old; } - public FcitxICWrapper(InputContext1 modern) + public FcitxICWrapper(OrgFcitxFcitxInputContext1 modern) { _modern = modern; } @@ -43,7 +43,7 @@ namespace Avalonia.FreeDesktop.DBusIme.Fcitx public ValueTask WatchForwardKeyAsync(Action handler) => _old?.WatchForwardKeyAsync(handler) - ?? _modern?.WatchForwardKeyAsync((e, ev) => handler.Invoke(e, (ev.Keyval, ev.State, ev.Type ? 1 : 0))) + ?? _modern?.WatchForwardKeyAsync((e, ev) => handler.Invoke(e, (ev.keyval, ev.state, ev.type ? 1 : 0))) ?? new ValueTask(default(IDisposable?)); public Task SetCapacityAsync(uint flags) => diff --git a/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxX11TextInputMethod.cs b/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxX11TextInputMethod.cs index 2a5260b1cf..6b30c5424a 100644 --- a/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxX11TextInputMethod.cs +++ b/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxX11TextInputMethod.cs @@ -17,21 +17,20 @@ namespace Avalonia.FreeDesktop.DBusIme.Fcitx protected override async Task Connect(string name) { - var service = new FcitxService(Connection, name); if (name == "org.fcitx.Fcitx") { - var method = service.CreateInputMethod("/inputmethod"); + var method = new OrgFcitxFcitxInputMethod(Connection, name, "/inputmethod"); var resp = await method.CreateICv3Async(GetAppName(), Process.GetCurrentProcess().Id); - var proxy = service.CreateInputContext($"/inputcontext_{resp.Icid}"); + var proxy = new OrgFcitxFcitxInputContext(Connection, name, $"/inputcontext_{resp.icid}"); _context = new FcitxICWrapper(proxy); } else { - var method = service.CreateInputMethod1("/inputmethod"); + var method = new OrgFcitxFcitxInputMethod1(Connection, name, "/inputmethod"); var resp = await method.CreateInputContextAsync(new[] { ("appName", GetAppName()) }); - var proxy = service.CreateInputContext1(resp.A0); + var proxy = new OrgFcitxFcitxInputContext1(Connection, name, resp.Item1); _context = new FcitxICWrapper(proxy); } diff --git a/src/Avalonia.FreeDesktop/DBusIme/IBus/IBus.DBus.cs b/src/Avalonia.FreeDesktop/DBusIme/IBus/IBus.DBus.cs deleted file mode 100644 index e0f9681766..0000000000 --- a/src/Avalonia.FreeDesktop/DBusIme/IBus/IBus.DBus.cs +++ /dev/null @@ -1,513 +0,0 @@ -using System; -using System.Threading.Tasks; -using Tmds.DBus.Protocol; - -namespace Avalonia.FreeDesktop.DBusIme.IBus -{ - internal class Portal : IBusObject - { - private const string Interface = "org.freedesktop.IBus.Portal"; - - public Portal(IBusService service, ObjectPath path) : base(service, path) { } - - public Task CreateInputContextAsync(string clientName) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_o(m, (IBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "CreateInputContext"); - writer.WriteString(clientName); - return writer.CreateMessage(); - } - } - } - - internal class InputContext : IBusObject - { - private const string Interface = "org.freedesktop.IBus.InputContext"; - - public InputContext(IBusService service, ObjectPath path) : base(service, path) { } - - public Task ProcessKeyEventAsync(uint keyval, uint keycode, uint state) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_b(m, (IBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "uuu", - member: "ProcessKeyEvent"); - writer.WriteUInt32(keyval); - writer.WriteUInt32(keycode); - writer.WriteUInt32(state); - return writer.CreateMessage(); - } - } - - public Task SetCursorLocationAsync(int x, int y, int w, int h) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "iiii", - member: "SetCursorLocation"); - writer.WriteInt32(x); - writer.WriteInt32(y); - writer.WriteInt32(w); - writer.WriteInt32(h); - return writer.CreateMessage(); - } - } - - public Task SetCursorLocationRelativeAsync(int x, int y, int w, int h) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "iiii", - member: "SetCursorLocationRelative"); - writer.WriteInt32(x); - writer.WriteInt32(y); - writer.WriteInt32(w); - writer.WriteInt32(h); - return writer.CreateMessage(); - } - } - - public Task ProcessHandWritingEventAsync(double[] coordinates) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "ad", - member: "ProcessHandWritingEvent"); - writer.WriteArray(coordinates); - return writer.CreateMessage(); - } - } - - public Task CancelHandWritingAsync(uint nStrokes) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "u", - member: "CancelHandWriting"); - writer.WriteUInt32(nStrokes); - return writer.CreateMessage(); - } - } - - public Task FocusInAsync() - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "FocusIn"); - return writer.CreateMessage(); - } - } - - public Task FocusOutAsync() - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "FocusOut"); - return writer.CreateMessage(); - } - } - - public Task ResetAsync() - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "Reset"); - return writer.CreateMessage(); - } - } - - public Task SetCapabilitiesAsync(uint caps) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "u", - member: "SetCapabilities"); - writer.WriteUInt32(caps); - return writer.CreateMessage(); - } - } - - public Task PropertyActivateAsync(string name, uint state) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "su", - member: "PropertyActivate"); - writer.WriteString(name); - writer.WriteUInt32(state); - return writer.CreateMessage(); - } - } - - public Task SetEngineAsync(string name) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "SetEngine"); - writer.WriteString(name); - return writer.CreateMessage(); - } - } - - public Task GetEngineAsync() - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_v(m, (IBusObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "GetEngine"); - return writer.CreateMessage(); - } - } - - public Task SetSurroundingTextAsync(object text, uint cursorPos, uint anchorPos) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "vuu", - member: "SetSurroundingText"); - writer.WriteVariant(text); - writer.WriteUInt32(cursorPos); - writer.WriteUInt32(anchorPos); - return writer.CreateMessage(); - } - } - - public ValueTask WatchCommitTextAsync(Action handler, bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "CommitText", static (m, s) => - ReadMessage_v(m, (IBusObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchForwardKeyEventAsync(Action handler, - bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "ForwardKeyEvent", static (m, s) => - ReadMessage_uuu(m, (IBusObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchUpdatePreeditTextAsync(Action handler, - bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "UpdatePreeditText", static (m, s) => - ReadMessage_vub(m, (IBusObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchUpdatePreeditTextWithModeAsync( - Action handler, bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "UpdatePreeditTextWithMode", static (m, s) => - ReadMessage_vubu(m, (IBusObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchShowPreeditTextAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "ShowPreeditText", handler, emitOnCapturedContext); - - public ValueTask WatchHidePreeditTextAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "HidePreeditText", handler, emitOnCapturedContext); - - public ValueTask WatchUpdateAuxiliaryTextAsync(Action handler, - bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "UpdateAuxiliaryText", static (m, s) => - ReadMessage_vb(m, (IBusObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchShowAuxiliaryTextAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "ShowAuxiliaryText", handler, emitOnCapturedContext); - - public ValueTask WatchHideAuxiliaryTextAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "HideAuxiliaryText", handler, emitOnCapturedContext); - - public ValueTask WatchUpdateLookupTableAsync(Action handler, - bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "UpdateLookupTable", static (m, s) => - ReadMessage_vb(m, (IBusObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchShowLookupTableAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "ShowLookupTable", handler, emitOnCapturedContext); - - public ValueTask WatchHideLookupTableAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "HideLookupTable", handler, emitOnCapturedContext); - - public ValueTask WatchPageUpLookupTableAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "PageUpLookupTable", handler, emitOnCapturedContext); - - public ValueTask WatchPageDownLookupTableAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "PageDownLookupTable", handler, emitOnCapturedContext); - - public ValueTask WatchCursorUpLookupTableAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "CursorUpLookupTable", handler, emitOnCapturedContext); - - public ValueTask WatchCursorDownLookupTableAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "CursorDownLookupTable", handler, emitOnCapturedContext); - - public ValueTask WatchRegisterPropertiesAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "RegisterProperties", static (m, s) => ReadMessage_v(m, (IBusObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchUpdatePropertyAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "UpdateProperty", static (m, s) => ReadMessage_v(m, (IBusObject)s!), handler, emitOnCapturedContext); - } - - internal class Service : IBusObject - { - private const string Interface = "org.freedesktop.IBus.Service"; - - public Service(IBusService service, ObjectPath path) : base(service, path) { } - - public Task DestroyAsync() - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "Destroy"); - return writer.CreateMessage(); - } - } - } - - internal class IBusService - { - public IBusService(Connection connection, string destination) - => (Connection, Destination) = (connection, destination); - - public Connection Connection { get; } - public string Destination { get; } - public Portal CreatePortal(string path) => new(this, path); - public InputContext CreateInputContext(string path) => new(this, path); - public Service CreateService(string path) => new(this, path); - } - - internal class IBusObject - { - protected IBusObject(IBusService service, ObjectPath path) - => (Service, Path) = (service, path); - - public IBusService Service { get; } - public ObjectPath Path { get; } - protected Connection Connection => Service.Connection; - - protected MessageBuffer CreateGetPropertyMessage(string @interface, string property) - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ss", - member: "Get"); - writer.WriteString(@interface); - writer.WriteString(property); - return writer.CreateMessage(); - } - - protected MessageBuffer CreateGetAllPropertiesMessage(string @interface) - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "s", - member: "GetAll"); - writer.WriteString(@interface); - return writer.CreateMessage(); - } - - protected ValueTask WatchPropertiesChangedAsync(string @interface, - MessageValueReader> reader, Action> handler, - bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = Service.Destination, - Path = Path, - Interface = "org.freedesktop.DBus.Properties", - Member = "PropertiesChanged", - Arg0 = @interface - }; - return Connection.AddMatchAsync(rule, reader, static (ex, changes, _, hs) => - ((Action>)hs!).Invoke(ex, changes), - this, handler, emitOnCapturedContext); - } - - public ValueTask WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, - MessageValueReader reader, Action handler, bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = sender, - Path = path, - Member = signal, - Interface = @interface - }; - return Connection.AddMatchAsync(rule, reader, static (ex, arg, _, hs) => ((Action)hs!).Invoke(ex, arg), - this, handler, emitOnCapturedContext); - } - - public ValueTask WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, Action handler, - bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = sender, - Path = path, - Member = signal, - Interface = @interface - }; - return Connection.AddMatchAsync(rule, static (_, _) => null!, static (ex, _, _, hs) => ((Action)hs!).Invoke(ex), this, handler, emitOnCapturedContext); - } - - protected static ObjectPath ReadMessage_o(Message message, IBusObject _) - { - var reader = message.GetBodyReader(); - return reader.ReadObjectPath(); - } - - protected static bool ReadMessage_b(Message message, IBusObject _) - { - var reader = message.GetBodyReader(); - return reader.ReadBool(); - } - - protected static object ReadMessage_v(Message message, IBusObject _) - { - var reader = message.GetBodyReader(); - return reader.ReadVariant(); - } - - protected static (uint, uint, uint) ReadMessage_uuu(Message message, IBusObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadUInt32(); - var arg1 = reader.ReadUInt32(); - var arg2 = reader.ReadUInt32(); - return (arg0, arg1, arg2); - } - - protected static (object, uint, bool) ReadMessage_vub(Message message, IBusObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadVariant(); - var arg1 = reader.ReadUInt32(); - var arg2 = reader.ReadBool(); - return (arg0, arg1, arg2); - } - - protected static (object, uint, bool, uint) ReadMessage_vubu(Message message, IBusObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadVariant(); - var arg1 = reader.ReadUInt32(); - var arg2 = reader.ReadBool(); - var arg3 = reader.ReadUInt32(); - return (arg0, arg1, arg2, arg3); - } - - protected static (object, bool) ReadMessage_vb(Message message, IBusObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadVariant(); - var arg1 = reader.ReadBool(); - return (arg0, arg1); - } - } -} diff --git a/src/Avalonia.FreeDesktop/DBusIme/IBus/IBusX11TextInputMethod.cs b/src/Avalonia.FreeDesktop/DBusIme/IBus/IBusX11TextInputMethod.cs index f3ab8617a4..4db0d95d3c 100644 --- a/src/Avalonia.FreeDesktop/DBusIme/IBus/IBusX11TextInputMethod.cs +++ b/src/Avalonia.FreeDesktop/DBusIme/IBus/IBusX11TextInputMethod.cs @@ -9,17 +9,17 @@ namespace Avalonia.FreeDesktop.DBusIme.IBus { internal class IBusX11TextInputMethod : DBusTextInputMethodBase { - private Service? _service; - private InputContext? _context; + private OrgFreedesktopIBusService? _service; + private OrgFreedesktopIBusInputContext? _context; public IBusX11TextInputMethod(Connection connection) : base(connection, "org.freedesktop.portal.IBus") { } protected override async Task Connect(string name) { - var service = new IBusService(Connection, name); - var path = await service.CreatePortal("/org/freedesktop/IBus").CreateInputContextAsync(GetAppName()); - _context = service.CreateInputContext(path); - _service = service.CreateService(path); + var portal = new OrgFreedesktopIBusPortal(Connection, name, "/org/freedesktop/IBus"); + var path = await portal.CreateInputContextAsync(GetAppName()); + _service = new OrgFreedesktopIBusService(Connection, name, path); + _context = new OrgFreedesktopIBusInputContext(Connection, name, path); AddDisposable(await _context.WatchCommitTextAsync(OnCommitText)); AddDisposable(await _context.WatchForwardKeyEventAsync(OnForwardKey)); Enqueue(() => _context.SetCapabilitiesAsync((uint)IBusCapability.CapFocus)); diff --git a/src/Avalonia.FreeDesktop/DBusInterfaces.cs b/src/Avalonia.FreeDesktop/DBusInterfaces.cs new file mode 100644 index 0000000000..3bece27ab1 --- /dev/null +++ b/src/Avalonia.FreeDesktop/DBusInterfaces.cs @@ -0,0 +1,18 @@ +using Tmds.DBus.SourceGenerator; + +namespace Avalonia.FreeDesktop +{ + [DBusInterface("./DBusXml/DBus.xml")] + [DBusInterface("./DBusXml/StatusNotifierWatcher.xml")] + [DBusInterface("./DBusXml/com.canonical.AppMenu.Registrar.xml")] + [DBusInterface("./DBusXml/org.fcitx.Fcitx.InputContext.xml")] + [DBusInterface("./DBusXml/org.fcitx.Fcitx.InputMethod.xml")] + [DBusInterface("./DBusXml/org.fcitx.Fcitx.InputContext1.xml")] + [DBusInterface("./DBusXml/org.fcitx.Fcitx.InputMethod1.xml")] + [DBusInterface("./DBusXml/org.freedesktop.portal.FileChooser.xml")] + [DBusInterface("./DBusXml/org.freedesktop.portal.Request.xml")] + [DBusInterface("./DBusXml/org.freedesktop.IBus.Portal.xml")] + [DBusHandler("./DBusXml/DBusMenu.xml")] + [DBusHandler("./DBusXml/StatusNotifierItem.xml")] + internal class DBusInterfaces { } +} diff --git a/src/Avalonia.FreeDesktop/DBusMenu.DBus.cs b/src/Avalonia.FreeDesktop/DBusMenu.DBus.cs deleted file mode 100644 index e3928cfbb2..0000000000 --- a/src/Avalonia.FreeDesktop/DBusMenu.DBus.cs +++ /dev/null @@ -1,500 +0,0 @@ -using System; -using Tmds.DBus.Protocol; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Avalonia.FreeDesktop -{ - internal record DBusMenuProperties - { - public uint Version { get; set; } - public string TextDirection { get; set; } = default!; - public string Status { get; set; } = default!; - public string[] IconThemePath { get; set; } = default!; - } - - internal class DBusMenu : DBusMenuObject - { - private const string Interface = "com.canonical.dbusmenu"; - - public DBusMenu(DBusMenuService service, ObjectPath path) : base(service, path) { } - - public Task<(uint Revision, (int, Dictionary, object[]) Layout)> GetLayoutAsync(int parentId, int recursionDepth, string[] propertyNames) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, _) => ReadMessage_uriaesvavz(m), this); - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "iias", - member: "GetLayout"); - writer.WriteInt32(parentId); - writer.WriteInt32(recursionDepth); - writer.WriteArray(propertyNames); - return writer.CreateMessage(); - } - } - - public Task<(int, Dictionary)[]> GetGroupPropertiesAsync(int[] ids, string[] propertyNames) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, _) => ReadMessage_ariaesvz(m), this); - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "aias", - member: "GetGroupProperties"); - writer.WriteArray(ids); - writer.WriteArray(propertyNames); - return writer.CreateMessage(); - } - } - - public Task GetPropertyAsync(int id, string name) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, _) => ReadMessage_v(m), this); - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "is", - member: "GetProperty"); - writer.WriteInt32(id); - writer.WriteString(name); - return writer.CreateMessage(); - } - } - - public Task EventAsync(int id, string eventId, object data, uint timestamp) - { - return Connection.CallMethodAsync(CreateMessage()); - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "isvu", - member: "Event"); - writer.WriteInt32(id); - writer.WriteString(eventId); - writer.WriteVariant(data); - writer.WriteUInt32(timestamp); - return writer.CreateMessage(); - } - } - - public Task EventGroupAsync((int, string, object, uint)[] events) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, _) => ReadMessage_ai(m), this); - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "a(isvu)", - member: "EventGroup"); - writer.WriteArray(events); - return writer.CreateMessage(); - } - } - - public Task AboutToShowAsync(int id) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, _) => ReadMessage_b(m), this); - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "i", - member: "AboutToShow"); - writer.WriteInt32(id); - return writer.CreateMessage(); - } - } - - public Task<(int[] UpdatesNeeded, int[] IdErrors)> AboutToShowGroupAsync(int[] ids) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, _) => ReadMessage_aiai(m), this); - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "ai", - member: "AboutToShowGroup"); - writer.WriteArray(ids); - return writer.CreateMessage(); - } - } - - public ValueTask WatchItemsPropertiesUpdatedAsync(Action)[] UpdatedProps, (int, string[])[] RemovedProps)> handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "ItemsPropertiesUpdated", static (m, _) => ReadMessage_ariaesvzariasz(m), handler, emitOnCapturedContext); - - public ValueTask WatchLayoutUpdatedAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "LayoutUpdated", static (m, _) => ReadMessage_ui(m), handler, emitOnCapturedContext); - - public ValueTask WatchItemActivationRequestedAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "ItemActivationRequested", static (m, _) => ReadMessage_iu(m), handler, emitOnCapturedContext); - - public Task SetVersionAsync(uint value) - { - return Connection.CallMethodAsync(CreateMessage()); - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ssv", - member: "Set"); - writer.WriteString(Interface); - writer.WriteString("Version"); - writer.WriteSignature("u"); - writer.WriteUInt32(value); - return writer.CreateMessage(); - } - } - - public Task SetTextDirectionAsync(string value) - { - return Connection.CallMethodAsync(CreateMessage()); - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ssv", - member: "Set"); - writer.WriteString(Interface); - writer.WriteString("TextDirection"); - writer.WriteSignature("s"); - writer.WriteString(value); - return writer.CreateMessage(); - } - } - - public Task SetStatusAsync(string value) - { - return Connection.CallMethodAsync(CreateMessage()); - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ssv", - member: "Set"); - writer.WriteString(Interface); - writer.WriteString("Status"); - writer.WriteSignature("s"); - writer.WriteString(value); - return writer.CreateMessage(); - } - } - - public Task SetIconThemePathAsync(string[] value) - { - return Connection.CallMethodAsync(CreateMessage()); - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ssv", - member: "Set"); - writer.WriteString(Interface); - writer.WriteString("IconThemePath"); - writer.WriteSignature("as"); - writer.WriteArray(value); - return writer.CreateMessage(); - } - } - - public Task GetVersionAsync() - => Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "Version"), static (m, _) => ReadMessage_v_u(m), this); - - public Task GetTextDirectionAsync() - => Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "TextDirection"), static (m, _) => ReadMessage_v_s(m), this); - - public Task GetStatusAsync() - => Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "Status"), static (m, _) => ReadMessage_v_s(m), this); - - public Task GetIconThemePathAsync() - => Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "IconThemePath"), static (m, _) => ReadMessage_v_as(m), this); - - public Task GetPropertiesAsync() - { - return Connection.CallMethodAsync(CreateGetAllPropertiesMessage(Interface), static (m, _) => ReadMessage(m), this); - static DBusMenuProperties ReadMessage(Message message) - { - var reader = message.GetBodyReader(); - return ReadProperties(ref reader); - } - } - - public ValueTask WatchPropertiesChangedAsync(Action> handler, bool emitOnCapturedContext = true) - { - return base.WatchPropertiesChangedAsync(Interface, static (m, _) => ReadMessage(m), handler, emitOnCapturedContext); - static PropertyChanges ReadMessage(Message message) - { - var reader = message.GetBodyReader(); - reader.ReadString(); // interface - List changed = new(); - return new PropertyChanges(ReadProperties(ref reader, changed), changed.ToArray(), ReadInvalidated(ref reader)); - } - static string[] ReadInvalidated(ref Reader reader) - { - List? invalidated = null; - var headersEnd = reader.ReadArrayStart(DBusType.String); - while (reader.HasNext(headersEnd)) - { - invalidated ??= new List(); - var property = reader.ReadString(); - switch (property) - { - case "Version": invalidated.Add("Version"); break; - case "TextDirection": invalidated.Add("TextDirection"); break; - case "Status": invalidated.Add("Status"); break; - case "IconThemePath": invalidated.Add("IconThemePath"); break; - } - } - return invalidated?.ToArray() ?? Array.Empty(); - } - } - - private static DBusMenuProperties ReadProperties(ref Reader reader, ICollection? changedList = null) - { - var props = new DBusMenuProperties(); - var headersEnd = reader.ReadArrayStart(DBusType.Struct); - while (reader.HasNext(headersEnd)) - { - var property = reader.ReadString(); - switch (property) - { - case "Version": - reader.ReadSignature("u"); - props.Version = reader.ReadUInt32(); - changedList?.Add("Version"); - break; - case "TextDirection": - reader.ReadSignature("s"); - props.TextDirection = reader.ReadString(); - changedList?.Add("TextDirection"); - break; - case "Status": - reader.ReadSignature("s"); - props.Status = reader.ReadString(); - changedList?.Add("Status"); - break; - case "IconThemePath": - reader.ReadSignature("as"); - props.IconThemePath = reader.ReadArray(); - changedList?.Add("IconThemePath"); - break; - default: - reader.ReadVariant(); - break; - } - } - return props; - } - } - - internal class DBusMenuService - { - public Connection Connection { get; } - public string Destination { get; } - public DBusMenuService(Connection connection, string destination) - => (Connection, Destination) = (connection, destination); - public DBusMenu CreateDbusmenu(string path) => new(this, path); - } - - internal class DBusMenuObject - { - public DBusMenuService Service { get; } - public ObjectPath Path { get; } - protected Connection Connection => Service.Connection; - protected DBusMenuObject(DBusMenuService service, ObjectPath path) - => (Service, Path) = (service, path); - - protected MessageBuffer CreateGetPropertyMessage(string @interface, string property) - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ss", - member: "Get"); - writer.WriteString(@interface); - writer.WriteString(property); - return writer.CreateMessage(); - } - - protected MessageBuffer CreateGetAllPropertiesMessage(string @interface) - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "s", - member: "GetAll"); - writer.WriteString(@interface); - return writer.CreateMessage(); - } - - protected ValueTask WatchPropertiesChangedAsync(string @interface, MessageValueReader> reader, Action> handler, bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = Service.Destination, - Path = Path, - Interface = "org.freedesktop.DBus.Properties", - Member = "PropertiesChanged", - Arg0 = @interface - }; - return Connection.AddMatchAsync(rule, reader, static (ex, changes, _, hs) - => ((Action>)hs!).Invoke(ex, changes), this, handler, emitOnCapturedContext); - } - - protected ValueTask WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, MessageValueReader reader, Action handler, bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = sender, - Path = path, - Member = signal, - Interface = @interface - }; - return Connection.AddMatchAsync(rule, reader, static (ex, arg, _, hs) - => ((Action)hs!).Invoke(ex, arg), this, handler, emitOnCapturedContext); - } - - protected ValueTask WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, Action handler, bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = sender, - Path = path, - Member = signal, - Interface = @interface - }; - return Connection.AddMatchAsync(rule, static (_, _) - => null!, static (ex, _, _, hs) - => ((Action)hs!).Invoke(ex), this, handler, emitOnCapturedContext); - } - - protected static (uint, (int, Dictionary, object[])) ReadMessage_uriaesvavz(Message message) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadUInt32(); - var arg1 = reader.ReadStruct, object[]>(); - return (arg0, arg1); - } - - protected static (int, Dictionary)[] ReadMessage_ariaesvz(Message message) - { - var reader = message.GetBodyReader(); - return reader.ReadArray<(int, Dictionary)>(); - } - - protected static object ReadMessage_v(Message message) - { - var reader = message.GetBodyReader(); - return reader.ReadVariant(); - } - - protected static int[] ReadMessage_ai(Message message) - { - var reader = message.GetBodyReader(); - return reader.ReadArray(); - } - - protected static bool ReadMessage_b(Message message) - { - var reader = message.GetBodyReader(); - return reader.ReadBool(); - } - - protected static (int[], int[]) ReadMessage_aiai(Message message) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadArray(); - var arg1 = reader.ReadArray(); - return (arg0, arg1); - } - - protected static ((int, Dictionary)[], (int, string[])[]) ReadMessage_ariaesvzariasz(Message message) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadArray<(int, Dictionary)>(); - var arg1 = reader.ReadArray<(int, string[])>(); - return (arg0, arg1); - } - - protected static (uint, int) ReadMessage_ui(Message message) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadUInt32(); - var arg1 = reader.ReadInt32(); - return (arg0, arg1); - } - - protected static (int, uint) ReadMessage_iu(Message message) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadInt32(); - var arg1 = reader.ReadUInt32(); - return (arg0, arg1); - } - - protected static uint ReadMessage_v_u(Message message) - { - var reader = message.GetBodyReader(); - reader.ReadSignature("u"); - return reader.ReadUInt32(); - } - - protected static string ReadMessage_v_s(Message message) - { - var reader = message.GetBodyReader(); - reader.ReadSignature("s"); - return reader.ReadString(); - } - - protected static string[] ReadMessage_v_as(Message message) - { - var reader = message.GetBodyReader(); - reader.ReadSignature("as"); - return reader.ReadArray(); - } - } -} diff --git a/src/Avalonia.FreeDesktop/DBusMenuExporter.cs b/src/Avalonia.FreeDesktop/DBusMenuExporter.cs index 69e2eed72f..e8d4a7b6b4 100644 --- a/src/Avalonia.FreeDesktop/DBusMenuExporter.cs +++ b/src/Avalonia.FreeDesktop/DBusMenuExporter.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.Linq; -using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Controls.Platform; using Avalonia.Input; @@ -25,16 +24,15 @@ namespace Avalonia.FreeDesktop public static string GenerateDBusMenuObjPath => $"/net/avaloniaui/dbusmenu/{Guid.NewGuid():N}"; - private class DBusMenuExporterImpl : ITopLevelNativeMenuExporter, IMethodHandler, IDisposable + private class DBusMenuExporterImpl : ComCanonicalDbusmenu, ITopLevelNativeMenuExporter, IDisposable { private readonly Connection _connection; - private readonly DBusMenuProperties _dBusMenuProperties = new() { Version = 2, Status = "normal" }; private readonly Dictionary _idsToItems = new(); private readonly Dictionary _itemsToIds = new(); private readonly HashSet _menus = new(); private readonly uint _xid; private readonly bool _appMenu = true; - private Registrar? _registrar; + private ComCanonicalAppMenuRegistrar? _registrar; private NativeMenu? _menu; private bool _disposed; private uint _revision = 1; @@ -59,7 +57,40 @@ namespace Avalonia.FreeDesktop Init(); } - public string Path { get; } + public override string Path { get; } + + protected override (uint revision, (int, Dictionary, object[]) layout) OnGetLayout(int parentId, int recursionDepth, string[] propertyNames) + { + var menu = GetMenu(parentId); + var layout = GetLayout(menu.item, menu.menu, recursionDepth, propertyNames); + if (!IsNativeMenuExported) + { + IsNativeMenuExported = true; + Dispatcher.UIThread.Post(() => OnIsNativeMenuExportedChanged?.Invoke(this, EventArgs.Empty)); + } + + return (_revision, layout); + } + + protected override (int, Dictionary)[] OnGetGroupProperties(int[] ids, string[] propertyNames) => + ids.Select(id => (id, GetProperties(GetMenu(id), propertyNames))).ToArray(); + + protected override object OnGetProperty(int id, string name) => GetProperty(GetMenu(id), name) ?? 0; + + protected override void OnEvent(int id, string eventId, object data, uint timestamp) => + Dispatcher.UIThread.Post(() => HandleEvent(id, eventId, data, timestamp)); + + protected override int[] OnEventGroup((int, string, object, uint)[] events) + { + foreach (var e in events) + Dispatcher.UIThread.Post(() => HandleEvent(e.Item1, e.Item2, e.Item3, e.Item4)); + return Array.Empty(); + } + + protected override bool OnAboutToShow(int id) => false; + + protected override (int[] updatesNeeded, int[] idErrors) OnAboutToShowGroup(int[] ids) => + (Array.Empty(), Array.Empty()); private async void Init() { @@ -69,8 +100,7 @@ namespace Avalonia.FreeDesktop var services = await _connection.ListServicesAsync(); if (!services.Contains("com.canonical.AppMenu.Registrar")) return; - _registrar = new RegistrarService(_connection, "com.canonical.AppMenu.Registrar") - .CreateRegistrar("/com/canonical/AppMenu/Registrar"); + _registrar = new ComCanonicalAppMenuRegistrar(_connection, "com.canonical.AppMenu.Registrar", "/com/canonical/AppMenu/Registrar"); if (!_disposed) await _registrar.RegisterWindowAsync(_xid, Path); // It's not really important if this code succeeds, @@ -297,140 +327,6 @@ namespace Avalonia.FreeDesktop } } - public ValueTask HandleMethodAsync(MethodContext context) - { - switch (context.Request.InterfaceAsString) - { - case "com.canonical.dbusmenu": - switch (context.Request.MemberAsString, context.Request.SignatureAsString) - { - case ("GetLayout", "iias"): - { - using var writer = context.CreateReplyWriter("u(ia{sv}av)"); - var reader = context.Request.GetBodyReader(); - var parentId = reader.ReadInt32(); - var recursionDepth = reader.ReadInt32(); - var propertyNames = reader.ReadArray(); - var menu = GetMenu(parentId); - var layout = GetLayout(menu.item, menu.menu, recursionDepth, propertyNames); - writer.WriteUInt32(_revision); - writer.WriteStruct(layout); - if (!IsNativeMenuExported) - { - IsNativeMenuExported = true; - Dispatcher.UIThread.Post(() => OnIsNativeMenuExportedChanged?.Invoke(this, EventArgs.Empty)); - } - - context.Reply(writer.CreateMessage()); - break; - } - case ("GetGroupProperties", "aias"): - { - using var writer = context.CreateReplyWriter("a(ia{sv})"); - var reader = context.Request.GetBodyReader(); - var ids = reader.ReadArray(); - var propertyNames = reader.ReadArray(); - var arrayStart = writer.WriteArrayStart(DBusType.Struct); - foreach (var id in ids) - { - var item = GetMenu(id); - var props = GetProperties(item, propertyNames); - writer.WriteStruct((id, props)); - } - - writer.WriteArrayEnd(arrayStart); - context.Reply(writer.CreateMessage()); - break; - } - case ("GetProperty", "is"): - { - using var writer = context.CreateReplyWriter("v"); - var reader = context.Request.GetBodyReader(); - var id = reader.ReadInt32(); - var name = reader.ReadString(); - writer.WriteVariant(GetProperty(GetMenu(id), name) ?? 0); - context.Reply(writer.CreateMessage()); - break; - } - case ("Event", "isvu"): - { - var reader = context.Request.GetBodyReader(); - var id = reader.ReadInt32(); - var eventId = reader.ReadString(); - var data = reader.ReadVariant(); - var timestamp = reader.ReadUInt32(); - Dispatcher.UIThread.Post(() => HandleEvent(id, eventId, data, timestamp)); - break; - } - case ("EventGroup", "a(isvu)"): - { - using var writer = context.CreateReplyWriter("ai"); - var reader = context.Request.GetBodyReader(); - var events = reader.ReadArray<(int Id, string EventId, object Data, uint Timestamp)>(); - foreach (var e in events) - Dispatcher.UIThread.Post(() => HandleEvent(e.Id, e.EventId, e.Data, e.Timestamp)); - writer.WriteArray(Array.Empty()); - context.Reply(writer.CreateMessage()); - break; - } - case ("AboutToShow", "i"): - { - using var writer = context.CreateReplyWriter("b"); - writer.WriteBool(false); - context.Reply(writer.CreateMessage()); - break; - } - case ("AboutToShowGroup", "ai"): - { - using var writer = context.CreateReplyWriter("aiai"); - writer.WriteStruct((Array.Empty(), Array.Empty())); - context.Reply(writer.CreateMessage()); - break; - } - } - - break; - case "org.freedesktop.DBus.Properties": - switch (context.Request.MemberAsString, context.Request.SignatureAsString) - { - case ("Version", "u"): - { - using var writer = context.CreateReplyWriter("u"); - writer.WriteUInt32(_dBusMenuProperties.Version); - context.Reply(writer.CreateMessage()); - break; - } - case ("TextDirection", "s"): - { - using var writer = context.CreateReplyWriter("s"); - writer.WriteString(_dBusMenuProperties.TextDirection); - context.Reply(writer.CreateMessage()); - break; - } - case ("Status", "s"): - { - using var writer = context.CreateReplyWriter("s"); - writer.WriteString(_dBusMenuProperties.Status); - context.Reply(writer.CreateMessage()); - break; - } - case ("IconThemePath", "as"): - { - using var writer = context.CreateReplyWriter("as"); - writer.WriteArray(_dBusMenuProperties.IconThemePath); - context.Reply(writer.CreateMessage()); - break; - } - } - - break; - } - - return default; - } - - public bool RunMethodHandlerSynchronously(Message message) => true; - private void EmitUIntIntSignal(string member, uint arg0, int arg1) { using var writer = _connection.GetMessageWriter(); diff --git a/src/Avalonia.FreeDesktop/DBusSystemDialog.cs b/src/Avalonia.FreeDesktop/DBusSystemDialog.cs index 7d1a0bbfc4..81233f3b2f 100644 --- a/src/Avalonia.FreeDesktop/DBusSystemDialog.cs +++ b/src/Avalonia.FreeDesktop/DBusSystemDialog.cs @@ -19,18 +19,18 @@ namespace Avalonia.FreeDesktop return null; var services = await DBusHelper.Connection.ListServicesAsync(); return services.Contains("org.freedesktop.portal.Desktop", StringComparer.Ordinal) - ? new DBusSystemDialog(new DesktopService(DBusHelper.Connection, "org.freedesktop.portal.Desktop"), handle) + ? new DBusSystemDialog(DBusHelper.Connection, handle) : null; } - private readonly DesktopService _desktopService; - private readonly FileChooser _fileChooser; + private readonly Connection _connection; + private readonly OrgFreedesktopPortalFileChooser _fileChooser; private readonly IPlatformHandle _handle; - private DBusSystemDialog(DesktopService desktopService, IPlatformHandle handle) + private DBusSystemDialog(Connection connection, IPlatformHandle handle) { - _desktopService = desktopService; - _fileChooser = desktopService.CreateFileChooser("/org/freedesktop/portal/desktop"); + _connection = connection; + _fileChooser = new OrgFreedesktopPortalFileChooser(connection, "org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop"); _handle = handle; } @@ -53,7 +53,7 @@ namespace Avalonia.FreeDesktop objectPath = await _fileChooser.OpenFileAsync(parentWindow, options.Title ?? string.Empty, chooserOptions); - var request = _desktopService.CreateRequest(objectPath); + var request = new OrgFreedesktopPortalRequest(_connection, "org.freedesktop.portal.Desktop", objectPath); var tsc = new TaskCompletionSource(); using var disposable = await request.WatchResponseAsync((e, x) => { @@ -82,7 +82,7 @@ namespace Avalonia.FreeDesktop chooserOptions.Add("current_folder", Encoding.UTF8.GetBytes(currentFolder.ToString())); objectPath = await _fileChooser.SaveFileAsync(parentWindow, options.Title ?? string.Empty, chooserOptions); - var request = _desktopService.CreateRequest(objectPath); + var request = new OrgFreedesktopPortalRequest(_connection, "org.freedesktop.portal.Desktop", objectPath); var tsc = new TaskCompletionSource(); using var disposable = await request.WatchResponseAsync((e, x) => { @@ -113,7 +113,7 @@ namespace Avalonia.FreeDesktop }; var objectPath = await _fileChooser.OpenFileAsync(parentWindow, options.Title ?? string.Empty, chooserOptions); - var request = _desktopService.CreateRequest(objectPath); + var request = new OrgFreedesktopPortalRequest(_connection, "org.freedesktop.portal.Desktop", objectPath); var tsc = new TaskCompletionSource(); using var disposable = await request.WatchResponseAsync((e, x) => { diff --git a/src/Avalonia.FreeDesktop/DBusTrayIconImpl.cs b/src/Avalonia.FreeDesktop/DBusTrayIconImpl.cs index d6518f7246..215408a0e3 100644 --- a/src/Avalonia.FreeDesktop/DBusTrayIconImpl.cs +++ b/src/Avalonia.FreeDesktop/DBusTrayIconImpl.cs @@ -1,8 +1,6 @@ using System; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Threading.Tasks; using Avalonia.Controls.Platform; using Avalonia.Logging; using Avalonia.Platform; @@ -13,14 +11,15 @@ namespace Avalonia.FreeDesktop internal class DBusTrayIconImpl : ITrayIconImpl { private static int s_trayIconInstanceId; + public static readonly (int, int, byte[]) EmptyPixmap = (1, 1, new byte[] { 255, 0, 0, 0 }); private readonly ObjectPath _dbusMenuPath; private readonly Connection? _connection; - private readonly DBus? _dBus; + private readonly OrgFreedesktopDBus? _dBus; private IDisposable? _serviceWatchDisposable; private StatusNotifierItemDbusObj? _statusNotifierItemDbusObj; - private StatusNotifierWatcher? _statusNotifierWatcher; + private OrgKdeStatusNotifierWatcher? _statusNotifierWatcher; private (int, int, byte[]) _icon; private string? _sysTrayServiceName; @@ -48,7 +47,7 @@ namespace Avalonia.FreeDesktop IsActive = true; - _dBus = new DBusService(_connection, "org.freedesktop.DBus").CreateDBus("/org/freedesktop/DBus"); + _dBus = new OrgFreedesktopDBus(_connection, "org.freedesktop.DBus", "/org/freedesktop/DBus"); _dbusMenuPath = DBusMenuExporter.GenerateDBusMenuObjPath; MenuExporter = DBusMenuExporter.TryCreateDetachedNativeMenu(_dbusMenuPath, _connection); @@ -61,8 +60,7 @@ namespace Avalonia.FreeDesktop if (_connection is null || _isDisposed) return; - _statusNotifierWatcher = new StatusNotifierWatcherService(_connection, "org.kde.StatusNotifierWatcher") - .CreateStatusNotifierWatcher("/StatusNotifierWatcher"); + _statusNotifierWatcher = new OrgKdeStatusNotifierWatcher(_connection, "org.kde.StatusNotifierWatcher", "/StatusNotifierWatcher"); _serviceConnected = true; } @@ -72,7 +70,7 @@ namespace Avalonia.FreeDesktop if (!services.Contains("org.kde.StatusNotifierWatcher", StringComparer.Ordinal)) return; - _serviceWatchDisposable = await _dBus!.WatchNameOwnerChangedAsync((_, x) => OnNameChange(x.A2) ); + _serviceWatchDisposable = await _dBus!.WatchNameOwnerChangedAsync((_, x) => OnNameChange(x.Item2) ); var nameOwner = await _dBus.GetNameOwnerAsync("org.kde.StatusNotifierWatcher"); OnNameChange(nameOwner); } @@ -147,7 +145,7 @@ namespace Avalonia.FreeDesktop if (icon is null) { - _statusNotifierItemDbusObj?.SetIcon(StatusNotifierItemDbusObj.StatusNotifierItemProperties.EmptyPixmap); + _statusNotifierItemDbusObj?.SetIcon(EmptyPixmap); return; } @@ -210,27 +208,37 @@ namespace Avalonia.FreeDesktop /// /// Useful guide: https://web.archive.org/web/20210818173850/https://www.notmart.org/misc/statusnotifieritem/statusnotifieritem.html /// - internal class StatusNotifierItemDbusObj : IMethodHandler + internal class StatusNotifierItemDbusObj : OrgKdeStatusNotifierItem { private readonly Connection _connection; - private readonly StatusNotifierItemProperties _backingProperties; public StatusNotifierItemDbusObj(Connection connection, ObjectPath dbusMenuPath) { _connection = connection; - _backingProperties = new StatusNotifierItemProperties - { - Menu = dbusMenuPath, // Needs a dbus menu somehow - ToolTip = (string.Empty, Array.Empty<(int, int, byte[])>(), string.Empty, string.Empty) - }; - + BackingProperties.Menu = dbusMenuPath; + BackingProperties.ToolTip = (string.Empty, Array.Empty<(int, int, byte[])>(), string.Empty, string.Empty); + BackingProperties.IconName = string.Empty; + BackingProperties.AttentionIconName = string.Empty; + BackingProperties.AttentionIconPixmap = new []{ DBusTrayIconImpl.EmptyPixmap }; + BackingProperties.AttentionMovieName = string.Empty; + BackingProperties.IconThemePath = string.Empty; + BackingProperties.OverlayIconName = string.Empty; + BackingProperties.OverlayIconPixmap = new []{ DBusTrayIconImpl.EmptyPixmap }; InvalidateAll(); } - public string Path => "/StatusNotifierItem"; + public override string Path => "/StatusNotifierItem"; public event Action? ActivationDelegate; + protected override void OnContextMenu(int x, int y) { } + + protected override void OnActivate(int x, int y) => ActivationDelegate?.Invoke(); + + protected override void OnSecondaryActivate(int x, int y) { } + + protected override void OnScroll(int delta, string orientation) { } + public void InvalidateAll() { EmitVoidSignal("NewTitle"); @@ -238,12 +246,12 @@ namespace Avalonia.FreeDesktop EmitVoidSignal("NewAttentionIcon"); EmitVoidSignal("NewOverlayIcon"); EmitVoidSignal("NewToolTip"); - EmitStringSignal("NewStatus", _backingProperties.Status); + EmitStringSignal("NewStatus", BackingProperties.Status); } public void SetIcon((int, int, byte[]) dbusPixmap) { - _backingProperties.IconPixmap = new[] { dbusPixmap }; + BackingProperties.IconPixmap = new[] { dbusPixmap }; InvalidateAll(); } @@ -252,124 +260,14 @@ namespace Avalonia.FreeDesktop if (text is null) return; - _backingProperties.Id = text; - _backingProperties.Category = "ApplicationStatus"; - _backingProperties.Status = text; - _backingProperties.Title = text; - _backingProperties.ToolTip = (string.Empty, Array.Empty<(int, int, byte[])>(), text, string.Empty); + BackingProperties.Id = text; + BackingProperties.Category = "ApplicationStatus"; + BackingProperties.Status = text; + BackingProperties.Title = text; + BackingProperties.ToolTip = (string.Empty, Array.Empty<(int, int, byte[])>(), text, string.Empty); InvalidateAll(); } - public bool RunMethodHandlerSynchronously(Message message) => false; - - public ValueTask HandleMethodAsync(MethodContext context) - { - switch (context.Request.InterfaceAsString) - { - case "org.kde.StatusNotifierItem": - switch (context.Request.MemberAsString, context.Request.SignatureAsString) - { - case ("ContextMenu", "ii"): - break; - case ("Activate", "ii"): - ActivationDelegate?.Invoke(); - break; - case ("SecondaryActivate", "ii"): - break; - case ("Scroll", "is"): - break; - } - - break; - case "org.freedesktop.DBus.Properties": - switch (context.Request.MemberAsString, context.Request.SignatureAsString) - { - case ("Get", "ss"): - { - var reader = context.Request.GetBodyReader(); - _ = reader.ReadString(); - var member = reader.ReadString(); - switch (member) - { - case "Category": - { - using var writer = context.CreateReplyWriter("s"); - writer.WriteString(_backingProperties.Category); - context.Reply(writer.CreateMessage()); - break; - } - case "Id": - { - using var writer = context.CreateReplyWriter("s"); - writer.WriteString(_backingProperties.Id); - context.Reply(writer.CreateMessage()); - break; - } - case "Title": - { - using var writer = context.CreateReplyWriter("s"); - writer.WriteString(_backingProperties.Title); - context.Reply(writer.CreateMessage()); - break; - } - case "Status": - { - using var writer = context.CreateReplyWriter("s"); - writer.WriteString(_backingProperties.Status); - context.Reply(writer.CreateMessage()); - break; - } - case "Menu": - { - using var writer = context.CreateReplyWriter("o"); - writer.WriteObjectPath(_backingProperties.Menu); - context.Reply(writer.CreateMessage()); - break; - } - case "IconPixmap": - { - using var writer = context.CreateReplyWriter("a(iiay)"); - writer.WriteArray(_backingProperties.IconPixmap); - context.Reply(writer.CreateMessage()); - break; - } - case "ToolTip": - { - using var writer = context.CreateReplyWriter("(sa(iiay)ss)"); - writer.WriteStruct(_backingProperties.ToolTip); - context.Reply(writer.CreateMessage()); - break; - } - } - - break; - } - case ("GetAll", "s"): - { - var writer = context.CreateReplyWriter("a{sv}"); - var dict = new Dictionary - { - { "Category", _backingProperties.Category }, - { "Id", _backingProperties.Id }, - { "Title", _backingProperties.Title }, - { "Status", _backingProperties.Status }, - { "Menu", _backingProperties.Menu }, - { "IconPixmap", _backingProperties.IconPixmap }, - { "ToolTip", _backingProperties.ToolTip } - }; - - writer.WriteDictionary(dict); - context.Reply(writer.CreateMessage()); - break; - } - } - - break; - } - - return default; - } - private void EmitVoidSignal(string member) { using var writer = _connection.GetMessageWriter(); @@ -384,27 +282,5 @@ namespace Avalonia.FreeDesktop writer.WriteString(value); _connection.TrySendMessage(writer.CreateMessage()); } - - internal record StatusNotifierItemProperties - { - public string Category { get; set; } = string.Empty; - public string Id { get; set; } = string.Empty; - public string Title { get; set; } = string.Empty; - public string Status { get; set; } = string.Empty; - public int WindowId { get; set; } - public string? IconThemePath { get; set; } - public ObjectPath Menu { get; set; } - public bool ItemIsMenu { get; set; } - public string? IconName { get; set; } - public (int, int, byte[])[] IconPixmap { get; set; } = { EmptyPixmap }; - public string? OverlayIconName { get; set; } - public (int, int, byte[])[]? OverlayIconPixmap { get; set; } - public string? AttentionIconName { get; set; } - public (int, int, byte[])[]? AttentionIconPixmap { get; set; } - public string? AttentionMovieName { get; set; } - public (string, (int, int, byte[])[], string, string) ToolTip { get; set; } - - public static (int, int, byte[]) EmptyPixmap = (1, 1, new byte[] { 255, 0, 0, 0 }); - } } } diff --git a/src/Avalonia.FreeDesktop/FreeDesktopPortalDesktop.DBus.cs b/src/Avalonia.FreeDesktop/FreeDesktopPortalDesktop.DBus.cs deleted file mode 100644 index 23f1dcf0e7..0000000000 --- a/src/Avalonia.FreeDesktop/FreeDesktopPortalDesktop.DBus.cs +++ /dev/null @@ -1,938 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Threading.Tasks; -using Tmds.DBus.Protocol; - -namespace Avalonia.FreeDesktop -{ - internal record NotificationProperties - { - public uint Version { get; set; } - } - - internal class Notification : DesktopObject - { - private const string Interface = "org.freedesktop.portal.Notification"; - - public Notification(DesktopService service, ObjectPath path) : base(service, path) { } - - public Task AddNotificationAsync(string id, Dictionary notification) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "sa{sv}", - member: "AddNotification"); - writer.WriteString(id); - writer.WriteDictionary(notification); - return writer.CreateMessage(); - } - } - - public Task RemoveNotificationAsync(string id) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "RemoveNotification"); - writer.WriteString(id); - return writer.CreateMessage(); - } - } - - public ValueTask WatchActionInvokedAsync(Action handler, - bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "ActionInvoked", static (m, s) - => ReadMessage_ssav(m, (DesktopObject)s!), handler, emitOnCapturedContext); - - public Task SetVersionAsync(uint value) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ssv", - member: "Set"); - writer.WriteString(Interface); - writer.WriteString("version"); - writer.WriteSignature("u"); - writer.WriteUInt32(value); - return writer.CreateMessage(); - } - } - - public Task GetVersionAsync() - => Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "version"), static (m, s) - => ReadMessage_v_u(m, (DesktopObject)s!), this); - - public Task GetPropertiesAsync() - { - return Connection.CallMethodAsync(CreateGetAllPropertiesMessage(Interface), static (m, _) - => ReadMessage(m), this); - - static NotificationProperties ReadMessage(Message message) - { - var reader = message.GetBodyReader(); - return ReadProperties(ref reader); - } - } - - public ValueTask WatchPropertiesChangedAsync(Action> handler, - bool emitOnCapturedContext = true) - { - return base.WatchPropertiesChangedAsync(Interface, static (m, _) - => ReadMessage(m), handler, emitOnCapturedContext); - - static PropertyChanges ReadMessage(Message message) - { - var reader = message.GetBodyReader(); - reader.ReadString(); // interface - List changed = new(); - return new PropertyChanges(ReadProperties(ref reader, changed), changed.ToArray(), - ReadInvalidated(ref reader)); - } - - static string[] ReadInvalidated(ref Reader reader) - { - List? invalidated = null; - var headersEnd = reader.ReadArrayStart(DBusType.String); - while (reader.HasNext(headersEnd)) - { - invalidated ??= new List(); - var property = reader.ReadString(); - switch (property) - { - case "version": - invalidated.Add("Version"); - break; - } - } - - return invalidated?.ToArray() ?? Array.Empty(); - } - } - - private static NotificationProperties ReadProperties(ref Reader reader, ICollection? changedList = null) - { - var props = new NotificationProperties(); - var headersEnd = reader.ReadArrayStart(DBusType.Struct); - while (reader.HasNext(headersEnd)) - { - var property = reader.ReadString(); - switch (property) - { - case "version": - reader.ReadSignature("u"); - props.Version = reader.ReadUInt32(); - changedList?.Add("Version"); - break; - default: - reader.ReadVariant(); - break; - } - } - - return props; - } - } - - internal record OpenURIProperties - { - public uint Version { get; set; } - } - - internal class OpenURI : DesktopObject - { - private const string Interface = "org.freedesktop.portal.OpenURI"; - - public OpenURI(DesktopService service, ObjectPath path) : base(service, path) { } - - public Task OpenUriAsync(string parentWindow, string uri, Dictionary options) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_o(m, (DesktopObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "ssa{sv}", - member: "OpenURI"); - writer.WriteString(parentWindow); - writer.WriteString(uri); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - - public Task OpenFileAsync(string parentWindow, SafeHandle fd, Dictionary options) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_o(m, (DesktopObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "sha{sv}", - member: "OpenFile"); - writer.WriteString(parentWindow); - writer.WriteHandle(fd); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - - public Task OpenDirectoryAsync(string parentWindow, SafeHandle fd, Dictionary options) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_o(m, (DesktopObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "sha{sv}", - member: "OpenDirectory"); - writer.WriteString(parentWindow); - writer.WriteHandle(fd); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - - public Task SetVersionAsync(uint value) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ssv", - member: "Set"); - writer.WriteString(Interface); - writer.WriteString("version"); - writer.WriteSignature("u"); - writer.WriteUInt32(value); - return writer.CreateMessage(); - } - } - - public Task GetVersionAsync() - => Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "version"), static (m, s) - => ReadMessage_v_u(m, (DesktopObject)s!), this); - - public Task GetPropertiesAsync() - { - return Connection.CallMethodAsync(CreateGetAllPropertiesMessage(Interface), static (m, _) - => ReadMessage(m), this); - - static OpenURIProperties ReadMessage(Message message) - { - var reader = message.GetBodyReader(); - return ReadProperties(ref reader); - } - } - - public ValueTask WatchPropertiesChangedAsync(Action> handler, - bool emitOnCapturedContext = true) - { - return base.WatchPropertiesChangedAsync(Interface, static (m, _) - => ReadMessage(m), handler, emitOnCapturedContext); - - static PropertyChanges ReadMessage(Message message) - { - var reader = message.GetBodyReader(); - reader.ReadString(); // interface - List changed = new(); - return new PropertyChanges(ReadProperties(ref reader, changed), changed.ToArray(), ReadInvalidated(ref reader)); - } - - static string[] ReadInvalidated(ref Reader reader) - { - List? invalidated = null; - var headersEnd = reader.ReadArrayStart(DBusType.String); - while (reader.HasNext(headersEnd)) - { - invalidated ??= new List(); - var property = reader.ReadString(); - switch (property) - { - case "version": - invalidated.Add("Version"); - break; - } - } - - return invalidated?.ToArray() ?? Array.Empty(); - } - } - - private static OpenURIProperties ReadProperties(ref Reader reader, ICollection? changedList = null) - { - var props = new OpenURIProperties(); - var headersEnd = reader.ReadArrayStart(DBusType.Struct); - while (reader.HasNext(headersEnd)) - { - var property = reader.ReadString(); - switch (property) - { - case "version": - reader.ReadSignature("u"); - props.Version = reader.ReadUInt32(); - changedList?.Add("Version"); - break; - default: - reader.ReadVariant(); - break; - } - } - - return props; - } - } - - internal record DynamicLauncherProperties - { - public uint SupportedLauncherTypes { get; set; } - public uint Version { get; set; } - } - - internal class DynamicLauncher : DesktopObject - { - private const string Interface = "org.freedesktop.portal.DynamicLauncher"; - - public DynamicLauncher(DesktopService service, ObjectPath path) : base(service, path) { } - - public Task InstallAsync(string token, string desktopFileId, string desktopEntry, Dictionary options) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "sssa{sv}", - member: "Install"); - writer.WriteString(token); - writer.WriteString(desktopFileId); - writer.WriteString(desktopEntry); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - - public Task PrepareInstallAsync(string parentWindow, string name, object iconV, Dictionary options) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_o(m, (DesktopObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "ssva{sv}", - member: "PrepareInstall"); - writer.WriteString(parentWindow); - writer.WriteString(name); - writer.WriteVariant(iconV); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - - public Task RequestInstallTokenAsync(string name, object iconV, Dictionary options) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) - => ReadMessage_s(m, (DesktopObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "sva{sv}", - member: "RequestInstallToken"); - writer.WriteString(name); - writer.WriteVariant(iconV); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - - public Task UninstallAsync(string desktopFileId, Dictionary options) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "sa{sv}", - member: "Uninstall"); - writer.WriteString(desktopFileId); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - - public Task GetDesktopEntryAsync(string desktopFileId) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) - => ReadMessage_s(m, (DesktopObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "GetDesktopEntry"); - writer.WriteString(desktopFileId); - return writer.CreateMessage(); - } - } - - public Task<(object IconV, string IconFormat, uint IconSize)> GetIconAsync(string desktopFileId) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) - => ReadMessage_vsu(m, (DesktopObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "GetIcon"); - writer.WriteString(desktopFileId); - return writer.CreateMessage(); - } - } - - public Task LaunchAsync(string desktopFileId, Dictionary options) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "sa{sv}", - member: "Launch"); - writer.WriteString(desktopFileId); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - - public Task SetSupportedLauncherTypesAsync(uint value) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ssv", - member: "Set"); - writer.WriteString(Interface); - writer.WriteString("SupportedLauncherTypes"); - writer.WriteSignature("u"); - writer.WriteUInt32(value); - return writer.CreateMessage(); - } - } - - public Task SetVersionAsync(uint value) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ssv", - member: "Set"); - writer.WriteString(Interface); - writer.WriteString("version"); - writer.WriteSignature("u"); - writer.WriteUInt32(value); - return writer.CreateMessage(); - } - } - - public Task GetSupportedLauncherTypesAsync() - => Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "SupportedLauncherTypes"), static (m, s) - => ReadMessage_v_u(m, (DesktopObject)s!), this); - - public Task GetVersionAsync() - => Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "version"), static (m, s) - => ReadMessage_v_u(m, (DesktopObject)s!), this); - - public Task GetPropertiesAsync() - { - return Connection.CallMethodAsync(CreateGetAllPropertiesMessage(Interface), static (m, _) - => ReadMessage(m), this); - - static DynamicLauncherProperties ReadMessage(Message message) - { - var reader = message.GetBodyReader(); - return ReadProperties(ref reader); - } - } - - public ValueTask WatchPropertiesChangedAsync(Action> handler, - bool emitOnCapturedContext = true) - { - return base.WatchPropertiesChangedAsync(Interface, static (m, _) - => ReadMessage(m), handler, - emitOnCapturedContext); - - static PropertyChanges ReadMessage(Message message) - { - var reader = message.GetBodyReader(); - reader.ReadString(); // interface - List changed = new(); - return new PropertyChanges(ReadProperties(ref reader, changed), changed.ToArray(), - ReadInvalidated(ref reader)); - } - - static string[] ReadInvalidated(ref Reader reader) - { - List? invalidated = null; - var headersEnd = reader.ReadArrayStart(DBusType.String); - while (reader.HasNext(headersEnd)) - { - invalidated ??= new List(); - var property = reader.ReadString(); - switch (property) - { - case "SupportedLauncherTypes": - invalidated.Add("SupportedLauncherTypes"); - break; - case "version": - invalidated.Add("Version"); - break; - } - } - - return invalidated?.ToArray() ?? Array.Empty(); - } - } - - private static DynamicLauncherProperties ReadProperties(ref Reader reader, ICollection? changedList = null) - { - var props = new DynamicLauncherProperties(); - var headersEnd = reader.ReadArrayStart(DBusType.Struct); - while (reader.HasNext(headersEnd)) - { - var property = reader.ReadString(); - switch (property) - { - case "SupportedLauncherTypes": - reader.ReadSignature("u"); - props.SupportedLauncherTypes = reader.ReadUInt32(); - changedList?.Add("SupportedLauncherTypes"); - break; - case "version": - reader.ReadSignature("u"); - props.Version = reader.ReadUInt32(); - changedList?.Add("Version"); - break; - default: - reader.ReadVariant(); - break; - } - } - - return props; - } - } - - internal record FileChooserProperties - { - public uint Version { get; set; } - } - - internal class FileChooser : DesktopObject - { - private const string Interface = "org.freedesktop.portal.FileChooser"; - - public FileChooser(DesktopService service, ObjectPath path) : base(service, path) { } - - public Task OpenFileAsync(string parentWindow, string title, Dictionary options) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_o(m, (DesktopObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "ssa{sv}", - member: "OpenFile"); - writer.WriteString(parentWindow); - writer.WriteString(title); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - - public Task SaveFileAsync(string parentWindow, string title, Dictionary options) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_o(m, (DesktopObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "ssa{sv}", - member: "SaveFile"); - writer.WriteString(parentWindow); - writer.WriteString(title); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - - public Task SaveFilesAsync(string parentWindow, string title, Dictionary options) - { - return Connection.CallMethodAsync(CreateMessage(), static (m, s) => ReadMessage_o(m, (DesktopObject)s!), this); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "ssa{sv}", - member: "SaveFiles"); - writer.WriteString(parentWindow); - writer.WriteString(title); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - - public Task SetVersionAsync(uint value) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ssv", - member: "Set"); - writer.WriteString(Interface); - writer.WriteString("version"); - writer.WriteSignature("u"); - writer.WriteUInt32(value); - return writer.CreateMessage(); - } - } - - public Task GetVersionAsync() - => Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "version"), static (m, s) - => ReadMessage_v_u(m, (DesktopObject)s!), this); - - public Task GetPropertiesAsync() - { - return Connection.CallMethodAsync(CreateGetAllPropertiesMessage(Interface), static (m, _) - => ReadMessage(m), this); - - static FileChooserProperties ReadMessage(Message message) - { - var reader = message.GetBodyReader(); - return ReadProperties(ref reader); - } - } - - public ValueTask WatchPropertiesChangedAsync(Action> handler, - bool emitOnCapturedContext = true) - { - return base.WatchPropertiesChangedAsync(Interface, static (m, _) - => ReadMessage(m), handler, emitOnCapturedContext); - - static PropertyChanges ReadMessage(Message message) - { - var reader = message.GetBodyReader(); - reader.ReadString(); // interface - List changed = new(); - return new PropertyChanges(ReadProperties(ref reader, changed), changed.ToArray(), - ReadInvalidated(ref reader)); - } - - static string[] ReadInvalidated(ref Reader reader) - { - List? invalidated = null; - var headersEnd = reader.ReadArrayStart(DBusType.String); - while (reader.HasNext(headersEnd)) - { - invalidated ??= new List(); - var property = reader.ReadString(); - switch (property) - { - case "version": - invalidated.Add("Version"); - break; - } - } - - return invalidated?.ToArray() ?? Array.Empty(); - } - } - - private static FileChooserProperties ReadProperties(ref Reader reader, ICollection? changedList = null) - { - var props = new FileChooserProperties(); - var headersEnd = reader.ReadArrayStart(DBusType.Struct); - while (reader.HasNext(headersEnd)) - { - var property = reader.ReadString(); - switch (property) - { - case "version": - reader.ReadSignature("u"); - props.Version = reader.ReadUInt32(); - changedList?.Add("Version"); - break; - default: - reader.ReadVariant(); - break; - } - } - - return props; - } - } - - internal class Request : DesktopObject - { - private const string Interface = "org.freedesktop.portal.Request"; - - public Request(DesktopService service, ObjectPath path) : base(service, path) { } - - public Task CloseAsync() - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - "Close"); - return writer.CreateMessage(); - } - } - - public ValueTask WatchResponseAsync(Action results)> handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "Response", - static (m, s) => ReadMessage_uaesv(m, (DesktopObject)s!), handler, emitOnCapturedContext); - } - - internal class DesktopService - { - public DesktopService(Connection connection, string destination) - => (Connection, Destination) = (connection, destination); - - public Connection Connection { get; } - public string Destination { get; } - public Notification CreateNotification(string path) => new(this, path); - public OpenURI CreateOpenUri(string path) => new(this, path); - public DynamicLauncher CreateDynamicLauncher(string path) => new(this, path); - public FileChooser CreateFileChooser(string path) => new(this, path); - public Request CreateRequest(string path) => new(this, path); - } - - internal class DesktopObject - { - protected DesktopObject(DesktopService service, ObjectPath path) - => (Service, Path) = (service, path); - - protected DesktopService Service { get; } - protected ObjectPath Path { get; } - protected Connection Connection => Service.Connection; - - protected MessageBuffer CreateGetPropertyMessage(string @interface, string property) - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ss", - member: "Get"); - writer.WriteString(@interface); - writer.WriteString(property); - return writer.CreateMessage(); - } - - protected MessageBuffer CreateGetAllPropertiesMessage(string @interface) - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "s", - member: "GetAll"); - writer.WriteString(@interface); - return writer.CreateMessage(); - } - - protected ValueTask WatchPropertiesChangedAsync(string @interface, - MessageValueReader> reader, Action> handler, - bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = Service.Destination, - Path = Path, - Interface = "org.freedesktop.DBus.Properties", - Member = "PropertiesChanged", - Arg0 = @interface - }; - return Connection.AddMatchAsync(rule, reader, static (ex, changes, _, hs) - => ((Action>)hs!).Invoke(ex, changes), this, handler, emitOnCapturedContext); - } - - protected ValueTask WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, - MessageValueReader reader, Action handler, bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = sender, - Path = path, - Member = signal, - Interface = @interface - }; - return Connection.AddMatchAsync(rule, reader, static (ex, arg, _, hs) => - ((Action)hs!).Invoke(ex, arg), this, handler, emitOnCapturedContext); - } - - protected static ObjectPath ReadMessage_o(Message message, DesktopObject _) - { - var reader = message.GetBodyReader(); - return reader.ReadObjectPath(); - } - - protected static uint ReadMessage_v_u(Message message, DesktopObject _) - { - var reader = message.GetBodyReader(); - reader.ReadSignature("u"); - return reader.ReadUInt32(); - } - - protected static (string, string, object[]) ReadMessage_ssav(Message message, DesktopObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadString(); - var arg1 = reader.ReadString(); - var arg2 = reader.ReadArray(); - return (arg0, arg1, arg2); - } - - protected static (uint, Dictionary) ReadMessage_uaesv(Message message, DesktopObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadUInt32(); - var arg1 = reader.ReadDictionary(); - return (arg0, arg1); - } - - protected static string ReadMessage_s(Message message, DesktopObject _) - { - var reader = message.GetBodyReader(); - return reader.ReadString(); - } - - protected static (object, string, uint) ReadMessage_vsu(Message message, DesktopObject _) - { - var reader = message.GetBodyReader(); - var arg0 = reader.ReadVariant(); - var arg1 = reader.ReadString(); - var arg2 = reader.ReadUInt32(); - return (arg0, arg1, arg2); - } - } - - internal class PropertyChanges - { - public PropertyChanges(TProperties properties, string[] invalidated, string[] changed) - => (Properties, Invalidated, Changed) = (properties, invalidated, changed); - - public TProperties Properties { get; } - public string[] Invalidated { get; } - public string[] Changed { get; } - public bool HasChanged(string property) => Array.IndexOf(Changed, property) != -1; - public bool IsInvalidated(string property) => Array.IndexOf(Invalidated, property) != -1; - } -} diff --git a/src/Avalonia.FreeDesktop/StatusNotifierWatcher.DBus.cs b/src/Avalonia.FreeDesktop/StatusNotifierWatcher.DBus.cs deleted file mode 100644 index 4e6ce3bd43..0000000000 --- a/src/Avalonia.FreeDesktop/StatusNotifierWatcher.DBus.cs +++ /dev/null @@ -1,350 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Tmds.DBus.Protocol; - -namespace Avalonia.FreeDesktop -{ - internal record StatusNotifierWatcherProperties - { - public string[] RegisteredStatusNotifierItems { get; set; } = default!; - public bool IsStatusNotifierHostRegistered { get; set; } - public int ProtocolVersion { get; set; } - } - - internal class StatusNotifierWatcher : StatusNotifierWatcherObject - { - private const string Interface = "org.kde.StatusNotifierWatcher"; - - public StatusNotifierWatcher(StatusNotifierWatcherService service, ObjectPath path) : base(service, path) { } - - public Task RegisterStatusNotifierItemAsync(string service) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "RegisterStatusNotifierItem"); - writer.WriteString(service); - return writer.CreateMessage(); - } - } - - public Task RegisterStatusNotifierHostAsync(string service) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - Interface, - signature: "s", - member: "RegisterStatusNotifierHost"); - writer.WriteString(service); - return writer.CreateMessage(); - } - } - - public ValueTask WatchStatusNotifierItemRegisteredAsync(Action handler, bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "StatusNotifierItemRegistered", static (m, s) => - ReadMessage_s(m, (StatusNotifierWatcherObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchStatusNotifierItemUnregisteredAsync(Action handler, bool emitOnCapturedContext = true) - => WatchSignalAsync(Service.Destination, Interface, Path, "StatusNotifierItemUnregistered", static (m, s) - => ReadMessage_s(m, (StatusNotifierWatcherObject)s!), handler, emitOnCapturedContext); - - public ValueTask WatchStatusNotifierHostRegisteredAsync(Action handler, bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "StatusNotifierHostRegistered", handler, emitOnCapturedContext); - - public ValueTask WatchStatusNotifierHostUnregisteredAsync(Action handler, bool emitOnCapturedContext = true) => - WatchSignalAsync(Service.Destination, Interface, Path, "StatusNotifierHostUnregistered", handler, emitOnCapturedContext); - - public Task SetRegisteredStatusNotifierItemsAsync(string[] value) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ssv", - member: "Set"); - writer.WriteString(Interface); - writer.WriteString("RegisteredStatusNotifierItems"); - writer.WriteSignature("as"); - writer.WriteArray(value); - return writer.CreateMessage(); - } - } - - public Task SetIsStatusNotifierHostRegisteredAsync(bool value) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ssv", - member: "Set"); - writer.WriteString(Interface); - writer.WriteString("IsStatusNotifierHostRegistered"); - writer.WriteSignature("b"); - writer.WriteBool(value); - return writer.CreateMessage(); - } - } - - public Task SetProtocolVersionAsync(int value) - { - return Connection.CallMethodAsync(CreateMessage()); - - MessageBuffer CreateMessage() - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ssv", - member: "Set"); - writer.WriteString(Interface); - writer.WriteString("ProtocolVersion"); - writer.WriteSignature("i"); - writer.WriteInt32(value); - return writer.CreateMessage(); - } - } - - public Task GetRegisteredStatusNotifierItemsAsync() => - Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "RegisteredStatusNotifierItems"), static (m, s) - => ReadMessage_v_as(m, (StatusNotifierWatcherObject)s!), this); - - public Task GetIsStatusNotifierHostRegisteredAsync() => - Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "IsStatusNotifierHostRegistered"), static (m, s) => - ReadMessage_v_b(m, (StatusNotifierWatcherObject)s!), this); - - public Task GetProtocolVersionAsync() => - Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "ProtocolVersion"), static (m, s) - => ReadMessage_v_i(m, (StatusNotifierWatcherObject)s!), this); - - public Task GetPropertiesAsync() - { - return Connection.CallMethodAsync(CreateGetAllPropertiesMessage(Interface), static (m, _) - => ReadMessage(m), this); - - static StatusNotifierWatcherProperties ReadMessage(Message message) - { - var reader = message.GetBodyReader(); - return ReadProperties(ref reader); - } - } - - public ValueTask WatchPropertiesChangedAsync(Action> handler, bool emitOnCapturedContext = true) - { - return base.WatchPropertiesChangedAsync(Interface, static (m, _) => ReadMessage(m), handler, emitOnCapturedContext); - - static PropertyChanges ReadMessage(Message message) - { - var reader = message.GetBodyReader(); - reader.ReadString(); // interface - List changed = new(); - return new PropertyChanges(ReadProperties(ref reader, changed), changed.ToArray(), - ReadInvalidated(ref reader)); - } - - static string[] ReadInvalidated(ref Reader reader) - { - List? invalidated = null; - var headersEnd = reader.ReadArrayStart(DBusType.String); - while (reader.HasNext(headersEnd)) - { - invalidated ??= new List(); - var property = reader.ReadString(); - switch (property) - { - case "RegisteredStatusNotifierItems": - invalidated.Add("RegisteredStatusNotifierItems"); - break; - case "IsStatusNotifierHostRegistered": - invalidated.Add("IsStatusNotifierHostRegistered"); - break; - case "ProtocolVersion": - invalidated.Add("ProtocolVersion"); - break; - } - } - - return invalidated?.ToArray() ?? Array.Empty(); - } - } - - private static StatusNotifierWatcherProperties ReadProperties(ref Reader reader, ICollection? changedList = null) - { - var props = new StatusNotifierWatcherProperties(); - var headersEnd = reader.ReadArrayStart(DBusType.Struct); - while (reader.HasNext(headersEnd)) - { - var property = reader.ReadString(); - switch (property) - { - case "RegisteredStatusNotifierItems": - reader.ReadSignature("as"); - props.RegisteredStatusNotifierItems = reader.ReadArray(); - changedList?.Add("RegisteredStatusNotifierItems"); - break; - case "IsStatusNotifierHostRegistered": - reader.ReadSignature("b"); - props.IsStatusNotifierHostRegistered = reader.ReadBool(); - changedList?.Add("IsStatusNotifierHostRegistered"); - break; - case "ProtocolVersion": - reader.ReadSignature("i"); - props.ProtocolVersion = reader.ReadInt32(); - changedList?.Add("ProtocolVersion"); - break; - default: - reader.ReadVariant(); - break; - } - } - - return props; - } - } - - internal class StatusNotifierWatcherService - { - public StatusNotifierWatcherService(Connection connection, string destination) => (Connection, Destination) = (connection, destination); - - public Connection Connection { get; } - public string Destination { get; } - - public StatusNotifierWatcher CreateStatusNotifierWatcher(string path) => new(this, path); - } - - internal class StatusNotifierWatcherObject - { - protected StatusNotifierWatcherObject(StatusNotifierWatcherService service, ObjectPath path) - { - (Service, Path) = (service, path); - } - - protected StatusNotifierWatcherService Service { get; } - protected ObjectPath Path { get; } - protected Connection Connection => Service.Connection; - - protected MessageBuffer CreateGetPropertyMessage(string @interface, string property) - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "ss", - member: "Get"); - writer.WriteString(@interface); - writer.WriteString(property); - return writer.CreateMessage(); - } - - protected MessageBuffer CreateGetAllPropertiesMessage(string @interface) - { - using var writer = Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - Service.Destination, - Path, - "org.freedesktop.DBus.Properties", - signature: "s", - member: "GetAll"); - writer.WriteString(@interface); - return writer.CreateMessage(); - } - - protected ValueTask WatchPropertiesChangedAsync(string @interface, MessageValueReader> reader, Action> handler, bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = Service.Destination, - Path = Path, - Interface = "org.freedesktop.DBus.Properties", - Member = "PropertiesChanged", - Arg0 = @interface - }; - return Connection.AddMatchAsync(rule, reader, static (ex, changes, _, hs) => - ((Action>)hs!).Invoke(ex, changes), this, handler, emitOnCapturedContext); - } - - protected ValueTask WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, MessageValueReader reader, Action handler, bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = sender, - Path = path, - Member = signal, - Interface = @interface - }; - return Connection.AddMatchAsync(rule, reader, static (ex, arg, _, hs) - => ((Action)hs!).Invoke(ex, arg), this, handler, emitOnCapturedContext); - } - - protected ValueTask WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, Action handler, bool emitOnCapturedContext) - { - var rule = new MatchRule - { - Type = MessageType.Signal, - Sender = sender, - Path = path, - Member = signal, - Interface = @interface - }; - return Connection.AddMatchAsync(rule, static (_, _) - => null!, static (Exception? ex, object _, object? _, object? hs) - => ((Action)hs!).Invoke(ex), this, handler, emitOnCapturedContext); - } - - protected static string ReadMessage_s(Message message, StatusNotifierWatcherObject _) - { - var reader = message.GetBodyReader(); - return reader.ReadString(); - } - - protected static string[] ReadMessage_v_as(Message message, StatusNotifierWatcherObject _) - { - var reader = message.GetBodyReader(); - reader.ReadSignature("as"); - return reader.ReadArray(); - } - - protected static bool ReadMessage_v_b(Message message, StatusNotifierWatcherObject _) - { - var reader = message.GetBodyReader(); - reader.ReadSignature("b"); - return reader.ReadBool(); - } - - protected static int ReadMessage_v_i(Message message, StatusNotifierWatcherObject _) - { - var reader = message.GetBodyReader(); - reader.ReadSignature("i"); - return reader.ReadInt32(); - } - } -} diff --git a/src/tools/Tmds.DBus.SourceGenerator b/src/tools/Tmds.DBus.SourceGenerator new file mode 160000 index 0000000000..1cf4faba30 --- /dev/null +++ b/src/tools/Tmds.DBus.SourceGenerator @@ -0,0 +1 @@ +Subproject commit 1cf4faba30741f799a33313a2842cf70eeb6c67e