Browse Source

Use DBusVariantItem to manually encode/decode variants

Note: Tray-Icon submenus don't work, needs investigation
pull/9810/head
affederaffe 3 years ago
parent
commit
86b61050a0
  1. 13
      src/Avalonia.FreeDesktop/DBusIme/IBus/IBusX11TextInputMethod.cs
  2. 3
      src/Avalonia.FreeDesktop/DBusInterfaces.cs
  3. 72
      src/Avalonia.FreeDesktop/DBusMenuExporter.cs
  4. 85
      src/Avalonia.FreeDesktop/DBusPlatformSettings.cs
  5. 16
      src/Avalonia.FreeDesktop/DBusSettings.cs
  6. 74
      src/Avalonia.FreeDesktop/DBusSystemDialog.cs
  7. 99
      src/Avalonia.FreeDesktop/DBusXml/org.freedesktop.portal.Settings.xml
  8. 2
      src/Linux/Tmds.DBus
  9. 2
      src/tools/Tmds.DBus.SourceGenerator

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

@ -4,6 +4,8 @@ using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Input.TextInput;
using Tmds.DBus.Protocol;
using Tmds.DBus.SourceGenerator;
namespace Avalonia.FreeDesktop.DBusIme.IBus
{
@ -49,18 +51,13 @@ namespace Avalonia.FreeDesktop.DBusIme.IBus
});
}
private void OnCommitText(Exception? e, object wtf)
private void OnCommitText(Exception? e, DBusVariantItem variantItem)
{
if (e is not null)
return;
// Hello darkness, my old friend
if (wtf.GetType().GetField("Item3") is { } prop)
{
var text = prop.GetValue(wtf) as string;
if (!string.IsNullOrEmpty(text))
FireCommit(text!);
}
if (variantItem.Value is DBusStructItem { Count: >= 3 } structItem && structItem[2] is DBusStringItem stringItem)
FireCommit(stringItem.Value);
}
protected override Task DisconnectAsync() => _service?.DestroyAsync() ?? Task.CompletedTask;

3
src/Avalonia.FreeDesktop/DBusInterfaces.cs

@ -9,9 +9,10 @@ namespace Avalonia.FreeDesktop
[DBusInterface("./DBusXml/org.fcitx.Fcitx.InputMethod.xml")]
[DBusInterface("./DBusXml/org.fcitx.Fcitx.InputContext1.xml")]
[DBusInterface("./DBusXml/org.fcitx.Fcitx.InputMethod1.xml")]
[DBusInterface("./DBusXml/org.freedesktop.IBus.Portal.xml")]
[DBusInterface("./DBusXml/org.freedesktop.portal.FileChooser.xml")]
[DBusInterface("./DBusXml/org.freedesktop.portal.Request.xml")]
[DBusInterface("./DBusXml/org.freedesktop.IBus.Portal.xml")]
[DBusInterface("./DBusXml/org.freedesktop.portal.Settings.xml")]
[DBusHandler("./DBusXml/DBusMenu.xml")]
[DBusHandler("./DBusXml/StatusNotifierItem.xml")]
internal class DBusInterfaces { }

72
src/Avalonia.FreeDesktop/DBusMenuExporter.cs

