如何在 Awesome WM 中调用 dbus 方法?

How to call dbus methods in Awesome WM?

我想从 Awesome WM 向其他应用程序发送 dbus 消息。但是,Awesome 的 dbus 接口的文档非常简单,我找不到任何示例。怎么做?比如我想在org.freedesktop.login1.

中使用Inhibit函数

Awesome 的内置穷人 DBus 包装器几乎不包含对 DBus 的足够支持以使其内置通知守护程序(顽皮)工作:https://github.com/awesomeWM/awesome/blob/259c4f716fbd08b4507ebb4cb4d40fe5cbabed0f/dbus.c#L858-L870

此 API 允许您通过 DBus 实现可用的对象并发出信号,但不能调用 DBus 方法。查看 some docs,似乎 Inhibit 接口是您必须调用的方法。更糟糕的是 - 它 returns 一个文件描述符!

通过大量阅读 GIO 的文档,我想到了以下(希望不言自明;但也请阅读 https://github.com/pavouk/lgi/blob/master/docs/gio.md)示例:

local lgi = require("lgi")
local Gio = lgi.require("Gio")
local GLib = lgi.require("GLib")

-- Workaround for https://github.com/pavouk/lgi/issues/142
local function bus_get_async(type)
    Gio.bus_get(type, nil, coroutine.running())
    local a, b = coroutine.yield()
    return Gio.bus_get_finish(b)
end

local function inhibit(bus, what, who, why, mode)
    local name = "org.freedesktop.login1"
    local object = "/org/freedesktop/login1"
    local interface = "org.freedesktop.login1.Manager"
    local message = Gio.DBusMessage.new_method_call(name, object, interface, "Inhibit")
    message:set_body(GLib.Variant("(ssss)",
        { what, who, why, mode }))

    local timeout = -1 -- Just use the default
    local result, err = bus:async_send_message_with_reply(message, Gio.DBusSendMessageFlags.NONE,
        timeout, nil)

    if err then
        print("error: " .. tostring(err))
        return
    end

    if result:get_message_type() == "ERROR" then
        local _, err = result:to_gerror()
        print("error: " .. tostring(err))
        return
    end

    local fd_list = result:get_unix_fd_list()
    local fd, err = fd_list:get(0)
    if err then
        print("error: " .. tostring(err))
        return
    end

    -- Now... somehow turn this fd into something we can close
    return Gio.UnixInputStream.new(fd, true)
end

Gio.Async.call(function()
    local bus = bus_get_async(Gio.BusType.SYSTEM)
    local a = inhibit(bus, "shutdown:sleep", "hi, it's me!", "Just because", "delay")
    print("got lock")
    io.popen("sleep 10"):read("*a")
    a:async_close()
    -- Speed up deletion of the GDBusMessage that still references the FD
    collectgarbage("collect")
    collectgarbage("collect")

    print("released lock")
    io.popen("sleep 10"):read("*a")
end)()

如果需要,您可以将对 async_foo 的调用替换为对 foo_sync 的调用,从而将上述内容变成同步的。这也允许摆脱使 bus_get_async() 工作的 hack 和 Gio.Async.call 包装一切。