【问题标题】:vala beginner: how to access DBus properties>vala 初学者:如何访问 DBus 属性>
【发布时间】:2022-04-17 20:32:22
【问题描述】:

我正在尝试将以下 python 代码转换为 vala

def powerStatusAvailable():
    """
    Check if org.freedesktop.UPower is available so that
    :py:func:`tools.onBattery` would return the correct power status.
    Returns:
        bool:   ``True`` if :py:func:`tools.onBattery` can report power status
    """
    if dbus:
        try:
            bus = dbus.SystemBus()
            proxy = bus.get_object('org.freedesktop.UPower',
                                   '/org/freedesktop/UPower')
            return 'OnBattery' in proxy.GetAll('org.freedesktop.UPower',
                            dbus_interface = 'org.freedesktop.DBus.Properties')
        except dbus.exceptions.DBusException:
            pass
    return False

作为一个完整的 vala 初学者,我非常迷茫。 我不了解对象层次结构。 文档和示例使用类 Bus。 还有一个类 DBusProxy 我应该使用那个吗? ...它有一个方法 get_cached_property_names

Bus 和 DBusProxy 有什么区别?

这是我的尝试,但当然失败了。

  using GLib;

// example of a DBus client
[DBus (name = "org.freedesktop.UPower")]
interface UPowerManager : GLib.Object {
    public abstract GLib.ObjectPath[] enumerate_devices () throws GLib.DBusError,GLib.IOError;
    public abstract GLib.ObjectPath get_display_device () throws GLib.DBusError,GLib.IOError;
    public abstract string get_critical_action () throws GLib.DBusError,GLib.IOError;
    public abstract string[] get_cached_property_names () throws GLib.DBusError,GLib.IOError;


}

int main (string[] args)
{

    UPowerManager upower_manager;
    upower_manager = Bus.get_proxy_sync(BusType.SYSTEM,"org.freedesktop.UPower","/org/freedesktop/UPower");
    string[] property_names;
    property_names = upower_manager.get_cached_property_names();


    stdout.printf ("Hello, World!\n");

    return 0;
}

但是编译出错

未捕获的错误:GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod:没有这样的方法 'GetCachedPropertyNames'

【问题讨论】:

    标签: vala


    【解决方案1】:

    这是我所做的:

    首先我使用DBus.Introspectable得到了XML定义:

    dbus-send --system --print-reply --type=method_call --dest=org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.DBus.Introspectable.Introspect
    

    您可以将该命令的结果转储到 .xml 文件中,但请确保仅包含 XML,该文件应如下所示:

    <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
                          "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
    <!-- GDBus 2.58.3 -->
    <node>
      <interface name="org.freedesktop.DBus.Properties">
      … and so on
    </node>
    

    下一步是使用您可以从https://github.com/freesmartphone/vala-dbus-binding-tool 获得的vala-dbus-binding-tool 创建接口

    vala-dbus-binding-tool -v
    

    这将生成一些 vala 文件,其中一个包含org.freedesktop.UPower 的正确接口。

    剩下的就是使用它,这很容易,这里有一个简单的例子:

    [DBus (name = "org.freedesktop.UPower", timeout = 120000)]
    public interface UPower : GLib.Object {
        [DBus (name = "EnumerateDevices")]
        public abstract async GLib.ObjectPath[] enumerate_devices() throws DBusError, IOError;
    
        [DBus (name = "GetDisplayDevice")]
        public abstract async GLib.ObjectPath get_display_device() throws DBusError, IOError;
    
        [DBus (name = "GetCriticalAction")]
        public abstract async string get_critical_action() throws DBusError, IOError;
    
        [DBus (name = "DeviceAdded")]
        public signal void device_added(GLib.ObjectPath device);
    
        [DBus (name = "DeviceRemoved")]
        public signal void device_removed(GLib.ObjectPath device);
    
        [DBus (name = "DaemonVersion")]
        public abstract string daemon_version { owned get; }
    
        [DBus (name = "OnBattery")]
        public abstract bool on_battery {  get; }
    
        [DBus (name = "LidIsClosed")]
        public abstract bool lid_is_closed {  get; }
    
        [DBus (name = "LidIsPresent")]
        public abstract bool lid_is_present {  get; }
    }
    
    int main (string[] args)
    {
        UPower upower;
        upower = Bus.get_proxy_sync(BusType.SYSTEM, "org.freedesktop.UPower",
                                    "/org/freedesktop/UPower");
    
        if (upower.on_battery) {
            stdout.printf ("System is running on battery\n");
        }
        else {
            stdout.printf ("System is running on line current\n");
        }
    
        return 0;
    }
    

    关于 GLib.Bus 与 GLib.DBusProxy 的问题。

    我不是专家,但如果您查看生成的 C 代码(您可以通过 valac -C 获得):

    static gboolean
    upower_dbus_proxy_get_on_battery (UPower* self)
    {
        GVariant *_inner_reply;
        gboolean _result;
        _inner_reply = g_dbus_proxy_get_cached_property ((GDBusProxy *) self, "OnBattery");
        if (!_inner_reply) {
            GVariant *_arguments;
            GVariant *_reply;
            GVariantBuilder _arguments_builder;
            g_variant_builder_init (&_arguments_builder, G_VARIANT_TYPE_TUPLE);
            g_variant_builder_add_value (&_arguments_builder, g_variant_new_string ("org.freedesktop.UPower"));
            g_variant_builder_add_value (&_arguments_builder, g_variant_new_string ("OnBattery"));
            _arguments = g_variant_builder_end (&_arguments_builder);
            _reply = g_dbus_proxy_call_sync ((GDBusProxy *) self, "org.freedesktop.DBus.Properties.Get", _arguments, G_DBUS_CALL_FLAGS_NONE, 120000, NULL, NULL);
            if (!_reply) {
                gboolean _tmp8_ = FALSE;
                return _tmp8_;
            }
            g_variant_get (_reply, "(v)", &_inner_reply);
            g_variant_unref (_reply);
        }
        _result = g_variant_get_boolean (_inner_reply);
        g_variant_unref (_inner_reply);
        return _result;
    }
    

    DBus 标记接口的高级魔法将自动在内部 DBusProxy 对象上调用其方法,无需在 Vala 中自己编写低级代码。

    【讨论】:

    • 你知道访问另一个 API DBusProxy 吗?
    • 我在答案中添加了一个部分。 DBusProxy 不是另一个 API,而是在你使用 Bus.get_proxy_sync() 方法和 GBus 属性标记的接口时在后台使用。
    • _reply 的那一行被截断了,不是吗?我在末尾看到了一个$,这让我想起了 nano 在行尾有更多内容时使用的字符。
    • 是的,我修好了。感谢您发现错误。
    猜你喜欢
    • 2019-03-05
    • 2011-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-26
    • 1970-01-01
    • 2011-02-24
    相关资源
    最近更新 更多