@ -9,8 +9,7 @@ using Avalonia.Input;
using Avalonia.Platform;
using Avalonia.Threading;
using Tmds.DBus.Protocol;
#pragma warning disable 1998
using Tmds.DBus.SourceGenerator;
namespace Avalonia.FreeDesktop
{
@ -60,7 +59,7 @@ namespace Avalonia.FreeDesktop
public override string Path { get; }
protected override (uint revision, (int, Dictionary<string, object>, object[]) layout) OnGetLayout(int parentId, int recursionDepth, string[] propertyNames)
protected override (uint revision, (int, Dictionary<string, DBusVariantItem>, DBusVariantItem[]) layout) OnGetLayout(int parentId, int recursionDepth, string[] propertyNames)
{
var menu = GetMenu(parentId);
var layout = GetLayout(menu.item, menu.menu, recursionDepth, propertyNames);
@ -73,15 +72,15 @@ namespace Avalonia.FreeDesktop
return (_revision, layout);
}
protected override (int, Dictionary<string, object>)[] OnGetGroupProperties(int[] ids, string[] propertyNames) =>
protected override (int, Dictionary<string, DBusVariantItem>)[] OnGetGroupProperties(int[] ids, string[] propertyNames) =>
ids.Select(id => (id, GetProperties(GetMenu(id), propertyNames))).ToArray();
protected override object OnGetProperty(int id, string name) => GetProperty(GetMenu(id), name) ?? 0;
protected override DBusVariantItem OnGetProperty(int id, string name) => GetProperty(GetMenu(id), name) ?? new DBusVariantItem("i", new DBusInt32Item(0));
protected override void OnEvent(int id, string eventId, object data, uint timestamp) =>
protected override void OnEvent(int id, string eventId, DBusVariantItem data, uint timestamp) =>
Dispatcher.UIThread.Post(() => HandleEvent(id, eventId));
protected override int[] OnEventGroup((int, string, object, uint)[] events)
protected override int[] OnEventGroup((int, string, DBusVariantItem, uint)[] events)
{
foreach (var e in events)
Dispatcher.UIThread.Post(() => HandleEvent(e.Item1, e.Item2));
@ -115,14 +114,14 @@ namespace Avalonia.FreeDesktop
if (_disposed)
return;
_disposed = true;
// Fire and forget
_registrar?.UnregisterWindowAsync(_xid);
_ = _registrar?.UnregisterWindowAsync(_xid);
}
public bool IsNativeMenuExported { get; private set; }
public event EventHandler? OnIsNativeMenuExportedChanged;
public void SetNativeMenu(NativeMenu? menu)
@ -203,31 +202,31 @@ namespace Avalonia.FreeDesktop
QueueReset();
}
private static readonly string[] AllProperties = {
private static readonly string[] s_allProperties = {
"type", "label", "enabled", "visible", "shortcut", "toggle-type", "children-display", "toggle-state", "icon-data"
};
private object? GetProperty((NativeMenuItemBase? item, NativeMenu? menu) i, string name)
private DBusVariantItem? GetProperty((NativeMenuItemBase? item, NativeMenu? menu) i, string name)
{
var (it, menu) = i;
if (it is NativeMenuItemSeparator)
{
if (name == "type")
return "separator";
return new DBusVariantItem("s", new DBusStringItem("separator"));
}
else if (it is NativeMenuItem item)
{
if (name == "type")
return null;
if (name == "label")
return item.Header ?? "<null>";
return new DBusVariantItem("s", new DBusStringItem(item.Header ?? "<null>"));
if (name == "enabled")
{
if (item.Menu is not null && item.Menu.Items.Count == 0)
return false;
return new DBusVariantItem("b", new DBusBoolItem(false));
if (!item.IsEnabled)
return false;
return new DBusVariantItem("b", new DBusBoolItem(false));
return null;
}
if (name == "shortcut")
@ -236,30 +235,30 @@ namespace Avalonia.FreeDesktop
return null;
if (item.Gesture.KeyModifiers == 0)
return null;
var lst = new List<string>();
var lst = new List<DBusItem>();
var mod = item.Gesture;
if (mod.KeyModifiers.HasAllFlags(KeyModifiers.Control))
lst.Add("Control");
lst.Add(new DBusStringItem("Control"));
if (mod.KeyModifiers.HasAllFlags(KeyModifiers.Alt))
lst.Add("Alt");
lst.Add(new DBusStringItem("Alt"));
if (mod.KeyModifiers.HasAllFlags(KeyModifiers.Shift))
lst.Add("Shift");
lst.Add(new DBusStringItem("Shift"));
if (mod.KeyModifiers.HasAllFlags(KeyModifiers.Meta))
lst.Add("Super");
lst.Add(item.Gesture.Key.ToString());
return new[] { lst.ToArray() };
lst.Add(new DBusStringItem("Super"));
lst.Add(new DBusStringItem(item.Gesture.Key.ToString()));
return new DBusVariantItem("aas", new DBusArrayItem(DBusType.Array, new[] { new DBusArrayItem(DBusType.String, lst) }));
}
if (name == "toggle-type")
{
if (item.ToggleType == NativeMenuItemToggleType.CheckBox)
return "checkmark";
return new DBusVariantItem("s", new DBusStringItem("checkmark"));
if (item.ToggleType == NativeMenuItemToggleType.Radio)
return "radio";
return new DBusVariantItem("s", new DBusStringItem("radio"));
}
if (name == "toggle-state" && item.ToggleType != NativeMenuItemToggleType.None)
return item.IsChecked ? 1 : 0;
return new DBusVariantItem("i", new DBusInt32Item(item.IsChecked ? 1 : 0));
if (name == "icon-data")
{
@ -273,23 +272,24 @@ namespace Avalonia.FreeDesktop
using var ms = new MemoryStream();
icon.Save(ms);
return ms.ToArray();
return new DBusVariantItem("ay",
new DBusArrayItem(DBusType.Byte, ms.ToArray().Select(static x => new DBusByteItem(x))));
}
}
}
if (name == "children-display")
return menu is not null ? "submenu" : null;
return menu is not null ? new DBusVariantItem("s", new DBusStringItem("submenu")) : null;
}
return null;
}
private Dictionary<string, object> GetProperties((NativeMenuItemBase? item, NativeMenu? menu) i, string[] names)
private Dictionary<string, DBusVariantItem> GetProperties((NativeMenuItemBase? item, NativeMenu? menu) i, string[] names)
{
if (names.Length == 0)
names = AllProperties;
var properties = new Dictionary<string, object>();
names = s_allProperties;
var properties = new Dictionary<string, DBusVariantItem>();
foreach (var n in names)
{
var v = GetProperty(i, n);
@ -300,17 +300,23 @@ namespace Avalonia.FreeDesktop
return properties;
}
private (int, Dictionary<string, object>, object[]) 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 props = GetProperties((item, menu), propertyNames);
var children = depth == 0 || menu is null ? Array.Empty<object>() : new object[menu.Items.Count];
var children = depth == 0 || menu is null ? Array.Empty<DBusVariantItem>() : new DBusVariantItem[menu.Items.Count];
if (menu is not null)
{
for (var c = 0; c < children.Length; c++)
{
var ch = menu.Items[c];
children[c] = 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] = 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))),
new DBusArrayItem(DBusType.Variant, layout.Item3)
}));
}
}

