|
|
|
@ -24,7 +24,7 @@ namespace Avalonia.FreeDesktop |
|
|
|
|
|
|
|
public static string GenerateDBusMenuObjPath => $"/net/avaloniaui/dbusmenu/{Guid.NewGuid():N}"; |
|
|
|
|
|
|
|
private sealed class DBusMenuExporterImpl : ComCanonicalDbusmenu, ITopLevelNativeMenuExporter, IDisposable |
|
|
|
private sealed class DBusMenuExporterImpl : ComCanonicalDbusmenuHandler, ITopLevelNativeMenuExporter, IDisposable |
|
|
|
{ |
|
|
|
private readonly Dictionary<int, NativeMenuItemBase> _idsToItems = new(); |
|
|
|
private readonly Dictionary<NativeMenuItemBase, int> _itemsToIds = new(); |
|
|
|
@ -32,7 +32,7 @@ namespace Avalonia.FreeDesktop |
|
|
|
private readonly PathHandler _pathHandler; |
|
|
|
private readonly uint _xid; |
|
|
|
private readonly bool _appMenu = true; |
|
|
|
private ComCanonicalAppMenuRegistrar? _registrar; |
|
|
|
private ComCanonicalAppMenuRegistrarProxy? _registrar; |
|
|
|
private NativeMenu? _menu; |
|
|
|
private bool _disposed; |
|
|
|
private uint _revision = 1; |
|
|
|
@ -63,7 +63,7 @@ namespace Avalonia.FreeDesktop |
|
|
|
|
|
|
|
public override Connection Connection { get; } |
|
|
|
|
|
|
|
protected override ValueTask<(uint Revision, (int, Dictionary<string, Variant>, Variant[]) Layout)> OnGetLayoutAsync(int parentId, int recursionDepth, string[] propertyNames) |
|
|
|
protected override ValueTask<(uint Revision, (int, Dictionary<string, VariantValue>, VariantValue[]) Layout)> OnGetLayoutAsync(Message message, int parentId, int recursionDepth, string[] propertyNames) |
|
|
|
{ |
|
|
|
var menu = GetMenu(parentId); |
|
|
|
var layout = GetLayout(menu.item, menu.menu, recursionDepth, propertyNames); |
|
|
|
@ -73,31 +73,31 @@ namespace Avalonia.FreeDesktop |
|
|
|
OnIsNativeMenuExportedChanged?.Invoke(this, EventArgs.Empty); |
|
|
|
} |
|
|
|
|
|
|
|
return new ValueTask<(uint, (int, Dictionary<string, Variant>, Variant[]))>((_revision, layout)); |
|
|
|
return new ValueTask<(uint, (int, Dictionary<string, VariantValue>, VariantValue[]))>((_revision, layout)); |
|
|
|
} |
|
|
|
|
|
|
|
protected override ValueTask<(int, Dictionary<string, Variant>)[]> OnGetGroupPropertiesAsync(int[] ids, string[] propertyNames) |
|
|
|
protected override ValueTask<(int, Dictionary<string, VariantValue>)[]> OnGetGroupPropertiesAsync(Message message, int[] ids, string[] propertyNames) |
|
|
|
=> new(ids.Select(id => (id, GetProperties(GetMenu(id), propertyNames))).ToArray()); |
|
|
|
|
|
|
|
protected override ValueTask<Variant> OnGetPropertyAsync(int id, string name) => |
|
|
|
new(GetProperty(GetMenu(id), name) ?? new Variant(0)); |
|
|
|
protected override ValueTask<VariantValue> OnGetPropertyAsync(Message message, int id, string name) => |
|
|
|
new(GetProperty(GetMenu(id), name) ?? VariantValue.Int32(0)); |
|
|
|
|
|
|
|
protected override ValueTask OnEventAsync(int id, string eventId, VariantValue data, uint timestamp) |
|
|
|
protected override ValueTask OnEventAsync(Message message, int id, string eventId, VariantValue data, uint timestamp) |
|
|
|
{ |
|
|
|
HandleEvent(id, eventId); |
|
|
|
return new ValueTask(); |
|
|
|
} |
|
|
|
|
|
|
|
protected override ValueTask<int[]> OnEventGroupAsync((int, string, VariantValue, uint)[] events) |
|
|
|
protected override ValueTask<int[]> OnEventGroupAsync(Message message, (int, string, VariantValue, uint)[] events) |
|
|
|
{ |
|
|
|
foreach (var e in events) |
|
|
|
HandleEvent(e.Item1, e.Item2); |
|
|
|
return new ValueTask<int[]>([]); |
|
|
|
} |
|
|
|
|
|
|
|
protected override ValueTask<bool> OnAboutToShowAsync(int id) => new(false); |
|
|
|
protected override ValueTask<bool> OnAboutToShowAsync(Message message, int id) => new(false); |
|
|
|
|
|
|
|
protected override ValueTask<(int[] UpdatesNeeded, int[] IdErrors)> OnAboutToShowGroupAsync(int[] ids) => |
|
|
|
protected override ValueTask<(int[] UpdatesNeeded, int[] IdErrors)> OnAboutToShowGroupAsync(Message message, int[] ids) => |
|
|
|
new(([], [])); |
|
|
|
|
|
|
|
private async Task InitializeAsync() |
|
|
|
@ -106,7 +106,7 @@ namespace Avalonia.FreeDesktop |
|
|
|
if (!_appMenu) |
|
|
|
return; |
|
|
|
|
|
|
|
_registrar = new ComCanonicalAppMenuRegistrar(Connection, "com.canonical.AppMenu.Registrar", "/com/canonical/AppMenu/Registrar"); |
|
|
|
_registrar = new ComCanonicalAppMenuRegistrarProxy(Connection, "com.canonical.AppMenu.Registrar", "/com/canonical/AppMenu/Registrar"); |
|
|
|
try |
|
|
|
{ |
|
|
|
if (!_disposed) |
|
|
|
@ -211,32 +211,32 @@ namespace Avalonia.FreeDesktop |
|
|
|
|
|
|
|
private static readonly string[] s_allProperties = ["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 VariantValue? GetProperty((NativeMenuItemBase? item, NativeMenu? menu) i, string name) |
|
|
|
{ |
|
|
|
var (it, menu) = i; |
|
|
|
|
|
|
|
if (it is NativeMenuItemSeparator) |
|
|
|
{ |
|
|
|
if (name == "type") |
|
|
|
return new Variant("separator"); |
|
|
|
return VariantValue.String("separator"); |
|
|
|
} |
|
|
|
else if (it is NativeMenuItem item) |
|
|
|
{ |
|
|
|
if (name == "type") |
|
|
|
return null; |
|
|
|
if (name == "label") |
|
|
|
return new Variant(item.Header ?? "<null>"); |
|
|
|
return VariantValue.String(item.Header ?? "<null>"); |
|
|
|
if (name == "enabled") |
|
|
|
{ |
|
|
|
if (item.Menu is not null && item.Menu.Items.Count == 0) |
|
|
|
return new Variant(false); |
|
|
|
return VariantValue.Bool(false); |
|
|
|
if (!item.IsEnabled) |
|
|
|
return new Variant(false); |
|
|
|
return VariantValue.Bool(false); |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
if (name == "visible") |
|
|
|
return new Variant(item.IsVisible); |
|
|
|
return VariantValue.Bool(item.IsVisible); |
|
|
|
|
|
|
|
if (name == "shortcut") |
|
|
|
{ |
|
|
|
@ -244,7 +244,7 @@ namespace Avalonia.FreeDesktop |
|
|
|
return null; |
|
|
|
if (item.Gesture.KeyModifiers == 0) |
|
|
|
return null; |
|
|
|
var lst = new Array<string>(); |
|
|
|
var lst = new List<string>(); |
|
|
|
var mod = item.Gesture; |
|
|
|
if (mod.KeyModifiers.HasAllFlags(KeyModifiers.Control)) |
|
|
|
lst.Add("Control"); |
|
|
|
@ -255,19 +255,19 @@ namespace Avalonia.FreeDesktop |
|
|
|
if (mod.KeyModifiers.HasAllFlags(KeyModifiers.Meta)) |
|
|
|
lst.Add("Super"); |
|
|
|
lst.Add(item.Gesture.Key.ToString()); |
|
|
|
return Variant.FromArray(new Array<Array<string>>([lst])); |
|
|
|
return VariantValue.ArrayOfVariant((VariantValue[]) [VariantValue.Array(lst)]); |
|
|
|
} |
|
|
|
|
|
|
|
if (name == "toggle-type") |
|
|
|
{ |
|
|
|
if (item.ToggleType == NativeMenuItemToggleType.CheckBox) |
|
|
|
return new Variant("checkmark"); |
|
|
|
return VariantValue.String("checkmark"); |
|
|
|
if (item.ToggleType == NativeMenuItemToggleType.Radio) |
|
|
|
return new Variant("radio"); |
|
|
|
return VariantValue.String("radio"); |
|
|
|
} |
|
|
|
|
|
|
|
if (name == "toggle-state" && item.ToggleType != NativeMenuItemToggleType.None) |
|
|
|
return new Variant(item.IsChecked ? 1 : 0); |
|
|
|
return VariantValue.Int32(item.IsChecked ? 1 : 0); |
|
|
|
|
|
|
|
if (name == "icon-data") |
|
|
|
{ |
|
|
|
@ -280,7 +280,7 @@ namespace Avalonia.FreeDesktop |
|
|
|
var icon = loader.LoadIcon(item.Icon.PlatformImpl.Item); |
|
|
|
using var ms = new MemoryStream(); |
|
|
|
icon.Save(ms); |
|
|
|
return Variant.FromArray(new Array<byte>(ms.ToArray())); |
|
|
|
return VariantValue.Array(ms.ToArray()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -288,7 +288,7 @@ namespace Avalonia.FreeDesktop |
|
|
|
if (name == "children-display") |
|
|
|
{ |
|
|
|
if (menu is not null) |
|
|
|
return new Variant("submenu"); |
|
|
|
return VariantValue.String("submenu"); |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -296,11 +296,11 @@ namespace Avalonia.FreeDesktop |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
private static Dictionary<string, Variant> GetProperties((NativeMenuItemBase? item, NativeMenu? menu) i, string[] names) |
|
|
|
private static Dictionary<string, VariantValue> GetProperties((NativeMenuItemBase? item, NativeMenu? menu) i, string[] names) |
|
|
|
{ |
|
|
|
if (names.Length == 0) |
|
|
|
names = s_allProperties; |
|
|
|
var properties = new Dictionary<string, Variant>(); |
|
|
|
var properties = new Dictionary<string, VariantValue>(); |
|
|
|
foreach (var n in names) |
|
|
|
{ |
|
|
|
var v = GetProperty(i, n); |
|
|
|
@ -311,18 +311,21 @@ namespace Avalonia.FreeDesktop |
|
|
|
return properties; |
|
|
|
} |
|
|
|
|
|
|
|
private (int, Dictionary<string, Variant>, Variant[]) GetLayout(NativeMenuItemBase? item, NativeMenu? menu, int depth, string[] propertyNames) |
|
|
|
private (int, Dictionary<string, VariantValue>, VariantValue[]) GetLayout(NativeMenuItemBase? item, NativeMenu? menu, int depth, string[] propertyNames) |
|
|
|
{ |
|
|
|
var id = item is null ? 0 : GetId(item); |
|
|
|
var props = GetProperties((item, menu), propertyNames); |
|
|
|
var children = depth == 0 || menu is null ? [] : new Variant[menu.Items.Count]; |
|
|
|
var children = depth == 0 || menu is null ? [] : new VariantValue[menu.Items.Count]; |
|
|
|
if (menu is not null) |
|
|
|
{ |
|
|
|
for (var c = 0; c < children.Length; c++) |
|
|
|
{ |
|
|
|
var ch = menu.Items[c]; |
|
|
|
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] = VariantValue.Struct( |
|
|
|
VariantValue.Int32(layout.Item1), |
|
|
|
new Dict<string, VariantValue>(layout.Item2), |
|
|
|
VariantValue.ArrayOfVariant(layout.Item3)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|