Browse Source

Revert "Reapply (#15568) + Updates (#16129)" (#16175)

This reverts commit 9c955d3b3d.
pull/16182/head
Nikita Tsukanov 2 years ago
committed by GitHub
parent
commit
1639aabd3c
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 10
      api/Avalonia.FreeDesktop.nupkg.xml
  2. 4
      src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj
  3. 4
      src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxICWrapper.cs
  4. 2
      src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxX11TextInputMethod.cs
  5. 21
      src/Avalonia.FreeDesktop/DBusIme/IBus/IBusX11TextInputMethod.cs
  6. 103
      src/Avalonia.FreeDesktop/DBusMenuExporter.cs
  7. 36
      src/Avalonia.FreeDesktop/DBusPlatformSettings.cs
  8. 109
      src/Avalonia.FreeDesktop/DBusSystemDialog.cs
  9. 36
      src/Avalonia.FreeDesktop/DBusTrayIconImpl.cs

10
api/Avalonia.FreeDesktop.nupkg.xml

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/en-us/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Tmds.DBus.SourceGenerator.PropertyChanges`1</Target>
<Left>baseline/netstandard2.0/Avalonia.FreeDesktop.dll</Left>
<Right>target/netstandard2.0/Avalonia.FreeDesktop.dll</Right>
</Suppression>
</Suppressions>

4
src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj

@ -12,8 +12,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Tmds.DBus.Protocol" Version="0.19.0" /> <PackageReference Include="Tmds.DBus.Protocol" Version="0.16.0" />
<PackageReference Include="Tmds.DBus.SourceGenerator" Version="0.0.17" PrivateAssets="all" /> <PackageReference Include="Tmds.DBus.SourceGenerator" Version="0.0.15" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

4
src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxICWrapper.cs

@ -45,7 +45,7 @@ namespace Avalonia.FreeDesktop.DBusIme.Fcitx
public ValueTask<IDisposable> WatchForwardKeyAsync(Action<Exception?, (uint keyval, uint state, int type)> handler) => public ValueTask<IDisposable> WatchForwardKeyAsync(Action<Exception?, (uint keyval, uint state, int type)> handler) =>
_old?.WatchForwardKeyAsync(handler) _old?.WatchForwardKeyAsync(handler)
?? _modern?.WatchForwardKeyAsync((e, ev) => handler.Invoke(e, (ev.Keyval, ev.State, ev.Type ? 1 : 0))) ?? _modern?.WatchForwardKeyAsync((e, ev) => handler.Invoke(e, (ev.keyval, ev.state, ev.type ? 1 : 0)))
?? new ValueTask<IDisposable>(Disposable.Empty); ?? new ValueTask<IDisposable>(Disposable.Empty);
public ValueTask<IDisposable> WatchUpdateFormattedPreeditAsync( public ValueTask<IDisposable> WatchUpdateFormattedPreeditAsync(
@ -53,7 +53,7 @@ namespace Avalonia.FreeDesktop.DBusIme.Fcitx
_old?.WatchUpdateFormattedPreeditAsync(handler!) _old?.WatchUpdateFormattedPreeditAsync(handler!)
?? _modern?.WatchUpdateFormattedPreeditAsync(handler!) ?? _modern?.WatchUpdateFormattedPreeditAsync(handler!)
?? new ValueTask<IDisposable>(Disposable.Empty); ?? new ValueTask<IDisposable>(Disposable.Empty);
public Task SetCapacityAsync(uint flags) => public Task SetCapacityAsync(uint flags) =>
_old?.SetCapacityAsync(flags) ?? _modern?.SetCapabilityAsync(flags) ?? Task.CompletedTask; _old?.SetCapacityAsync(flags) ?? _modern?.SetCapabilityAsync(flags) ?? Task.CompletedTask;
} }

2
src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxX11TextInputMethod.cs

@ -29,7 +29,7 @@ namespace Avalonia.FreeDesktop.DBusIme.Fcitx
var resp = await method.CreateICv3Async(GetAppName(), var resp = await method.CreateICv3Async(GetAppName(),
Process.GetCurrentProcess().Id); Process.GetCurrentProcess().Id);
var proxy = new OrgFcitxFcitxInputContext(Connection, name, $"/inputcontext_{resp.Icid}"); var proxy = new OrgFcitxFcitxInputContext(Connection, name, $"/inputcontext_{resp.icid}");
_context = new FcitxICWrapper(proxy); _context = new FcitxICWrapper(proxy);
} }
else else

21
src/Avalonia.FreeDesktop/DBusIme/IBus/IBusX11TextInputMethod.cs

@ -51,16 +51,17 @@ namespace Avalonia.FreeDesktop.DBusIme.IBus
Client.SetPreeditText(_preeditText, _preeditText == null ? null : _preeditCursor); Client.SetPreeditText(_preeditText, _preeditText == null ? null : _preeditCursor);
} }
private void OnUpdatePreedit(Exception? arg1, (VariantValue Text, uint CursorPos, bool Visible) preeditComponents) private void OnUpdatePreedit(Exception? arg1, (DBusVariantItem text, uint cursor_pos, bool visible) preeditComponents)
{ {
if (preeditComponents.Text is { Type: VariantValueType.Struct, Count: >= 3 } structItem && structItem.GetItem(2) is { Type: VariantValueType.String} stringItem) if (preeditComponents.text is { Value: DBusStructItem { Count: >= 3 } structItem } &&
structItem[2] is DBusStringItem stringItem)
{ {
_preeditText = stringItem.GetString(); _preeditText = stringItem.Value;
_preeditCursor = _preeditText != null _preeditCursor = _preeditText != null
? Utf16Utils.CharacterOffsetToStringOffset(_preeditText, ? Utf16Utils.CharacterOffsetToStringOffset(_preeditText,
(int)Math.Min(preeditComponents.CursorPos, int.MaxValue), false) (int)Math.Min(preeditComponents.cursor_pos, int.MaxValue), false)
: 0; : 0;
_preeditShown = true; _preeditShown = true;
} }
else else
@ -101,13 +102,13 @@ namespace Avalonia.FreeDesktop.DBusIme.IBus
}); });
} }
private void OnCommitText(Exception? e, VariantValue variantItem) private void OnCommitText(Exception? e, DBusVariantItem variantItem)
{ {
if (_insideReset > 0) if (_insideReset > 0)
{ {
// For some reason iBus can trigger a CommitText while being reset. // For some reason iBus can trigger a CommitText while being reset.
// Thankfully the signal is sent _during_ Reset call processing, // Thankfully the signal is sent _during_ Reset call processing,
// so it arrives on-the-wire before Reset call result, so we can // so it arrives on-the-wire before Reset call result, so we can
// check if we have any pending Reset calls and ignore the signal here // check if we have any pending Reset calls and ignore the signal here
return; return;
} }
@ -117,8 +118,8 @@ namespace Avalonia.FreeDesktop.DBusIme.IBus
return; return;
} }
if (variantItem.Count >= 3 && variantItem.GetItem(2) is { Type: VariantValueType.String } stringItem) if (variantItem.Value is DBusStructItem { Count: >= 3 } structItem && structItem[2] is DBusStringItem stringItem)
FireCommit(stringItem.GetString()); FireCommit(stringItem.Value);
} }
protected override Task DisconnectAsync() => _service?.DestroyAsync() ?? Task.CompletedTask; protected override Task DisconnectAsync() => _service?.DestroyAsync() ?? Task.CompletedTask;

103
src/Avalonia.FreeDesktop/DBusMenuExporter.cs

@ -43,10 +43,7 @@ namespace Avalonia.FreeDesktop
InitBackingProperties(); InitBackingProperties();
Connection = connection; Connection = connection;
_xid = (uint)xid.ToInt32(); _xid = (uint)xid.ToInt32();
Path = GenerateDBusMenuObjPath;
PathHandler = new PathHandler(GenerateDBusMenuObjPath);
PathHandler.Add(this);
SetNativeMenu(new NativeMenu()); SetNativeMenu(new NativeMenu());
_ = InitializeAsync(); _ = InitializeAsync();
} }
@ -56,22 +53,24 @@ namespace Avalonia.FreeDesktop
InitBackingProperties(); InitBackingProperties();
Connection = connection; Connection = connection;
_appMenu = false; _appMenu = false;
Path = path;
PathHandler = new PathHandler(path);
PathHandler.Add(this);
SetNativeMenu(new NativeMenu()); SetNativeMenu(new NativeMenu());
_ = InitializeAsync(); _ = InitializeAsync();
} }
private void InitBackingProperties() private void InitBackingProperties()
{ {
Version = 4; BackingProperties.Version = 4;
BackingProperties.Status = string.Empty;
BackingProperties.TextDirection = string.Empty;
BackingProperties.IconThemePath = Array.Empty<string>();
} }
public override Connection Connection { get; } protected override Connection Connection { get; }
protected override ValueTask<(uint Revision, (int, Dictionary<string, Variant>, Variant[]) Layout)> OnGetLayoutAsync(int parentId, int recursionDepth, string[] propertyNames) public override string Path { get; }
protected override ValueTask<(uint revision, (int, Dictionary<string, DBusVariantItem>, DBusVariantItem[]) layout)> OnGetLayoutAsync(int parentId, int recursionDepth, string[] propertyNames)
{ {
var menu = GetMenu(parentId); var menu = GetMenu(parentId);
var layout = GetLayout(menu.item, menu.menu, recursionDepth, propertyNames); var layout = GetLayout(menu.item, menu.menu, recursionDepth, propertyNames);
@ -81,22 +80,22 @@ namespace Avalonia.FreeDesktop
OnIsNativeMenuExportedChanged?.Invoke(this, EventArgs.Empty); OnIsNativeMenuExportedChanged?.Invoke(this, EventArgs.Empty);
} }
return new ValueTask<(uint, (int, Dictionary<string, Variant>, Variant[]))>((_revision, layout)); return new ValueTask<(uint, (int, Dictionary<string, DBusVariantItem>, DBusVariantItem[]))>((_revision, layout));
} }
protected override ValueTask<(int, Dictionary<string, Variant>)[]> OnGetGroupPropertiesAsync(int[] ids, string[] propertyNames) protected override ValueTask<(int, Dictionary<string, DBusVariantItem>)[]> OnGetGroupPropertiesAsync(int[] ids, string[] propertyNames)
=> new(ids.Select(id => (id, GetProperties(GetMenu(id), propertyNames))).ToArray()); => new(ids.Select(id => (id, GetProperties(GetMenu(id), propertyNames))).ToArray());
protected override ValueTask<Variant> OnGetPropertyAsync(int id, string name) => protected override ValueTask<DBusVariantItem> OnGetPropertyAsync(int id, string name) =>
new(GetProperty(GetMenu(id), name) ?? new Variant(0)); new(GetProperty(GetMenu(id), name) ?? new DBusVariantItem("i", new DBusInt32Item(0)));
protected override ValueTask OnEventAsync(int id, string eventId, VariantValue data, uint timestamp) protected override ValueTask OnEventAsync(int id, string eventId, DBusVariantItem data, uint timestamp)
{ {
HandleEvent(id, eventId); HandleEvent(id, eventId);
return new ValueTask(); return new ValueTask();
} }
protected override ValueTask<int[]> OnEventGroupAsync((int, string, VariantValue, uint)[] events) protected override ValueTask<int[]> OnEventGroupAsync((int, string, DBusVariantItem, uint)[] events)
{ {
foreach (var e in events) foreach (var e in events)
HandleEvent(e.Item1, e.Item2); HandleEvent(e.Item1, e.Item2);
@ -105,12 +104,12 @@ namespace Avalonia.FreeDesktop
protected override ValueTask<bool> OnAboutToShowAsync(int id) => new(false); protected override ValueTask<bool> OnAboutToShowAsync(int id) => new(false);
protected override ValueTask<(int[] UpdatesNeeded, int[] IdErrors)> OnAboutToShowGroupAsync(int[] ids) => protected override ValueTask<(int[] updatesNeeded, int[] idErrors)> OnAboutToShowGroupAsync(int[] ids) =>
new((Array.Empty<int>(), Array.Empty<int>())); new((Array.Empty<int>(), Array.Empty<int>()));
private async Task InitializeAsync() private async Task InitializeAsync()
{ {
Connection.AddMethodHandler(this.PathHandler!); Connection.AddMethodHandler(this);
if (!_appMenu) if (!_appMenu)
return; return;
@ -118,7 +117,7 @@ namespace Avalonia.FreeDesktop
try try
{ {
if (!_disposed) if (!_disposed)
await _registrar.RegisterWindowAsync(_xid, this.PathHandler!.Path); await _registrar.RegisterWindowAsync(_xid, Path);
} }
catch catch
{ {
@ -221,32 +220,35 @@ namespace Avalonia.FreeDesktop
"type", "label", "enabled", "visible", "shortcut", "toggle-type", "children-display", "toggle-state", "icon-data" "type", "label", "enabled", "visible", "shortcut", "toggle-type", "children-display", "toggle-state", "icon-data"
}; };
private static Variant? GetProperty((NativeMenuItemBase? item, NativeMenu? menu) i, string name) private static DBusVariantItem? GetProperty((NativeMenuItemBase? item, NativeMenu? menu) i, string name)
{ {
var (it, menu) = i; var (it, menu) = i;
if (it is NativeMenuItemSeparator) if (it is NativeMenuItemSeparator)
{ {
if (name == "type") if (name == "type")
return new Variant("separator"); return new DBusVariantItem("s", new DBusStringItem("separator"));
} }
else if (it is NativeMenuItem item) else if (it is NativeMenuItem item)
{ {
if (name == "type") if (name == "type")
return null; return null;
if (name == "label") if (name == "label")
return new Variant(item.Header ?? "<null>"); return new DBusVariantItem("s", new DBusStringItem(item.Header ?? "<null>"));
if (name == "enabled") if (name == "enabled")
{ {
if (item.Menu is not null && item.Menu.Items.Count == 0) if (item.Menu is not null && item.Menu.Items.Count == 0)
return new Variant(false); return new DBusVariantItem("b", new DBusBoolItem(false));
if (!item.IsEnabled) if (!item.IsEnabled)
return new Variant(false); return new DBusVariantItem("b", new DBusBoolItem(false));
return null; return null;
} }
if (name == "visible") if (name == "visible") {
return new Variant(item.IsVisible); if (!item.IsVisible)
return new DBusVariantItem("b", new DBusBoolItem(false));
return new DBusVariantItem("b", new DBusBoolItem(true));
}
if (name == "shortcut") if (name == "shortcut")
{ {
@ -254,30 +256,30 @@ namespace Avalonia.FreeDesktop
return null; return null;
if (item.Gesture.KeyModifiers == 0) if (item.Gesture.KeyModifiers == 0)
return null; return null;
var lst = new Array<Variant>(); var lst = new List<DBusItem>();
var mod = item.Gesture; var mod = item.Gesture;
if (mod.KeyModifiers.HasAllFlags(KeyModifiers.Control)) if (mod.KeyModifiers.HasAllFlags(KeyModifiers.Control))
lst.Add(new Variant("Control")); lst.Add(new DBusStringItem("Control"));
if (mod.KeyModifiers.HasAllFlags(KeyModifiers.Alt)) if (mod.KeyModifiers.HasAllFlags(KeyModifiers.Alt))
lst.Add(new Variant("Alt")); lst.Add(new DBusStringItem("Alt"));
if (mod.KeyModifiers.HasAllFlags(KeyModifiers.Shift)) if (mod.KeyModifiers.HasAllFlags(KeyModifiers.Shift))
lst.Add(new Variant("Shift")); lst.Add(new DBusStringItem("Shift"));
if (mod.KeyModifiers.HasAllFlags(KeyModifiers.Meta)) if (mod.KeyModifiers.HasAllFlags(KeyModifiers.Meta))
lst.Add(new Variant("Super")); lst.Add(new DBusStringItem("Super"));
lst.Add(new Variant(item.Gesture.Key.ToString())); lst.Add(new DBusStringItem(item.Gesture.Key.ToString()));
return Variant.FromArray(new Array<Array<Variant>>(new[] { lst })); return new DBusVariantItem("aas", new DBusArrayItem(DBusType.Array, new[] { new DBusArrayItem(DBusType.String, lst) }));
} }
if (name == "toggle-type") if (name == "toggle-type")
{ {
if (item.ToggleType == NativeMenuItemToggleType.CheckBox) if (item.ToggleType == NativeMenuItemToggleType.CheckBox)
return new Variant("checkmark"); return new DBusVariantItem("s", new DBusStringItem("checkmark"));
if (item.ToggleType == NativeMenuItemToggleType.Radio) if (item.ToggleType == NativeMenuItemToggleType.Radio)
return new Variant("radio"); return new DBusVariantItem("s", new DBusStringItem("radio"));
} }
if (name == "toggle-state" && item.ToggleType != NativeMenuItemToggleType.None) if (name == "toggle-state" && item.ToggleType != NativeMenuItemToggleType.None)
return new Variant(item.IsChecked ? 1 : 0); return new DBusVariantItem("i", new DBusInt32Item(item.IsChecked ? 1 : 0));
if (name == "icon-data") if (name == "icon-data")
{ {
@ -290,49 +292,50 @@ namespace Avalonia.FreeDesktop
var icon = loader.LoadIcon(item.Icon.PlatformImpl.Item); var icon = loader.LoadIcon(item.Icon.PlatformImpl.Item);
using var ms = new MemoryStream(); using var ms = new MemoryStream();
icon.Save(ms); icon.Save(ms);
return Variant.FromArray(new Array<byte>(ms.ToArray())); return new DBusVariantItem("ay", new DBusByteArrayItem(ms.ToArray()));
} }
} }
} }
if (name == "children-display") if (name == "children-display")
{ return menu is not null ? new DBusVariantItem("s", new DBusStringItem("submenu")) : null;
if (menu is not null)
return new Variant("submenu");
return null;
}
} }
return null; return null;
} }
private static Dictionary<string, Variant> GetProperties((NativeMenuItemBase? item, NativeMenu? menu) i, string[] names) private static Dictionary<string, DBusVariantItem> GetProperties((NativeMenuItemBase? item, NativeMenu? menu) i, string[] names)
{ {
if (names.Length == 0) if (names.Length == 0)
names = s_allProperties; names = s_allProperties;
var properties = new Dictionary<string, Variant>(); var properties = new Dictionary<string, DBusVariantItem>();
foreach (var n in names) foreach (var n in names)
{ {
var v = GetProperty(i, n); var v = GetProperty(i, n);
if (v.HasValue) if (v is not null)
properties.Add(n, v.Value); properties.Add(n, v);
} }
return properties; return properties;
} }
private (int, Dictionary<string, Variant>, Variant[]) GetLayout(NativeMenuItemBase? item, NativeMenu? menu, int depth, string[] propertyNames) private (int, Dictionary<string, DBusVariantItem>, DBusVariantItem[]) GetLayout(NativeMenuItemBase? item, NativeMenu? menu, int depth, string[] propertyNames)
{ {
var id = item is null ? 0 : GetId(item); var id = item is null ? 0 : GetId(item);
var props = GetProperties((item, menu), propertyNames); var props = GetProperties((item, menu), propertyNames);
var children = depth == 0 || menu is null ? Array.Empty<Variant>() : new Variant[menu.Items.Count]; var children = depth == 0 || menu is null ? Array.Empty<DBusVariantItem>() : new DBusVariantItem[menu.Items.Count];
if (menu is not null) if (menu is not null)
{ {
for (var c = 0; c < children.Length; c++) for (var c = 0; c < children.Length; c++)
{ {
var ch = menu.Items[c]; var ch = menu.Items[c];
var layout = GetLayout(ch, (ch as NativeMenuItem)?.Menu, depth == -1 ? -1 : depth - 1, propertyNames); var layout = GetLayout(ch, (ch as NativeMenuItem)?.Menu, depth == -1 ? -1 : depth - 1, propertyNames);
children[c] = Variant.FromStruct(Struct.Create(layout.Item1, new Dict<string, Variant>(layout.Item2), new Array<Variant>(layout.Item3))); children[c] = new DBusVariantItem("(ia{sv}av)", new DBusStructItem(new DBusItem[]
{
new DBusInt32Item(layout.Item1),
new DBusArrayItem(DBusType.DictEntry, layout.Item2.Select(static x => new DBusDictEntryItem(new DBusStringItem(x.Key), x.Value)).ToArray()),
new DBusArrayItem(DBusType.Variant, layout.Item3)
}));
} }
} }

36
src/Avalonia.FreeDesktop/DBusPlatformSettings.cs

@ -43,12 +43,14 @@ namespace Avalonia.FreeDesktop
try try
{ {
var version = await _settings!.GetVersionPropertyAsync(); var version = await _settings!.GetVersionPropertyAsync();
VariantValue value; DBusVariantItem value;
if (version >= 2) if (version >= 2)
value = await _settings!.ReadOneAsync("org.freedesktop.appearance", "color-scheme"); value = await _settings!.ReadOneAsync("org.freedesktop.appearance", "color-scheme");
else else
value = (await _settings!.ReadAsync("org.freedesktop.appearance", "color-scheme")).GetItem(0); value = (DBusVariantItem)(await _settings!.ReadAsync("org.freedesktop.appearance", "color-scheme")).Value;
return ToColorScheme(value.GetUInt32()); if (value.Value is DBusUInt32Item dBusUInt32Item)
return ToColorScheme(dBusUInt32Item.Value);
return null;
} }
catch (DBusException) catch (DBusException)
{ {
@ -61,12 +63,14 @@ namespace Avalonia.FreeDesktop
try try
{ {
var version = await _settings!.GetVersionPropertyAsync(); var version = await _settings!.GetVersionPropertyAsync();
VariantValue value; DBusVariantItem value;
if (version >= 2) if (version >= 2)
value = await _settings!.ReadOneAsync("org.freedesktop.appearance", "accent-color"); value = await _settings!.ReadOneAsync("org.freedesktop.appearance", "accent-color");
else else
value = (await _settings!.ReadAsync("org.freedesktop.appearance", "accent-color")).GetItem(0); value = (DBusVariantItem)(await _settings!.ReadAsync("org.freedesktop.appearance", "accent-color")).Value;
return ToAccentColor(value); if (value.Value is DBusStructItem dBusStructItem)
return ToAccentColor(dBusStructItem);
return null;
} }
catch (DBusException) catch (DBusException)
{ {
@ -74,20 +78,20 @@ namespace Avalonia.FreeDesktop
} }
} }
private void SettingsChangedHandler(Exception? exception, (string Namespace, string Key, VariantValue Value) tuple) private void SettingsChangedHandler(Exception? exception, (string @namespace, string key, DBusVariantItem value) valueTuple)
{ {
if (exception is not null) if (exception is not null)
return; return;
switch (tuple) switch (valueTuple)
{ {
case ("org.freedesktop.appearance", "color-scheme", var colorScheme): case ("org.freedesktop.appearance", "color-scheme", { } colorScheme):
_themeVariant = ToColorScheme(colorScheme.GetUInt32()); _themeVariant = ToColorScheme((colorScheme.Value as DBusUInt32Item)!.Value);
_lastColorValues = BuildPlatformColorValues(); _lastColorValues = BuildPlatformColorValues();
OnColorValuesChanged(_lastColorValues!); OnColorValuesChanged(_lastColorValues!);
break; break;
case ("org.freedesktop.appearance", "accent-color", var accentColor): case ("org.freedesktop.appearance", "accent-color", { } accentColor):
_accentColor = ToAccentColor(accentColor); _accentColor = ToAccentColor((accentColor.Value as DBusStructItem)!);
_lastColorValues = BuildPlatformColorValues(); _lastColorValues = BuildPlatformColorValues();
OnColorValuesChanged(_lastColorValues!); OnColorValuesChanged(_lastColorValues!);
break; break;
@ -116,16 +120,16 @@ namespace Avalonia.FreeDesktop
return isDark ? PlatformThemeVariant.Dark : PlatformThemeVariant.Light; return isDark ? PlatformThemeVariant.Dark : PlatformThemeVariant.Light;
} }
private static Color? ToAccentColor(VariantValue value) private static Color? ToAccentColor(DBusStructItem value)
{ {
/* /*
Indicates the system's preferred accent color as a tuple of RGB values Indicates the system's preferred accent color as a tuple of RGB values
in the sRGB color space, in the range [0,1]. in the sRGB color space, in the range [0,1].
Out-of-range RGB values should be treated as an unset accent color. Out-of-range RGB values should be treated as an unset accent color.
*/ */
var r = value.GetItem(0).GetDouble(); var r = (value[0] as DBusDoubleItem)!.Value;
var g = value.GetItem(1).GetDouble(); var g = (value[1] as DBusDoubleItem)!.Value;
var b = value.GetItem(2).GetDouble(); var b = (value[2] as DBusDoubleItem)!.Value;
if (r is < 0 or > 1 || g is < 0 or > 1 || b is < 0 or > 1) if (r is < 0 or > 1 || g is < 0 or > 1 || b is < 0 or > 1)
return null; return null;
return Color.FromRgb((byte)(r * 255), (byte)(g * 255), (byte)(b * 255)); return Color.FromRgb((byte)(r * 255), (byte)(g * 255), (byte)(b * 255));

109
src/Avalonia.FreeDesktop/DBusSystemDialog.cs

@ -59,15 +59,14 @@ namespace Avalonia.FreeDesktop
{ {
var parentWindow = $"x11:{_handle.Handle:X}"; var parentWindow = $"x11:{_handle.Handle:X}";
ObjectPath objectPath; ObjectPath objectPath;
var chooserOptions = new Dictionary<string, Variant>(); var chooserOptions = new Dictionary<string, DBusVariantItem>();
var filters = ParseFilters(options.FileTypeFilter);
if (TryParseFilters(options.FileTypeFilter, out var filters)) if (filters is not null)
chooserOptions.Add("filters", filters); chooserOptions.Add("filters", filters);
if (options.SuggestedStartLocation?.TryGetLocalPath() is { } folderPath) if (options.SuggestedStartLocation?.TryGetLocalPath() is { } folderPath)
chooserOptions.Add("current_folder", Variant.FromArray(new Array<byte>(Encoding.UTF8.GetBytes(folderPath + "\0")))); chooserOptions.Add("current_folder", new DBusVariantItem("ay", new DBusByteArrayItem(Encoding.UTF8.GetBytes(folderPath + "\0"))));
chooserOptions.Add("multiple", new DBusVariantItem("b", new DBusBoolItem(options.AllowMultiple)));
chooserOptions.Add("multiple", new Variant(options.AllowMultiple));
objectPath = await _fileChooser.OpenFileAsync(parentWindow, options.Title ?? string.Empty, chooserOptions); objectPath = await _fileChooser.OpenFileAsync(parentWindow, options.Title ?? string.Empty, chooserOptions);
@ -78,7 +77,7 @@ namespace Avalonia.FreeDesktop
if (e is not null) if (e is not null)
tsc.TrySetException(e); tsc.TrySetException(e);
else else
tsc.TrySetResult(x.Results["uris"].GetArray<string>()); tsc.TrySetResult((x.results["uris"].Value as DBusArrayItem)?.Select(static y => (y as DBusStringItem)!.Value).ToArray());
}); });
var uris = await tsc.Task ?? Array.Empty<string>(); var uris = await tsc.Task ?? Array.Empty<string>();
@ -89,14 +88,15 @@ namespace Avalonia.FreeDesktop
{ {
var parentWindow = $"x11:{_handle.Handle:X}"; var parentWindow = $"x11:{_handle.Handle:X}";
ObjectPath objectPath; ObjectPath objectPath;
var chooserOptions = new Dictionary<string, Variant>(); var chooserOptions = new Dictionary<string, DBusVariantItem>();
if (TryParseFilters(options.FileTypeChoices, out var filters)) var filters = ParseFilters(options.FileTypeChoices);
if (filters is not null)
chooserOptions.Add("filters", filters); chooserOptions.Add("filters", filters);
if (options.SuggestedFileName is { } currentName) if (options.SuggestedFileName is { } currentName)
chooserOptions.Add("current_name", new Variant(currentName)); chooserOptions.Add("current_name", new DBusVariantItem("s", new DBusStringItem(currentName)));
if (options.SuggestedStartLocation?.TryGetLocalPath() is { } folderPath) if (options.SuggestedStartLocation?.TryGetLocalPath() is { } folderPath)
chooserOptions.Add("current_folder", Variant.FromArray(new Array<byte>(Encoding.UTF8.GetBytes(folderPath + "\0")))); chooserOptions.Add("current_folder", new DBusVariantItem("ay", new DBusByteArrayItem(Encoding.UTF8.GetBytes(folderPath + "\0"))));
objectPath = await _fileChooser.SaveFileAsync(parentWindow, options.Title ?? string.Empty, chooserOptions); objectPath = await _fileChooser.SaveFileAsync(parentWindow, options.Title ?? string.Empty, chooserOptions);
var request = new OrgFreedesktopPortalRequest(_connection, "org.freedesktop.portal.Desktop", objectPath); var request = new OrgFreedesktopPortalRequest(_connection, "org.freedesktop.portal.Desktop", objectPath);
@ -105,31 +105,41 @@ namespace Avalonia.FreeDesktop
using var disposable = await request.WatchResponseAsync((e, x) => using var disposable = await request.WatchResponseAsync((e, x) =>
{ {
if (e is not null) if (e is not null)
{
tsc.TrySetException(e); tsc.TrySetException(e);
}
else else
{ {
if (x.Results.TryGetValue("current_filter", out var currentFilter)) if(x.results.TryGetValue("current_filter", out var value))
{ {
var name = currentFilter.GetItem(0).GetString(); var currentFilter = value.Value as DBusStructItem;
selectedType = new FilePickerFileType(name); if(currentFilter != null)
var patterns = new List<string>();
var mimeTypes = new List<string>();
var types = currentFilter.GetItem(1).GetArray<VariantValue>();
foreach(var t in types)
{ {
if (t.GetItem(0).GetUInt32() == 1) var name = (currentFilter[0] as DBusStringItem)?.Value.ToString() ?? "";
mimeTypes.Add(t.GetItem(1).GetString()); selectedType = new FilePickerFileType(name);
else if(currentFilter[1] is DBusArrayItem types)
patterns.Add(t.GetItem(1).GetString()); {
List<string> filters = new List<string>();
List<string> mimeTypes = new List<string>();
foreach(var t in types)
{
if(t is DBusStructItem filter)
{
if((filter[0] as DBusUInt32Item)?.Value == 1)
{
mimeTypes.Add((filter[1] as DBusStringItem)?.Value.ToString() ?? "");
}
else
{
filters.Add((filter[1] as DBusStringItem)?.Value.ToString() ?? "");
}
}
}
selectedType.Patterns = filters;
selectedType.MimeTypes = mimeTypes;
}
} }
selectedType.Patterns = patterns;
selectedType.MimeTypes = mimeTypes;
} }
tsc.TrySetResult((x.results["uris"].Value as DBusArrayItem)?.Select(static y => (y as DBusStringItem)!.Value).ToArray());
tsc.TrySetResult(x.Results["uris"].GetArray<string>());
} }
}); });
@ -150,16 +160,16 @@ namespace Avalonia.FreeDesktop
return Array.Empty<IStorageFolder>(); return Array.Empty<IStorageFolder>();
var parentWindow = $"x11:{_handle.Handle:X}"; var parentWindow = $"x11:{_handle.Handle:X}";
var chooserOptions = new Dictionary<string, Variant> var chooserOptions = new Dictionary<string, DBusVariantItem>
{ {
{ "directory", new Variant(true) }, { "directory", new DBusVariantItem("b", new DBusBoolItem(true)) },
{ "multiple", new Variant(options.AllowMultiple) } { "multiple", new DBusVariantItem("b", new DBusBoolItem(options.AllowMultiple)) }
}; };
if (options.SuggestedFileName is { } currentName) if (options.SuggestedFileName is { } currentName)
chooserOptions.Add("current_name", new Variant(currentName)); chooserOptions.Add("current_name", new DBusVariantItem("s", new DBusStringItem(currentName)));
if (options.SuggestedStartLocation?.TryGetLocalPath() is { } folderPath) if (options.SuggestedStartLocation?.TryGetLocalPath() is { } folderPath)
chooserOptions.Add("current_folder", Variant.FromArray(new Array<byte>(Encoding.UTF8.GetBytes(folderPath + "\0")))); chooserOptions.Add("current_folder", new DBusVariantItem("ay", new DBusByteArrayItem(Encoding.UTF8.GetBytes(folderPath + "\0"))));
var objectPath = await _fileChooser.OpenFileAsync(parentWindow, options.Title ?? string.Empty, chooserOptions); var objectPath = await _fileChooser.OpenFileAsync(parentWindow, options.Title ?? string.Empty, chooserOptions);
var request = new OrgFreedesktopPortalRequest(_connection, "org.freedesktop.portal.Desktop", objectPath); var request = new OrgFreedesktopPortalRequest(_connection, "org.freedesktop.portal.Desktop", objectPath);
@ -169,7 +179,7 @@ namespace Avalonia.FreeDesktop
if (e is not null) if (e is not null)
tsc.TrySetException(e); tsc.TrySetException(e);
else else
tsc.TrySetResult(x.Results["uris"].GetArray<string>()); tsc.TrySetResult((x.results["uris"].Value as DBusArrayItem)?.Select(static y => (y as DBusStringItem)!.Value).ToArray());
}); });
var uris = await tsc.Task ?? Array.Empty<string>(); var uris = await tsc.Task ?? Array.Empty<string>();
@ -180,35 +190,40 @@ namespace Avalonia.FreeDesktop
.Select(static path => new BclStorageFolder(new DirectoryInfo(path))).ToList(); .Select(static path => new BclStorageFolder(new DirectoryInfo(path))).ToList();
} }
private static bool TryParseFilters(IReadOnlyList<FilePickerFileType>? fileTypes, out Variant result) private static DBusVariantItem? ParseFilters(IReadOnlyList<FilePickerFileType>? fileTypes)
{ {
const uint GlobStyle = 0u; const uint GlobStyle = 0u;
const uint MimeStyle = 1u; const uint MimeStyle = 1u;
// Example: [('Images', [(0, '*.ico'), (1, 'image/png')]), ('Text', [(0, '*.txt')])] // Example: [('Images', [(0, '*.ico'), (1, 'image/png')]), ('Text', [(0, '*.txt')])]
if (fileTypes is null) if (fileTypes is null)
{ return null;
result = default;
return false;
}
var filters = new Array<Struct<string, Array<Struct<uint, string>>>>(); var filters = new List<DBusItem>();
foreach (var fileType in fileTypes) foreach (var fileType in fileTypes)
{ {
var extensions = new List<Struct<uint, string>>(); var extensions = new List<DBusItem>();
if (fileType.Patterns?.Count > 0) if (fileType.Patterns?.Count > 0)
extensions.AddRange(fileType.Patterns.Select(static pattern => Struct.Create(GlobStyle, pattern))); extensions.AddRange(
fileType.Patterns.Select(static pattern =>
new DBusStructItem(new DBusItem[] { new DBusUInt32Item(GlobStyle), new DBusStringItem(pattern) })));
else if (fileType.MimeTypes?.Count > 0) else if (fileType.MimeTypes?.Count > 0)
extensions.AddRange(fileType.MimeTypes.Select(static mimeType => Struct.Create(MimeStyle, mimeType))); extensions.AddRange(
fileType.MimeTypes.Select(static mimeType =>
new DBusStructItem(new DBusItem[] { new DBusUInt32Item(MimeStyle), new DBusStringItem(mimeType) })));
else else
continue; continue;
filters.Add(Struct.Create(fileType.Name, new Array<Struct<uint, string>>(extensions))); filters.Add(new DBusStructItem(
new DBusItem[]
{
new DBusStringItem(fileType.Name),
new DBusArrayItem(DBusType.Struct, extensions)
}));
} }
result = Variant.FromArray(filters); return filters.Count > 0 ? new DBusVariantItem("a(sa(us))", new DBusArrayItem(DBusType.Struct, filters)) : null;
return true;
} }
} }
} }

36
src/Avalonia.FreeDesktop/DBusTrayIconImpl.cs

@ -58,7 +58,7 @@ namespace Avalonia.FreeDesktop
MenuExporter = DBusMenuExporter.TryCreateDetachedNativeMenu(_dbusMenuPath, _connection); MenuExporter = DBusMenuExporter.TryCreateDetachedNativeMenu(_dbusMenuPath, _connection);
_statusNotifierItemDbusObj = new StatusNotifierItemDbusObj(_connection, _dbusMenuPath); _statusNotifierItemDbusObj = new StatusNotifierItemDbusObj(_connection, _dbusMenuPath);
_connection.AddMethodHandler(_statusNotifierItemDbusObj.PathHandler!); _connection.AddMethodHandler(_statusNotifierItemDbusObj);
WatchAsync(); WatchAsync();
} }
@ -84,7 +84,7 @@ namespace Avalonia.FreeDesktop
if (_isDisposed || _connection is null || name != "org.kde.StatusNotifierWatcher") if (_isDisposed || _connection is null || name != "org.kde.StatusNotifierWatcher")
return; return;
if (!_serviceConnected && newOwner is not null) if (!_serviceConnected & newOwner is not null)
{ {
_serviceConnected = true; _serviceConnected = true;
_statusNotifierWatcher = new OrgKdeStatusNotifierWatcher(_connection, "org.kde.StatusNotifierWatcher", "/StatusNotifierWatcher"); _statusNotifierWatcher = new OrgKdeStatusNotifierWatcher(_connection, "org.kde.StatusNotifierWatcher", "/StatusNotifierWatcher");
@ -216,15 +216,27 @@ namespace Avalonia.FreeDesktop
public StatusNotifierItemDbusObj(Connection connection, ObjectPath dbusMenuPath) public StatusNotifierItemDbusObj(Connection connection, ObjectPath dbusMenuPath)
{ {
Connection = connection; Connection = connection;
Menu = dbusMenuPath; BackingProperties.Menu = dbusMenuPath;
PathHandler = new PathHandler("/StatusNotifierItem"); BackingProperties.Category = string.Empty;
PathHandler.Add(this); BackingProperties.Status = string.Empty;
BackingProperties.Id = string.Empty;
BackingProperties.Title = string.Empty;
BackingProperties.IconPixmap = Array.Empty<(int, int, byte[])>();
BackingProperties.AttentionIconName = string.Empty;
BackingProperties.AttentionIconPixmap = Array.Empty<(int, int, byte[])>();
BackingProperties.AttentionMovieName = string.Empty;
BackingProperties.OverlayIconName = string.Empty;
BackingProperties.OverlayIconPixmap = Array.Empty<(int, int, byte[])>();
BackingProperties.ToolTip = (string.Empty, Array.Empty<(int, int, byte[])>(), string.Empty, string.Empty);
InvalidateAll(); InvalidateAll();
} }
protected override Connection Connection { get; }
public override string Path => "/StatusNotifierItem";
public event Action? ActivationDelegate; public event Action? ActivationDelegate;
public override Connection Connection { get; }
protected override ValueTask OnContextMenuAsync(int x, int y) => new(); protected override ValueTask OnContextMenuAsync(int x, int y) => new();
protected override ValueTask OnActivateAsync(int x, int y) protected override ValueTask OnActivateAsync(int x, int y)
@ -244,12 +256,12 @@ namespace Avalonia.FreeDesktop
EmitNewAttentionIcon(); EmitNewAttentionIcon();
EmitNewOverlayIcon(); EmitNewOverlayIcon();
EmitNewToolTip(); EmitNewToolTip();
EmitNewStatus(Status); EmitNewStatus(BackingProperties.Status);
} }
public void SetIcon((int, int, byte[]) dbusPixmap) public void SetIcon((int, int, byte[]) dbusPixmap)
{ {
IconPixmap = new[] { dbusPixmap }; BackingProperties.IconPixmap = new[] { dbusPixmap };
InvalidateAll(); InvalidateAll();
} }
@ -258,10 +270,10 @@ namespace Avalonia.FreeDesktop
if (text is null) if (text is null)
return; return;
Id = text; BackingProperties.Id = text;
Category = "ApplicationStatus"; BackingProperties.Category = "ApplicationStatus";
Status = text; BackingProperties.Status = text;
Title = text; BackingProperties.Title = text;
InvalidateAll(); InvalidateAll();
} }
} }

Loading…
Cancel
Save