85
src/Avalonia.FreeDesktop/DBusPlatformSettings.cs

@ -2,44 +2,35 @@
using System.Threading.Tasks;
using Avalonia.Logging;
using Avalonia.Platform;
using Tmds.DBus.SourceGenerator;
namespace Avalonia.FreeDesktop;
internal class DBusPlatformSettings : DefaultPlatformSettings
namespace Avalonia.FreeDesktop
{
private readonly IDBusSettings? _settings;
private PlatformColorValues? _lastColorValues;
public DBusPlatformSettings()
internal class DBusPlatformSettings : DefaultPlatformSettings
{
_settings = DBusHelper.TryInitialize()?
.CreateProxy<IDBusSettings>("org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop");
private readonly OrgFreedesktopPortalSettings? _settings;
private PlatformColorValues? _lastColorValues;
if (_settings is not null)
public DBusPlatformSettings()
{
_ = _settings.WatchSettingChangedAsync(SettingsChangedHandler);
if (DBusHelper.Connection is null)
return;
_ = TryGetInitialValue();
_settings = new OrgFreedesktopPortalSettings(DBusHelper.Connection, "org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop");
_ = _settings.WatchSettingChangedAsync(SettingsChangedHandler);
_ = TryGetInitialValueAsync();
}
}
public override PlatformColorValues GetColorValues()
{
return _lastColorValues ?? base.GetColorValues();
}
private async Task TryGetInitialValue()
{
var colorSchemeTask = _settings!.ReadAsync("org.freedesktop.appearance", "color-scheme");
if (colorSchemeTask.Status == TaskStatus.RanToCompletion)
public override PlatformColorValues GetColorValues()
{
_lastColorValues = GetColorValuesFromSetting(colorSchemeTask.Result);
return _lastColorValues ?? base.GetColorValues();
}
else
private async Task TryGetInitialValueAsync()
{
try
{
var value = await colorSchemeTask;
var value = await _settings!.ReadAsync("org.freedesktop.appearance", "color-scheme");
_lastColorValues = GetColorValuesFromSetting(value);
OnColorValuesChanged(_lastColorValues);
}
@ -49,29 +40,31 @@ internal class DBusPlatformSettings : DefaultPlatformSettings
Logger.TryGet(LogEventLevel.Error, LogArea.FreeDesktopPlatform)?.Log(this, "Unable to get setting value", ex);
}
}
}
private void SettingsChangedHandler((string @namespace, string key, object value) tuple)
{
if (tuple.@namespace == "org.freedesktop.appearance"
&& tuple.key == "color-scheme")
private void SettingsChangedHandler(Exception? exception, (string @namespace, string key, DBusVariantItem value) valueTuple)
{
/*
<member>0: No preference</member>
<member>1: Prefer dark appearance</member>
<member>2: Prefer light appearance</member>
*/
_lastColorValues = GetColorValuesFromSetting(tuple.value);
OnColorValuesChanged(_lastColorValues);
if (exception is not null)
return;
if (valueTuple is ("org.freedesktop.appearance", "color-scheme", { } value))
{
/*
<member>0: No preference</member>
<member>1: Prefer dark appearance</member>
<member>2: Prefer light appearance</member>
*/
_lastColorValues = GetColorValuesFromSetting(value);
OnColorValuesChanged(_lastColorValues);
}
}
}
private static PlatformColorValues GetColorValuesFromSetting(object value)
{
var isDark = value?.ToString() == "1";
return new PlatformColorValues
private static PlatformColorValues GetColorValuesFromSetting(DBusVariantItem value)
{
ThemeVariant = isDark ? PlatformThemeVariant.Dark : PlatformThemeVariant.Light
};
var isDark = ((value.Value as DBusVariantItem)!.Value as DBusUInt32Item)!.Value == 1;
return new PlatformColorValues
{
ThemeVariant = isDark ? PlatformThemeVariant.Dark : PlatformThemeVariant.Light
};
}
}
}

16
src/Avalonia.FreeDesktop/DBusSettings.cs

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Tmds.DBus;
namespace Avalonia.FreeDesktop;
[DBusInterface("org.freedesktop.portal.Settings")]
internal interface IDBusSettings : IDBusObject
{
Task<(string @namespace, IDictionary<string, object>)> ReadAllAsync(string[] namespaces);
Task<object> ReadAsync(string @namespace, string key);
Task<IDisposable> WatchSettingChangedAsync(Action<(string @namespace, string key, object value)> handler, Action<Exception>? onError = null);
}

74
src/Avalonia.FreeDesktop/DBusSystemDialog.cs

@ -2,12 +2,12 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Platform;
using Avalonia.Platform.Storage;
using Avalonia.Platform.Storage.FileIO;
using Tmds.DBus.Protocol;
using Tmds.DBus.SourceGenerator;
namespace Avalonia.FreeDesktop
{
@ -44,12 +44,12 @@ namespace Avalonia.FreeDesktop
{
var parentWindow = $"x11:{_handle.Handle:X}";
ObjectPath objectPath;
var chooserOptions = new Dictionary<string, object>();
var chooserOptions = new Dictionary<string, DBusVariantItem>();
var filters = ParseFilters(options.FileTypeFilter);
if (filters.Any())
if (filters is not null)
chooserOptions.Add("filters", filters);
chooserOptions.Add("multiple", options.AllowMultiple);
chooserOptions.Add("multiple", new DBusVariantItem("b", new DBusBoolItem(options.AllowMultiple)));
objectPath = await _fileChooser.OpenFileAsync(parentWindow, options.Title ?? string.Empty, chooserOptions);
@ -58,9 +58,8 @@ namespace Avalonia.FreeDesktop
using var disposable = await request.WatchResponseAsync((e, x) =>
{
if (e is not null)
tsc.TrySetException(e);
else
tsc.TrySetResult(x.results["uris"] as string[]);
return;
tsc.TrySetResult((x.results["uris"].Value as DBusArrayItem)?.Select(static y => (y as DBusStringItem)!.Value).ToArray());
});
var uris = await tsc.Task ?? Array.Empty<string>();
@ -71,15 +70,15 @@ namespace Avalonia.FreeDesktop
{
var parentWindow = $"x11:{_handle.Handle:X}";
ObjectPath objectPath;
var chooserOptions = new Dictionary<string, object>();
var chooserOptions = new Dictionary<string, DBusVariantItem>();
var filters = ParseFilters(options.FileTypeChoices);
if (filters.Any())
if (filters is not null)
chooserOptions.Add("filters", filters);
if (options.SuggestedFileName is { } currentName)
chooserOptions.Add("current_name", currentName);
chooserOptions.Add("current_name", new DBusVariantItem("s", new DBusStringItem(currentName)));
if (options.SuggestedStartLocation?.TryGetUri(out var currentFolder) == true)
chooserOptions.Add("current_folder", Encoding.UTF8.GetBytes(currentFolder.ToString()));
chooserOptions.Add("current_folder", new DBusVariantItem("s", new DBusStringItem(currentFolder.ToString())));
objectPath = await _fileChooser.SaveFileAsync(parentWindow, options.Title ?? string.Empty, chooserOptions);
var request = new OrgFreedesktopPortalRequest(_connection, "org.freedesktop.portal.Desktop", objectPath);
@ -87,9 +86,8 @@ namespace Avalonia.FreeDesktop
using var disposable = await request.WatchResponseAsync((e, x) =>
{
if (e is not null)
tsc.TrySetException(e);
else
tsc.TrySetResult(x.results["uris"] as string[]);
return;
tsc.TrySetResult((x.results["uris"].Value as DBusArrayItem)?.Select(static y => (y as DBusStringItem)!.Value).ToArray());
});
var uris = await tsc.Task;
@ -106,10 +104,10 @@ namespace Avalonia.FreeDesktop
public override async Task<IReadOnlyList<IStorageFolder>> OpenFolderPickerAsync(FolderPickerOpenOptions options)
{
var parentWindow = $"x11:{_handle.Handle:X}";
var chooserOptions = new Dictionary<string, object>
var chooserOptions = new Dictionary<string, DBusVariantItem>
{
{ "directory", true },
{ "multiple", options.AllowMultiple }
{ "directory", new DBusVariantItem("b", new DBusBoolItem(true)) },
{ "multiple", new DBusVariantItem("b", new DBusBoolItem(options.AllowMultiple)) }
};
var objectPath = await _fileChooser.OpenFileAsync(parentWindow, options.Title ?? string.Empty, chooserOptions);
@ -118,9 +116,8 @@ namespace Avalonia.FreeDesktop
using var disposable = await request.WatchResponseAsync((e, x) =>
{
if (e is not null)
tsc.TrySetException(e);
else
tsc.TrySetResult(x.results["uris"] as string[]);
return;
tsc.TrySetResult((x.results["uris"].Value as DBusArrayItem)?.Select(static y => (y as DBusStringItem)!.Value).ToArray());
});
var uris = await tsc.Task ?? Array.Empty<string>();
@ -131,29 +128,38 @@ namespace Avalonia.FreeDesktop
.Select(static path => new BclStorageFolder(new DirectoryInfo(path))).ToList();
}
private static (string name, (uint style, string extension)[])[] ParseFilters(IReadOnlyList<FilePickerFileType>? fileTypes)
private static DBusVariantItem? ParseFilters(IReadOnlyList<FilePickerFileType>? fileTypes)
{
const uint GlobStyle = 0u;
const uint MimeStyle = 1u;
// Example: [('Images', [(0, '*.ico'), (1, 'image/png')]), ('Text', [(0, '*.txt')])]
if (fileTypes is null)
return Array.Empty<(string name, (uint style, string extension)[])>();
return null;
var any = false;
var filters = new DBusArrayItem(DBusType.Struct, new List<DBusItem>());
var filters = new List<(string name, (uint style, string extension)[])>();
foreach (var fileType in fileTypes)
{
const uint GlobStyle = 0u;
const uint MimeStyle = 1u;
var extensions = Enumerable.Empty<(uint, string)>();
var extensions = new List<DBusItem>();
if (fileType.Patterns?.Count > 0)
extensions.AddRange(
fileType.Patterns.Select(static pattern =>
new DBusStructItem(new DBusItem[] { new DBusUInt32Item(GlobStyle), new DBusStringItem(pattern) })));
else if (fileType.MimeTypes?.Count > 0)
extensions.AddRange(
fileType.MimeTypes.Select(static mimeType =>
new DBusStructItem(new DBusItem[] { new DBusUInt32Item(MimeStyle), new DBusStringItem(mimeType) })));
else
continue;
if (fileType.Patterns is not null)
extensions = extensions.Concat(fileType.Patterns.Select(static x => (globStyle: GlobStyle, x)));
else if (fileType.MimeTypes is not null)
extensions = extensions.Concat(fileType.MimeTypes.Select(static x => (mimeStyle: MimeStyle, x)));
if (extensions.Any())
filters.Add((fileType.Name, extensions.ToArray()));
any = true;
filters.Add(new DBusStructItem(
new DBusItem[] { new DBusStringItem(fileType.Name), new DBusArrayItem(DBusType.Struct, extensions) }));
}
return filters.ToArray();
return any ? new DBusVariantItem("a(sa(us))", filters) : null;
}
}
}

99
src/Avalonia.FreeDesktop/DBusXml/org.freedesktop.portal.Settings.xml

@ -0,0 +1,99 @@
<?xml version="1.0"?>
<!--
Copyright (C) 2018 Igalia S.L.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
Author: Patrick Griffis <pgriffis@igalia.com>
-->
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
<!--
org.freedesktop.portal.Settings:
@short_description: Settings interface
This interface provides read-only access to a small number
of host settings required for toolkits similar to XSettings.
It is not for general purpose settings.
Currently the interface provides the following keys:
<variablelist>
<varlistentry>
<term>org.freedesktop.appearance color-scheme u</term>
<listitem><para>
Indicates the system's preferred color scheme.
Supported values are:
<simplelist>
<member>0: No preference</member>
<member>1: Prefer dark appearance</member>
<member>2: Prefer light appearance</member>
</simplelist>
Unknown values should be treated as 0 (no preference).
</para></listitem>
</varlistentry>
</variablelist>
Implementations can provide other keys; they are entirely
implementation details that are undocumented. If you are a
toolkit and want to use this please open an issue.
This documentation describes version 1 of this interface.
-->
<interface name="org.freedesktop.portal.Settings">
<!--
ReadAll:
@namespaces: List of namespaces to filter results by, supports simple globbing explained below.
@value: Dictionary of namespaces to its keys and values.
If @namespaces is an empty array or contains an empty string it matches all. Globbing is supported but only for
trailing sections, e.g. "org.example.*".
-->
<method name='ReadAll'>
<arg name='namespaces' type='as'/>
<arg name='value' direction='out' type='a{sa{sv}}'/>
</method>
<!--
Read:
@namespace: Namespace to look up @key in.
@key: The key to get.
@value: The value @key is set to.
Reads a single value. Returns an error on any unknown namespace or key.
-->
<method name='Read'>
<arg name='namespace' type='s'/>
<arg name='key' type='s'/>
<arg name='value' direction='out' type='v'/>
</method>
<!--
SettingChanged:
@namespace: Namespace of changed setting.
@key: The key of changed setting.
@value: The new value.
Emitted when a setting changes.
-->
<signal name='SettingChanged'>
<arg name='namespace' direction='out' type='s'/>
<arg name='key' direction='out' type='s'/>
<arg name='value' direction='out' type='v'/>
</signal>
<property name="version" type="u" access="read"/>
</interface>
</node>

2
src/Linux/Tmds.DBus

@ -1 +1 @@
Subproject commit bfca94ab052683c7ccef51e4a036098f539cc676
Subproject commit e86bcf1bc2d86338ab61663a4ae48dbc0bd7e02d

2
src/tools/Tmds.DBus.SourceGenerator

@ -1 +1 @@
Subproject commit 6007f27d04691f7c4c35722df3dc65bf4b558f18
Subproject commit 86e0ded07fc8622e216f93f8fc01e8c1b3ef29b1
Loading…
Cancel
Save