29 changed files with 4272 additions and 907 deletions
@ -0,0 +1,176 @@ |
|||||
|
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(), (Message m, object? 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 Registrar(this, path); |
||||
|
} |
||||
|
|
||||
|
internal class AppMenuRegistrarObject |
||||
|
{ |
||||
|
protected AppMenuRegistrarObject(RegistrarService service, ObjectPath path) |
||||
|
=> (Service, Path) = (service, path); |
||||
|
|
||||
|
public RegistrarService 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<IDisposable> WatchPropertiesChangedAsync<TProperties>(string @interface, |
||||
|
MessageValueReader<PropertyChanges<TProperties>> reader, Action<Exception?, PropertyChanges<TProperties>> 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, |
||||
|
(Exception? ex, PropertyChanges<TProperties> changes, object? rs, object? hs) => |
||||
|
((Action<Exception?, PropertyChanges<TProperties>>)hs!).Invoke(ex, changes), |
||||
|
this, handler, emitOnCapturedContext); |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchSignalAsync<TArg>(string sender, string @interface, ObjectPath path, string signal, |
||||
|
MessageValueReader<TArg> reader, Action<Exception?, TArg> handler, bool emitOnCapturedContext) |
||||
|
{ |
||||
|
var rule = new MatchRule |
||||
|
{ |
||||
|
Type = MessageType.Signal, |
||||
|
Sender = sender, |
||||
|
Path = path, |
||||
|
Member = signal, |
||||
|
Interface = @interface |
||||
|
}; |
||||
|
return Connection.AddMatchAsync(rule, reader, |
||||
|
(Exception? ex, TArg arg, object? rs, object? hs) => ((Action<Exception?, TArg>)hs!).Invoke(ex, arg), |
||||
|
this, handler, emitOnCapturedContext); |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, Action<Exception?> handler, |
||||
|
bool emitOnCapturedContext) |
||||
|
{ |
||||
|
var rule = new MatchRule |
||||
|
{ |
||||
|
Type = MessageType.Signal, |
||||
|
Sender = sender, |
||||
|
Path = path, |
||||
|
Member = signal, |
||||
|
Interface = @interface |
||||
|
}; |
||||
|
return Connection.AddMatchAsync<object>(rule, (Message message, object? state) => null!, |
||||
|
(Exception? ex, object v, object? rs, object? hs) => ((Action<Exception?>)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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,643 @@ |
|||||
|
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<string> 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<uint> 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<uint> 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<uint> 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<string, string> 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<bool> 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<string[]> 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<string[]> 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<string> 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<string[]> 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<uint> 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<uint> 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<byte[]> 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<byte[]> 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<string> 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<Dictionary<string, object>> 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<IDisposable> WatchNameOwnerChangedAsync(Action<Exception?, (string A0, string A1, string A2)> handler, bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "NameOwnerChanged", static (m, s) => |
||||
|
ReadMessage_sss(m, (DBusObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchNameLostAsync(Action<Exception?, string> handler, bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "NameLost", static (m, s) => |
||||
|
ReadMessage_s(m, (DBusObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchNameAcquiredAsync(Action<Exception?, string> 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<string[]> GetFeaturesAsync() => |
||||
|
Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "Features"), static (m, s) => |
||||
|
ReadMessage_v_as(m, (DBusObject)s!), this); |
||||
|
|
||||
|
public Task<string[]> GetInterfacesAsync() => |
||||
|
Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "Interfaces"), static (m, s) => |
||||
|
ReadMessage_v_as(m, (DBusObject)s!), this); |
||||
|
|
||||
|
public Task<DBusProperties> GetPropertiesAsync() |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateGetAllPropertiesMessage(Interface), static (m, s) => |
||||
|
ReadMessage(m, (DBusObject)s!), this); |
||||
|
|
||||
|
static DBusProperties ReadMessage(Message message, DBusObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
return ReadProperties(ref reader); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchPropertiesChangedAsync(Action<Exception?, PropertyChanges<DBusProperties>> handler, bool emitOnCapturedContext = true) |
||||
|
{ |
||||
|
return base.WatchPropertiesChangedAsync(Interface, static (m, s) => |
||||
|
ReadMessage(m, (DBusObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
static PropertyChanges<DBusProperties> ReadMessage(Message message, DBusObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
reader.ReadString(); // interface
|
||||
|
List<string> changed = new(); |
||||
|
return new PropertyChanges<DBusProperties>(ReadProperties(ref reader, changed), changed.ToArray(), ReadInvalidated(ref reader)); |
||||
|
} |
||||
|
|
||||
|
static string[] ReadInvalidated(ref Reader reader) |
||||
|
{ |
||||
|
List<string>? invalidated = null; |
||||
|
var headersEnd = reader.ReadArrayStart(DBusType.String); |
||||
|
while (reader.HasNext(headersEnd)) |
||||
|
{ |
||||
|
invalidated ??= new List<string>(); |
||||
|
var property = reader.ReadString(); |
||||
|
switch (property) |
||||
|
{ |
||||
|
case "Features": |
||||
|
invalidated.Add("Features"); |
||||
|
break; |
||||
|
case "Interfaces": |
||||
|
invalidated.Add("Interfaces"); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return invalidated?.ToArray() ?? Array.Empty<string>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static DBusProperties ReadProperties(ref Reader reader, List<string>? 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<string>(); |
||||
|
changedList?.Add("Features"); |
||||
|
break; |
||||
|
case "Interfaces": |
||||
|
reader.ReadSignature("as"); |
||||
|
props.Interfaces = reader.ReadArray<string>(); |
||||
|
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<IDisposable> WatchPropertiesChangedAsync<TProperties>(string @interface, |
||||
|
MessageValueReader<PropertyChanges<TProperties>> reader, Action<Exception?, PropertyChanges<TProperties>> 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<Exception?, PropertyChanges<TProperties>>)hs!).Invoke(ex, changes), this, handler, emitOnCapturedContext); |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchSignalAsync<TArg>(string sender, string @interface, ObjectPath path, string signal, |
||||
|
MessageValueReader<TArg> reader, Action<Exception?, TArg> 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<Exception?, TArg>)hs!).Invoke(ex, arg), this, handler, emitOnCapturedContext); |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, Action<Exception?> handler, |
||||
|
bool emitOnCapturedContext) |
||||
|
{ |
||||
|
var rule = new MatchRule |
||||
|
{ |
||||
|
Type = MessageType.Signal, |
||||
|
Sender = sender, |
||||
|
Path = path, |
||||
|
Member = signal, |
||||
|
Interface = @interface |
||||
|
}; |
||||
|
return Connection.AddMatchAsync<object>(rule, static (_, _) => null!, static (ex, _, _, hs) => |
||||
|
((Action<Exception?>)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<string>(); |
||||
|
} |
||||
|
|
||||
|
protected static byte[] ReadMessage_ay(Message message, DBusObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
return reader.ReadArray<byte>(); |
||||
|
} |
||||
|
|
||||
|
protected static Dictionary<string, object> ReadMessage_aesv(Message message, DBusObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
return reader.ReadDictionary<string, object>(); |
||||
|
} |
||||
|
|
||||
|
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<string>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,32 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Runtime.CompilerServices; |
|
||||
using System.Threading.Tasks; |
|
||||
using Tmds.DBus; |
|
||||
|
|
||||
[assembly: InternalsVisibleTo(Connection.DynamicAssemblyName)] |
|
||||
namespace Avalonia.FreeDesktop |
|
||||
{ |
|
||||
[DBusInterface("org.freedesktop.portal.FileChooser")] |
|
||||
internal interface IFileChooser : IDBusObject |
|
||||
{ |
|
||||
Task<ObjectPath> OpenFileAsync(string ParentWindow, string Title, IDictionary<string, object> Options); |
|
||||
Task<ObjectPath> SaveFileAsync(string ParentWindow, string Title, IDictionary<string, object> Options); |
|
||||
Task<ObjectPath> SaveFilesAsync(string ParentWindow, string Title, IDictionary<string, object> Options); |
|
||||
Task<T> GetAsync<T>(string prop); |
|
||||
Task<FileChooserProperties> GetAllAsync(); |
|
||||
Task SetAsync(string prop, object val); |
|
||||
Task<IDisposable> WatchPropertiesAsync(Action<PropertyChanges> handler); |
|
||||
} |
|
||||
|
|
||||
[Dictionary] |
|
||||
internal class FileChooserProperties |
|
||||
{ |
|
||||
public uint Version { get; set; } |
|
||||
} |
|
||||
|
|
||||
internal static class FileChooserExtensions |
|
||||
{ |
|
||||
public static Task<uint> GetVersionAsync(this IFileChooser o) => o.GetAsync<uint>("version"); |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,627 @@ |
|||||
|
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<int> 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<IDisposable> WatchCommitStringAsync(Action<Exception?, string> handler, bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "CommitString", static (m, s) => |
||||
|
ReadMessage_s(m, (FcitxObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchCurrentIMAsync(Action<Exception?, (string Name, string UniqueName, string LangCode)> handler, |
||||
|
bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "CurrentIM", static (m, s) => |
||||
|
ReadMessage_sss(m, (FcitxObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchUpdateFormattedPreeditAsync(Action<Exception?, ((string, int)[] Str, int Cursorpos)> handler, |
||||
|
bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "UpdateFormattedPreedit", static (m, s) => |
||||
|
ReadMessage_arsizi(m, (FcitxObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchForwardKeyAsync(Action<Exception?, (uint Keyval, uint State, int Type)> handler, |
||||
|
bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "ForwardKey", static (m, s) => |
||||
|
ReadMessage_uui(m, (FcitxObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchDeleteSurroundingTextAsync(Action<Exception?, (int Offset, uint Nchar)> 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<bool> 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<IDisposable> WatchCommitStringAsync(Action<Exception?, string> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "CommitString", static (m, s) => |
||||
|
ReadMessage_s(m, (FcitxObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchCurrentIMAsync(Action<Exception?, (string Name, string UniqueName, string LangCode)> handler, |
||||
|
bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "CurrentIM", static (m, s) => |
||||
|
ReadMessage_sss(m, (FcitxObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchUpdateFormattedPreeditAsync(Action<Exception?, ((string, int)[] Str, int Cursorpos)> handler, |
||||
|
bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "UpdateFormattedPreedit", static (m, s) => |
||||
|
ReadMessage_arsizi(m, (FcitxObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchForwardKeyAsync(Action<Exception?, (uint Keyval, uint State, bool Type)> handler, |
||||
|
bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "ForwardKey", static (m, s) => |
||||
|
ReadMessage_uub(m, (FcitxObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchDeleteSurroundingTextAsync(Action<Exception?, (int Offset, uint Nchar)> 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<IDisposable> WatchPropertiesChangedAsync<TProperties>(string @interface, |
||||
|
MessageValueReader<PropertyChanges<TProperties>> reader, Action<Exception?, PropertyChanges<TProperties>> 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<Exception?, PropertyChanges<TProperties>>)hs!).Invoke(ex, changes), |
||||
|
this, handler, emitOnCapturedContext); |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchSignalAsync<TArg>(string sender, string @interface, ObjectPath path, string signal, |
||||
|
MessageValueReader<TArg> reader, Action<Exception?, TArg> 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<Exception?, TArg>)hs!).Invoke(ex, arg), this, handler, emitOnCapturedContext); |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, Action<Exception?> handler, |
||||
|
bool emitOnCapturedContext) |
||||
|
{ |
||||
|
var rule = new MatchRule |
||||
|
{ |
||||
|
Type = MessageType.Signal, |
||||
|
Sender = sender, |
||||
|
Path = path, |
||||
|
Member = signal, |
||||
|
Interface = @interface |
||||
|
}; |
||||
|
return Connection.AddMatchAsync<object>(rule, static (_, _) => |
||||
|
null!, static (ex, _, _, hs) => |
||||
|
((Action<Exception?>)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<byte>(); |
||||
|
return (arg0, arg1); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,69 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Runtime.CompilerServices; |
|
||||
using System.Threading.Tasks; |
|
||||
using Tmds.DBus; |
|
||||
|
|
||||
[assembly: InternalsVisibleTo(Tmds.DBus.Connection.DynamicAssemblyName)] |
|
||||
namespace Avalonia.FreeDesktop.DBusIme.Fcitx |
|
||||
{ |
|
||||
[DBusInterface("org.fcitx.Fcitx.InputMethod")] |
|
||||
interface IFcitxInputMethod : IDBusObject |
|
||||
{ |
|
||||
Task<(int icid, bool enable, uint keyval1, uint state1, uint keyval2, uint state2)> CreateICv3Async( |
|
||||
string Appname, int Pid); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
[DBusInterface("org.fcitx.Fcitx.InputContext")] |
|
||||
interface IFcitxInputContext : IDBusObject |
|
||||
{ |
|
||||
Task EnableICAsync(); |
|
||||
Task CloseICAsync(); |
|
||||
Task FocusInAsync(); |
|
||||
Task FocusOutAsync(); |
|
||||
Task ResetAsync(); |
|
||||
Task MouseEventAsync(int X); |
|
||||
Task SetCursorLocationAsync(int X, int Y); |
|
||||
Task SetCursorRectAsync(int X, int Y, int W, int H); |
|
||||
Task SetCapacityAsync(uint Caps); |
|
||||
Task SetSurroundingTextAsync(string Text, uint Cursor, uint Anchor); |
|
||||
Task SetSurroundingTextPositionAsync(uint Cursor, uint Anchor); |
|
||||
Task DestroyICAsync(); |
|
||||
Task<int> ProcessKeyEventAsync(uint Keyval, uint Keycode, uint State, int Type, uint Time); |
|
||||
Task<IDisposable> WatchEnableIMAsync(Action handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchCloseIMAsync(Action handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable?> WatchCommitStringAsync(Action<string> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchCurrentIMAsync(Action<(string name, string uniqueName, string langCode)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchUpdatePreeditAsync(Action<(string str, int cursorpos)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchUpdateFormattedPreeditAsync(Action<((string, int)[] str, int cursorpos)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchUpdateClientSideUIAsync(Action<(string auxup, string auxdown, string preedit, string candidateword, string imname, int cursorpos)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable?> WatchForwardKeyAsync(Action<(uint keyval, uint state, int type)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchDeleteSurroundingTextAsync(Action<(int offset, uint nchar)> handler, Action<Exception>? onError = null); |
|
||||
} |
|
||||
|
|
||||
[DBusInterface("org.fcitx.Fcitx.InputContext1")] |
|
||||
interface IFcitxInputContext1 : IDBusObject |
|
||||
{ |
|
||||
Task FocusInAsync(); |
|
||||
Task FocusOutAsync(); |
|
||||
Task ResetAsync(); |
|
||||
Task SetCursorRectAsync(int X, int Y, int W, int H); |
|
||||
Task SetCapabilityAsync(ulong Caps); |
|
||||
Task SetSurroundingTextAsync(string Text, uint Cursor, uint Anchor); |
|
||||
Task SetSurroundingTextPositionAsync(uint Cursor, uint Anchor); |
|
||||
Task DestroyICAsync(); |
|
||||
Task<bool> ProcessKeyEventAsync(uint Keyval, uint Keycode, uint State, bool Type, uint Time); |
|
||||
Task<IDisposable?> WatchCommitStringAsync(Action<string> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchCurrentIMAsync(Action<(string name, string uniqueName, string langCode)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchUpdateFormattedPreeditAsync(Action<((string, int)[] str, int cursorpos)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable?> WatchForwardKeyAsync(Action<(uint keyval, uint state, bool type)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchDeleteSurroundingTextAsync(Action<(int offset, uint nchar)> handler, Action<Exception>? onError = null); |
|
||||
} |
|
||||
|
|
||||
[DBusInterface("org.fcitx.Fcitx.InputMethod1")] |
|
||||
interface IFcitxInputMethod1 : IDBusObject |
|
||||
{ |
|
||||
Task<(ObjectPath path, byte[] data)> CreateInputContextAsync((string, string)[] arg0); |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,513 @@ |
|||||
|
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<ObjectPath> 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<bool> 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<object> 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<IDisposable> WatchCommitTextAsync(Action<Exception?, object> handler, bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "CommitText", static (m, s) => |
||||
|
ReadMessage_v(m, (IBusObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchForwardKeyEventAsync(Action<Exception?, (uint Keyval, uint Keycode, uint State)> handler, |
||||
|
bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "ForwardKeyEvent", static (m, s) => |
||||
|
ReadMessage_uuu(m, (IBusObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchUpdatePreeditTextAsync(Action<Exception?, (object Text, uint CursorPos, bool Visible)> handler, |
||||
|
bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "UpdatePreeditText", static (m, s) => |
||||
|
ReadMessage_vub(m, (IBusObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchUpdatePreeditTextWithModeAsync( |
||||
|
Action<Exception?, (object Text, uint CursorPos, bool Visible, uint Mode)> handler, bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "UpdatePreeditTextWithMode", static (m, s) => |
||||
|
ReadMessage_vubu(m, (IBusObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchShowPreeditTextAsync(Action<Exception?> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "ShowPreeditText", handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchHidePreeditTextAsync(Action<Exception?> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "HidePreeditText", handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchUpdateAuxiliaryTextAsync(Action<Exception?, (object Text, bool Visible)> handler, |
||||
|
bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "UpdateAuxiliaryText", static (m, s) => |
||||
|
ReadMessage_vb(m, (IBusObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchShowAuxiliaryTextAsync(Action<Exception?> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "ShowAuxiliaryText", handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchHideAuxiliaryTextAsync(Action<Exception?> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "HideAuxiliaryText", handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchUpdateLookupTableAsync(Action<Exception?, (object Table, bool Visible)> handler, |
||||
|
bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "UpdateLookupTable", static (m, s) => |
||||
|
ReadMessage_vb(m, (IBusObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchShowLookupTableAsync(Action<Exception?> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "ShowLookupTable", handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchHideLookupTableAsync(Action<Exception?> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "HideLookupTable", handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchPageUpLookupTableAsync(Action<Exception?> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "PageUpLookupTable", handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchPageDownLookupTableAsync(Action<Exception?> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "PageDownLookupTable", handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchCursorUpLookupTableAsync(Action<Exception?> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "CursorUpLookupTable", handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchCursorDownLookupTableAsync(Action<Exception?> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "CursorDownLookupTable", handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchRegisterPropertiesAsync(Action<Exception?, object> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "RegisterProperties", static (m, s) => ReadMessage_v(m, (IBusObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchUpdatePropertyAsync(Action<Exception?, object> 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<IDisposable> WatchPropertiesChangedAsync<TProperties>(string @interface, |
||||
|
MessageValueReader<PropertyChanges<TProperties>> reader, Action<Exception?, PropertyChanges<TProperties>> 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<Exception?, PropertyChanges<TProperties>>)hs!).Invoke(ex, changes), |
||||
|
this, handler, emitOnCapturedContext); |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchSignalAsync<TArg>(string sender, string @interface, ObjectPath path, string signal, |
||||
|
MessageValueReader<TArg> reader, Action<Exception?, TArg> 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<Exception?, TArg>)hs!).Invoke(ex, arg), |
||||
|
this, handler, emitOnCapturedContext); |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, Action<Exception?> handler, |
||||
|
bool emitOnCapturedContext) |
||||
|
{ |
||||
|
var rule = new MatchRule |
||||
|
{ |
||||
|
Type = MessageType.Signal, |
||||
|
Sender = sender, |
||||
|
Path = path, |
||||
|
Member = signal, |
||||
|
Interface = @interface |
||||
|
}; |
||||
|
return Connection.AddMatchAsync<object>(rule, static (_, _) => null!, static (ex, _, _, hs) => ((Action<Exception?>)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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,52 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Runtime.CompilerServices; |
|
||||
using System.Runtime.InteropServices; |
|
||||
using System.Threading.Tasks; |
|
||||
using Tmds.DBus; |
|
||||
|
|
||||
[assembly: InternalsVisibleTo(Connection.DynamicAssemblyName)] |
|
||||
namespace Avalonia.FreeDesktop.DBusIme.IBus |
|
||||
{ |
|
||||
[DBusInterface("org.freedesktop.IBus.InputContext")] |
|
||||
interface IIBusInputContext : IDBusObject |
|
||||
{ |
|
||||
Task<bool> ProcessKeyEventAsync(uint Keyval, uint Keycode, uint State); |
|
||||
Task SetCursorLocationAsync(int X, int Y, int W, int H); |
|
||||
Task FocusInAsync(); |
|
||||
Task FocusOutAsync(); |
|
||||
Task ResetAsync(); |
|
||||
Task SetCapabilitiesAsync(uint Caps); |
|
||||
Task PropertyActivateAsync(string Name, int State); |
|
||||
Task SetEngineAsync(string Name); |
|
||||
Task<object> GetEngineAsync(); |
|
||||
Task DestroyAsync(); |
|
||||
Task SetSurroundingTextAsync(object Text, uint CursorPos, uint AnchorPos); |
|
||||
Task<IDisposable> WatchCommitTextAsync(Action<object> cb, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchForwardKeyEventAsync(Action<(uint keyval, uint keycode, uint state)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchRequireSurroundingTextAsync(Action handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchDeleteSurroundingTextAsync(Action<(int offset, uint nchars)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchUpdatePreeditTextAsync(Action<(object text, uint cursorPos, bool visible)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchShowPreeditTextAsync(Action handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchHidePreeditTextAsync(Action handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchUpdateAuxiliaryTextAsync(Action<(object text, bool visible)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchShowAuxiliaryTextAsync(Action handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchHideAuxiliaryTextAsync(Action handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchUpdateLookupTableAsync(Action<(object table, bool visible)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchShowLookupTableAsync(Action handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchHideLookupTableAsync(Action handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchPageUpLookupTableAsync(Action handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchPageDownLookupTableAsync(Action handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchCursorUpLookupTableAsync(Action handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchCursorDownLookupTableAsync(Action handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchRegisterPropertiesAsync(Action<object> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchUpdatePropertyAsync(Action<object> handler, Action<Exception>? onError = null); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
[DBusInterface("org.freedesktop.IBus.Portal")] |
|
||||
interface IIBusPortal : IDBusObject |
|
||||
{ |
|
||||
Task<ObjectPath> CreateInputContextAsync(string Name); |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,463 @@ |
|||||
|
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<string, object>, object[]) Layout)> GetLayoutAsync(int parentId, int recursionDepth, string[] propertyNames) |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateMessage(), (m, s) => ReadMessage_uriaesvavz(m, (DBusMenuObject)s!), 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<string, object>)[]> GetGroupPropertiesAsync(int[] ids, string[] propertyNames) |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateMessage(), (m, s) => ReadMessage_ariaesvz(m, (DBusMenuObject)s!), 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<object> GetPropertyAsync(int id, string name) |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateMessage(), (m, s) => ReadMessage_v(m, (DBusMenuObject)s!), 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<int[]> EventGroupAsync((int, string, object, uint)[] events) |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateMessage(), (m, s) => ReadMessage_ai(m, (DBusMenuObject)s!), 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<bool> AboutToShowAsync(int id) |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateMessage(), (m, s) => ReadMessage_b(m, (DBusMenuObject)s!), 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(), (m, s) => ReadMessage_aiai(m, (DBusMenuObject)s!), 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<IDisposable> WatchItemsPropertiesUpdatedAsync(Action<Exception?, ((int, Dictionary<string, object>)[] UpdatedProps, (int, string[])[] RemovedProps)> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "ItemsPropertiesUpdated", (m, s) => ReadMessage_ariaesvzariasz(m, (DBusMenuObject)s!), handler, emitOnCapturedContext); |
||||
|
public ValueTask<IDisposable> WatchLayoutUpdatedAsync(Action<Exception?, (uint Revision, int Parent)> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "LayoutUpdated", (m, s) => ReadMessage_ui(m, (DBusMenuObject)s!), handler, emitOnCapturedContext); |
||||
|
public ValueTask<IDisposable> WatchItemActivationRequestedAsync(Action<Exception?, (int Id, uint Timestamp)> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "ItemActivationRequested", (m, s) => ReadMessage_iu(m, (DBusMenuObject)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 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<uint> GetVersionAsync() |
||||
|
=> Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "Version"), (m, s) => ReadMessage_v_u(m, (DBusMenuObject)s!), this); |
||||
|
public Task<string> GetTextDirectionAsync() |
||||
|
=> Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "TextDirection"), (m, s) => ReadMessage_v_s(m, (DBusMenuObject)s!), this); |
||||
|
public Task<string> GetStatusAsync() |
||||
|
=> Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "Status"), (m, s) => ReadMessage_v_s(m, (DBusMenuObject)s!), this); |
||||
|
public Task<string[]> GetIconThemePathAsync() |
||||
|
=> Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "IconThemePath"), (m, s) => ReadMessage_v_as(m, (DBusMenuObject)s!), this); |
||||
|
public Task<DBusMenuProperties> GetPropertiesAsync() |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateGetAllPropertiesMessage(Interface), (m, s) => ReadMessage(m, (DBusMenuObject)s!), this); |
||||
|
static DBusMenuProperties ReadMessage(Message message, DBusMenuObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
return ReadProperties(ref reader); |
||||
|
} |
||||
|
} |
||||
|
public ValueTask<IDisposable> WatchPropertiesChangedAsync(Action<Exception?, PropertyChanges<DBusMenuProperties>> handler, bool emitOnCapturedContext = true) |
||||
|
{ |
||||
|
return base.WatchPropertiesChangedAsync(Interface, (m, s) => ReadMessage(m, (DBusMenuObject)s!), handler, emitOnCapturedContext); |
||||
|
static PropertyChanges<DBusMenuProperties> ReadMessage(Message message, DBusMenuObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
reader.ReadString(); // interface
|
||||
|
List<string> changed = new(), invalidated = new(); |
||||
|
return new PropertyChanges<DBusMenuProperties>(ReadProperties(ref reader, changed), changed.ToArray(), ReadInvalidated(ref reader)); |
||||
|
} |
||||
|
static string[] ReadInvalidated(ref Reader reader) |
||||
|
{ |
||||
|
List<string>? invalidated = null; |
||||
|
ArrayEnd headersEnd = reader.ReadArrayStart(DBusType.String); |
||||
|
while (reader.HasNext(headersEnd)) |
||||
|
{ |
||||
|
invalidated ??= new(); |
||||
|
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<string>(); |
||||
|
} |
||||
|
} |
||||
|
private static DBusMenuProperties ReadProperties(ref Reader reader, List<string>? changedList = null) |
||||
|
{ |
||||
|
var props = new DBusMenuProperties(); |
||||
|
ArrayEnd 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<string>(); |
||||
|
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 DBusMenu(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<IDisposable> WatchPropertiesChangedAsync<TProperties>(string @interface, MessageValueReader<PropertyChanges<TProperties>> reader, Action<Exception?, PropertyChanges<TProperties>> 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, |
||||
|
(ex, changes, rs, hs) => ((Action<Exception?, PropertyChanges<TProperties>>)hs!).Invoke(ex, changes), |
||||
|
this, handler, emitOnCapturedContext); |
||||
|
} |
||||
|
public ValueTask<IDisposable> WatchSignalAsync<TArg>(string sender, string @interface, ObjectPath path, string signal, MessageValueReader<TArg> reader, Action<Exception?, TArg> handler, bool emitOnCapturedContext) |
||||
|
{ |
||||
|
var rule = new MatchRule |
||||
|
{ |
||||
|
Type = MessageType.Signal, |
||||
|
Sender = sender, |
||||
|
Path = path, |
||||
|
Member = signal, |
||||
|
Interface = @interface |
||||
|
}; |
||||
|
return Connection.AddMatchAsync(rule, reader, |
||||
|
(ex, arg, rs, hs) => ((Action<Exception?, TArg>)hs!).Invoke(ex, arg), |
||||
|
this, handler, emitOnCapturedContext); |
||||
|
} |
||||
|
public ValueTask<IDisposable> WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, Action<Exception?> handler, bool emitOnCapturedContext) |
||||
|
{ |
||||
|
var rule = new MatchRule |
||||
|
{ |
||||
|
Type = MessageType.Signal, |
||||
|
Sender = sender, |
||||
|
Path = path, |
||||
|
Member = signal, |
||||
|
Interface = @interface |
||||
|
}; |
||||
|
return Connection.AddMatchAsync<object>(rule, (message, state) => null!, |
||||
|
(ex, v, rs, hs) => ((Action<Exception?>)hs!).Invoke(ex), this, handler, emitOnCapturedContext); |
||||
|
} |
||||
|
protected static (uint, (int, Dictionary<string, object>, object[])) ReadMessage_uriaesvavz(Message message, DBusMenuObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
var arg0 = reader.ReadUInt32(); |
||||
|
var arg1 = reader.ReadStruct<int, Dictionary<string, object>, object[]>(); |
||||
|
return (arg0, arg1); |
||||
|
} |
||||
|
protected static (int, Dictionary<string, object>)[] ReadMessage_ariaesvz(Message message, DBusMenuObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
return reader.ReadArray<(int, Dictionary<string, object>)>(); |
||||
|
} |
||||
|
protected static object ReadMessage_v(Message message, DBusMenuObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
return reader.ReadVariant(); |
||||
|
} |
||||
|
protected static int[] ReadMessage_ai(Message message, DBusMenuObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
return reader.ReadArray<int>(); |
||||
|
} |
||||
|
protected static bool ReadMessage_b(Message message, DBusMenuObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
return reader.ReadBool(); |
||||
|
} |
||||
|
protected static (int[], int[]) ReadMessage_aiai(Message message, DBusMenuObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
var arg0 = reader.ReadArray<int>(); |
||||
|
var arg1 = reader.ReadArray<int>(); |
||||
|
return (arg0, arg1); |
||||
|
} |
||||
|
protected static ((int, Dictionary<string, object>)[], (int, string[])[]) ReadMessage_ariaesvzariasz(Message message, DBusMenuObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
var arg0 = reader.ReadArray<(int, Dictionary<string, object>)>(); |
||||
|
var arg1 = reader.ReadArray<(int, string[])>(); |
||||
|
return (arg0, arg1); |
||||
|
} |
||||
|
protected static (uint, int) ReadMessage_ui(Message message, DBusMenuObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
var arg0 = reader.ReadUInt32(); |
||||
|
var arg1 = reader.ReadInt32(); |
||||
|
return (arg0, arg1); |
||||
|
} |
||||
|
protected static (int, uint) ReadMessage_iu(Message message, DBusMenuObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
var arg0 = reader.ReadInt32(); |
||||
|
var arg1 = reader.ReadUInt32(); |
||||
|
return (arg0, arg1); |
||||
|
} |
||||
|
protected static uint ReadMessage_v_u(Message message, DBusMenuObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
reader.ReadSignature("u"); |
||||
|
return reader.ReadUInt32(); |
||||
|
} |
||||
|
protected static string ReadMessage_v_s(Message message, DBusMenuObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
reader.ReadSignature("s"); |
||||
|
return reader.ReadString(); |
||||
|
} |
||||
|
protected static string[] ReadMessage_v_as(Message message, DBusMenuObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
reader.ReadSignature("as"); |
||||
|
return reader.ReadArray<string>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,56 +0,0 @@ |
|||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Runtime.CompilerServices; |
|
||||
using System.Threading.Tasks; |
|
||||
using Tmds.DBus; |
|
||||
|
|
||||
[assembly: InternalsVisibleTo(Tmds.DBus.Connection.DynamicAssemblyName)] |
|
||||
namespace Avalonia.FreeDesktop.DBusMenu |
|
||||
{ |
|
||||
|
|
||||
[DBusInterface("org.freedesktop.DBus.Properties")] |
|
||||
interface IFreeDesktopDBusProperties : IDBusObject |
|
||||
{ |
|
||||
Task<object> GetAsync(string prop); |
|
||||
Task<DBusMenuProperties> GetAllAsync(); |
|
||||
Task SetAsync(string prop, object val); |
|
||||
Task<IDisposable> WatchPropertiesAsync(Action<PropertyChanges> handler); |
|
||||
} |
|
||||
|
|
||||
[DBusInterface("com.canonical.dbusmenu")] |
|
||||
interface IDBusMenu : IFreeDesktopDBusProperties |
|
||||
{ |
|
||||
Task<(uint revision, (int, KeyValuePair<string, object>[], object[]) layout)> GetLayoutAsync(int ParentId, int RecursionDepth, string[] PropertyNames); |
|
||||
Task<(int, KeyValuePair<string, object>[])[]> GetGroupPropertiesAsync(int[] Ids, string[] PropertyNames); |
|
||||
Task<object> GetPropertyAsync(int Id, string Name); |
|
||||
Task EventAsync(int Id, string EventId, object Data, uint Timestamp); |
|
||||
Task<int[]> EventGroupAsync((int id, string eventId, object data, uint timestamp)[] events); |
|
||||
Task<bool> AboutToShowAsync(int Id); |
|
||||
Task<(int[] updatesNeeded, int[] idErrors)> AboutToShowGroupAsync(int[] Ids); |
|
||||
Task<IDisposable> WatchItemsPropertiesUpdatedAsync(Action<((int, IDictionary<string, object>)[] updatedProps, (int, string[])[] removedProps)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchLayoutUpdatedAsync(Action<(uint revision, int parent)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchItemActivationRequestedAsync(Action<(int id, uint timestamp)> handler, Action<Exception>? onError = null); |
|
||||
} |
|
||||
|
|
||||
[Dictionary] |
|
||||
class DBusMenuProperties |
|
||||
{ |
|
||||
public uint Version { get; set; } = default (uint); |
|
||||
public string? TextDirection { get; set; } = default (string); |
|
||||
public string? Status { get; set; } = default (string); |
|
||||
public string[]? IconThemePath { get; set; } = default (string[]); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
[DBusInterface("com.canonical.AppMenu.Registrar")] |
|
||||
interface IRegistrar : IDBusObject |
|
||||
{ |
|
||||
Task RegisterWindowAsync(uint WindowId, ObjectPath MenuObjectPath); |
|
||||
Task UnregisterWindowAsync(uint WindowId); |
|
||||
Task<(string service, ObjectPath menuObjectPath)> GetMenuForWindowAsync(uint WindowId); |
|
||||
Task<(uint, string, ObjectPath)[]> GetMenusAsync(); |
|
||||
Task<IDisposable> WatchWindowRegisteredAsync(Action<(uint windowId, string service, ObjectPath menuObjectPath)> handler, Action<Exception>? onError = null); |
|
||||
Task<IDisposable> WatchWindowUnregisteredAsync(Action<uint> handler, Action<Exception>? onError = null); |
|
||||
} |
|
||||
} |
|
||||
@ -1,16 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Runtime.CompilerServices; |
|
||||
using System.Threading.Tasks; |
|
||||
using Tmds.DBus; |
|
||||
|
|
||||
[assembly: InternalsVisibleTo(Connection.DynamicAssemblyName)] |
|
||||
namespace Avalonia.FreeDesktop |
|
||||
{ |
|
||||
[DBusInterface("org.freedesktop.portal.Request")] |
|
||||
internal interface IRequest : IDBusObject |
|
||||
{ |
|
||||
Task CloseAsync(); |
|
||||
Task<IDisposable> WatchResponseAsync(Action<(uint response, IDictionary<string, object> results)> handler, Action<Exception>? onError = null); |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,937 @@ |
|||||
|
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<string, object> 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<IDisposable> WatchActionInvokedAsync(Action<Exception?, (string Id, string Action, object[] Parameter)> handler, |
||||
|
bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "ActionInvoked", |
||||
|
(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<uint> GetVersionAsync() |
||||
|
=> Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "version"), |
||||
|
(m, s) => ReadMessage_v_u(m, (DesktopObject)s!), this); |
||||
|
|
||||
|
public Task<NotificationProperties> GetPropertiesAsync() |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateGetAllPropertiesMessage(Interface), |
||||
|
(m, s) => ReadMessage(m, (DesktopObject)s!), this); |
||||
|
|
||||
|
static NotificationProperties ReadMessage(Message message, DesktopObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
return ReadProperties(ref reader); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchPropertiesChangedAsync(Action<Exception?, PropertyChanges<NotificationProperties>> handler, |
||||
|
bool emitOnCapturedContext = true) |
||||
|
{ |
||||
|
return base.WatchPropertiesChangedAsync(Interface, (m, s) => ReadMessage(m, (DesktopObject)s!), handler, |
||||
|
emitOnCapturedContext); |
||||
|
|
||||
|
static PropertyChanges<NotificationProperties> ReadMessage(Message message, DesktopObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
reader.ReadString(); // interface
|
||||
|
List<string> changed = new(); |
||||
|
return new PropertyChanges<NotificationProperties>(ReadProperties(ref reader, changed), changed.ToArray(), |
||||
|
ReadInvalidated(ref reader)); |
||||
|
} |
||||
|
|
||||
|
static string[] ReadInvalidated(ref Reader reader) |
||||
|
{ |
||||
|
List<string>? invalidated = null; |
||||
|
ArrayEnd headersEnd = reader.ReadArrayStart(DBusType.String); |
||||
|
while (reader.HasNext(headersEnd)) |
||||
|
{ |
||||
|
invalidated ??= new(); |
||||
|
var property = reader.ReadString(); |
||||
|
switch (property) |
||||
|
{ |
||||
|
case "version": |
||||
|
invalidated.Add("Version"); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return invalidated?.ToArray() ?? Array.Empty<string>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static NotificationProperties ReadProperties(ref Reader reader, List<string>? changedList = null) |
||||
|
{ |
||||
|
var props = new NotificationProperties(); |
||||
|
ArrayEnd 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<ObjectPath> OpenUriAsync(string parentWindow, string uri, Dictionary<string, object> options) |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateMessage(), (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<ObjectPath> OpenFileAsync(string parentWindow, SafeHandle fd, Dictionary<string, object> options) |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateMessage(), (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<ObjectPath> OpenDirectoryAsync(string parentWindow, SafeHandle fd, Dictionary<string, object> options) |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateMessage(), (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<uint> GetVersionAsync() |
||||
|
=> Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "version"), |
||||
|
(m, s) => ReadMessage_v_u(m, (DesktopObject)s!), this); |
||||
|
|
||||
|
public Task<OpenURIProperties> GetPropertiesAsync() |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateGetAllPropertiesMessage(Interface), |
||||
|
(m, s) => ReadMessage(m, (DesktopObject)s!), this); |
||||
|
|
||||
|
static OpenURIProperties ReadMessage(Message message, DesktopObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
return ReadProperties(ref reader); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchPropertiesChangedAsync(Action<Exception?, PropertyChanges<OpenURIProperties>> handler, |
||||
|
bool emitOnCapturedContext = true) |
||||
|
{ |
||||
|
return base.WatchPropertiesChangedAsync(Interface, (m, s) => ReadMessage(m, (DesktopObject)s!), handler, |
||||
|
emitOnCapturedContext); |
||||
|
|
||||
|
static PropertyChanges<OpenURIProperties> ReadMessage(Message message, DesktopObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
reader.ReadString(); // interface
|
||||
|
List<string> changed = new(); |
||||
|
return new PropertyChanges<OpenURIProperties>(ReadProperties(ref reader, changed), changed.ToArray(), ReadInvalidated(ref reader)); |
||||
|
} |
||||
|
|
||||
|
static string[] ReadInvalidated(ref Reader reader) |
||||
|
{ |
||||
|
List<string>? invalidated = null; |
||||
|
ArrayEnd headersEnd = reader.ReadArrayStart(DBusType.String); |
||||
|
while (reader.HasNext(headersEnd)) |
||||
|
{ |
||||
|
invalidated ??= new(); |
||||
|
var property = reader.ReadString(); |
||||
|
switch (property) |
||||
|
{ |
||||
|
case "version": |
||||
|
invalidated.Add("Version"); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return invalidated?.ToArray() ?? Array.Empty<string>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static OpenURIProperties ReadProperties(ref Reader reader, List<string>? changedList = null) |
||||
|
{ |
||||
|
var props = new OpenURIProperties(); |
||||
|
ArrayEnd 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<string, object> 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<ObjectPath> PrepareInstallAsync(string parentWindow, string name, object iconV, Dictionary<string, object> options) |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateMessage(), (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<string> RequestInstallTokenAsync(string name, object iconV, Dictionary<string, object> options) |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateMessage(), (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<string, object> 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<string> GetDesktopEntryAsync(string desktopFileId) |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateMessage(), (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(), (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<string, object> 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<uint> GetSupportedLauncherTypesAsync() |
||||
|
=> Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "SupportedLauncherTypes"), |
||||
|
(m, s) => ReadMessage_v_u(m, (DesktopObject)s!), this); |
||||
|
|
||||
|
public Task<uint> GetVersionAsync() |
||||
|
=> Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "version"), |
||||
|
(m, s) => ReadMessage_v_u(m, (DesktopObject)s!), this); |
||||
|
|
||||
|
public Task<DynamicLauncherProperties> GetPropertiesAsync() |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateGetAllPropertiesMessage(Interface), |
||||
|
(m, s) => ReadMessage(m, (DesktopObject)s!), this); |
||||
|
|
||||
|
static DynamicLauncherProperties ReadMessage(Message message, DesktopObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
return ReadProperties(ref reader); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchPropertiesChangedAsync(Action<Exception?, PropertyChanges<DynamicLauncherProperties>> handler, |
||||
|
bool emitOnCapturedContext = true) |
||||
|
{ |
||||
|
return base.WatchPropertiesChangedAsync(Interface, (m, s) => ReadMessage(m, (DesktopObject)s!), handler, |
||||
|
emitOnCapturedContext); |
||||
|
|
||||
|
static PropertyChanges<DynamicLauncherProperties> ReadMessage(Message message, DesktopObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
reader.ReadString(); // interface
|
||||
|
List<string> changed = new(); |
||||
|
return new PropertyChanges<DynamicLauncherProperties>(ReadProperties(ref reader, changed), changed.ToArray(), |
||||
|
ReadInvalidated(ref reader)); |
||||
|
} |
||||
|
|
||||
|
static string[] ReadInvalidated(ref Reader reader) |
||||
|
{ |
||||
|
List<string>? invalidated = null; |
||||
|
ArrayEnd headersEnd = reader.ReadArrayStart(DBusType.String); |
||||
|
while (reader.HasNext(headersEnd)) |
||||
|
{ |
||||
|
invalidated ??= new(); |
||||
|
var property = reader.ReadString(); |
||||
|
switch (property) |
||||
|
{ |
||||
|
case "SupportedLauncherTypes": |
||||
|
invalidated.Add("SupportedLauncherTypes"); |
||||
|
break; |
||||
|
case "version": |
||||
|
invalidated.Add("Version"); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return invalidated?.ToArray() ?? Array.Empty<string>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static DynamicLauncherProperties ReadProperties(ref Reader reader, List<string>? changedList = null) |
||||
|
{ |
||||
|
var props = new DynamicLauncherProperties(); |
||||
|
ArrayEnd 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<ObjectPath> OpenFileAsync(string parentWindow, string title, Dictionary<string, object> options) |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateMessage(), (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<ObjectPath> SaveFileAsync(string parentWindow, string title, Dictionary<string, object> options) |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateMessage(), (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<ObjectPath> SaveFilesAsync(string parentWindow, string title, Dictionary<string, object> options) |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateMessage(), (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<uint> GetVersionAsync() |
||||
|
=> Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "version"), |
||||
|
(m, s) => ReadMessage_v_u(m, (DesktopObject)s!), this); |
||||
|
|
||||
|
public Task<FileChooserProperties> GetPropertiesAsync() |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateGetAllPropertiesMessage(Interface), |
||||
|
(m, s) => ReadMessage(m, (DesktopObject)s!), this); |
||||
|
|
||||
|
static FileChooserProperties ReadMessage(Message message, DesktopObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
return ReadProperties(ref reader); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchPropertiesChangedAsync(Action<Exception?, PropertyChanges<FileChooserProperties>> handler, |
||||
|
bool emitOnCapturedContext = true) |
||||
|
{ |
||||
|
return base.WatchPropertiesChangedAsync(Interface, (m, s) => ReadMessage(m, (DesktopObject)s!), handler, |
||||
|
emitOnCapturedContext); |
||||
|
|
||||
|
static PropertyChanges<FileChooserProperties> ReadMessage(Message message, DesktopObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
reader.ReadString(); // interface
|
||||
|
List<string> changed = new(); |
||||
|
return new PropertyChanges<FileChooserProperties>(ReadProperties(ref reader, changed), changed.ToArray(), |
||||
|
ReadInvalidated(ref reader)); |
||||
|
} |
||||
|
|
||||
|
static string[] ReadInvalidated(ref Reader reader) |
||||
|
{ |
||||
|
List<string>? invalidated = null; |
||||
|
ArrayEnd headersEnd = reader.ReadArrayStart(DBusType.String); |
||||
|
while (reader.HasNext(headersEnd)) |
||||
|
{ |
||||
|
invalidated ??= new(); |
||||
|
var property = reader.ReadString(); |
||||
|
switch (property) |
||||
|
{ |
||||
|
case "version": |
||||
|
invalidated.Add("Version"); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return invalidated?.ToArray() ?? Array.Empty<string>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static FileChooserProperties ReadProperties(ref Reader reader, List<string>? changedList = null) |
||||
|
{ |
||||
|
var props = new FileChooserProperties(); |
||||
|
ArrayEnd 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<IDisposable> WatchResponseAsync(Action<Exception?, (uint response, IDictionary<string, object> 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); |
||||
|
|
||||
|
public DesktopService 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<IDisposable> WatchPropertiesChangedAsync<TProperties>(string @interface, |
||||
|
MessageValueReader<PropertyChanges<TProperties>> reader, Action<Exception?, PropertyChanges<TProperties>> 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, |
||||
|
(ex, changes, rs, hs) => |
||||
|
((Action<Exception?, PropertyChanges<TProperties>>)hs!).Invoke(ex, changes), |
||||
|
this, handler, emitOnCapturedContext); |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchSignalAsync<TArg>(string sender, string @interface, ObjectPath path, string signal, |
||||
|
MessageValueReader<TArg> reader, Action<Exception?, TArg> handler, bool emitOnCapturedContext) |
||||
|
{ |
||||
|
var rule = new MatchRule |
||||
|
{ |
||||
|
Type = MessageType.Signal, |
||||
|
Sender = sender, |
||||
|
Path = path, |
||||
|
Member = signal, |
||||
|
Interface = @interface |
||||
|
}; |
||||
|
return Connection.AddMatchAsync(rule, reader, |
||||
|
(ex, arg, rs, hs) => ((Action<Exception?, TArg>)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<object>(); |
||||
|
return (arg0, arg1, arg2); |
||||
|
} |
||||
|
|
||||
|
protected static (uint, Dictionary<string, object>) ReadMessage_uaesv(Message message, DesktopObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
var arg0 = reader.ReadUInt32(); |
||||
|
var arg1 = reader.ReadDictionary<string, object>(); |
||||
|
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<TProperties> |
||||
|
{ |
||||
|
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; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,351 @@ |
|||||
|
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<IDisposable> WatchStatusNotifierItemRegisteredAsync(Action<Exception?, string> handler, bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "StatusNotifierItemRegistered", static (m, s) => |
||||
|
ReadMessage_s(m, (StatusNotifierWatcherObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchStatusNotifierItemUnregisteredAsync(Action<Exception?, string> handler, bool emitOnCapturedContext = true) |
||||
|
=> WatchSignalAsync(Service.Destination, Interface, Path, "StatusNotifierItemUnregistered", static (m, s) |
||||
|
=> ReadMessage_s(m, (StatusNotifierWatcherObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchStatusNotifierHostRegisteredAsync(Action<Exception?> handler, bool emitOnCapturedContext = true) => |
||||
|
WatchSignalAsync(Service.Destination, Interface, Path, "StatusNotifierHostRegistered", handler, emitOnCapturedContext); |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchStatusNotifierHostUnregisteredAsync(Action<Exception?> 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<string[]> GetRegisteredStatusNotifierItemsAsync() => |
||||
|
Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "RegisteredStatusNotifierItems"), static (m, s) |
||||
|
=> ReadMessage_v_as(m, (StatusNotifierWatcherObject)s!), this); |
||||
|
|
||||
|
public Task<bool> GetIsStatusNotifierHostRegisteredAsync() => |
||||
|
Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "IsStatusNotifierHostRegistered"), static (m, s) => |
||||
|
ReadMessage_v_b(m, (StatusNotifierWatcherObject)s!), this); |
||||
|
|
||||
|
public Task<int> GetProtocolVersionAsync() => |
||||
|
Connection.CallMethodAsync(CreateGetPropertyMessage(Interface, "ProtocolVersion"), static (m, s) |
||||
|
=> ReadMessage_v_i(m, (StatusNotifierWatcherObject)s!), this); |
||||
|
|
||||
|
public Task<StatusNotifierWatcherProperties> GetPropertiesAsync() |
||||
|
{ |
||||
|
return Connection.CallMethodAsync(CreateGetAllPropertiesMessage(Interface), static (m, s) |
||||
|
=> ReadMessage(m, (StatusNotifierWatcherObject)s!), this); |
||||
|
|
||||
|
static StatusNotifierWatcherProperties ReadMessage(Message message, StatusNotifierWatcherObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
return ReadProperties(ref reader); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchPropertiesChangedAsync(Action<Exception?, PropertyChanges<StatusNotifierWatcherProperties>> handler, bool emitOnCapturedContext = true) |
||||
|
{ |
||||
|
return base.WatchPropertiesChangedAsync(Interface, static (m, s) => ReadMessage(m, (StatusNotifierWatcherObject)s!), handler, emitOnCapturedContext); |
||||
|
|
||||
|
static PropertyChanges<StatusNotifierWatcherProperties> ReadMessage(Message message, StatusNotifierWatcherObject _) |
||||
|
{ |
||||
|
var reader = message.GetBodyReader(); |
||||
|
reader.ReadString(); // interface
|
||||
|
List<string> changed = new(); |
||||
|
return new PropertyChanges<StatusNotifierWatcherProperties>(ReadProperties(ref reader, changed), changed.ToArray(), |
||||
|
ReadInvalidated(ref reader)); |
||||
|
} |
||||
|
|
||||
|
static string[] ReadInvalidated(ref Reader reader) |
||||
|
{ |
||||
|
List<string>? invalidated = null; |
||||
|
var headersEnd = reader.ReadArrayStart(DBusType.String); |
||||
|
while (reader.HasNext(headersEnd)) |
||||
|
{ |
||||
|
invalidated ??= new List<string>(); |
||||
|
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<string>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static StatusNotifierWatcherProperties ReadProperties(ref Reader reader, List<string>? 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<string>(); |
||||
|
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); |
||||
|
} |
||||
|
|
||||
|
public StatusNotifierWatcherService 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<IDisposable> WatchPropertiesChangedAsync<TProperties>(string @interface, MessageValueReader<PropertyChanges<TProperties>> reader, Action<Exception?, PropertyChanges<TProperties>> 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<Exception?, PropertyChanges<TProperties>>)hs!).Invoke(ex, changes), this, handler, emitOnCapturedContext); |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchSignalAsync<TArg>(string sender, string @interface, ObjectPath path, string signal, MessageValueReader<TArg> reader, Action<Exception?, TArg> handler, bool emitOnCapturedContext) |
||||
|
{ |
||||
|
var rule = new MatchRule |
||||
|
{ |
||||
|
Type = MessageType.Signal, |
||||
|
Sender = sender, |
||||
|
Path = path, |
||||
|
Member = signal, |
||||
|
Interface = @interface |
||||
|
}; |
||||
|
return Connection.AddMatchAsync(rule, reader, |
||||
|
(ex, arg, _, hs) => ((Action<Exception?, TArg>)hs!).Invoke(ex, arg), |
||||
|
this, handler, emitOnCapturedContext); |
||||
|
} |
||||
|
|
||||
|
public ValueTask<IDisposable> WatchSignalAsync(string sender, string @interface, ObjectPath path, string signal, Action<Exception?> 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<Exception?>)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<string>(); |
||||
|
} |
||||
|
|
||||
|
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(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue