I want to send dbus messages to other applications from Awesome WM. However, the documentation for Awesome's dbus interfact is pretty minimalistic, and I can't find any examples. How to do that? For example, I want to use the Inhibit
function in org.freedesktop.login1
.
Awesome's built-in poor man's DBus wrapper barely contains enough support for DBus to have its built-in notification daemon (naughty) work: https://github.com/awesomeWM/awesome/blob/259c4f716fbd08b4507ebb4cb4d40fe5cbabed0f/dbus.c#L858-L870
This API allows you to implement an object available via DBus and to emit signals, but not to call DBus methods. Looking at some docs, it seems like the Inhibit
interface is a method that you have to call. Even worse - it returns a file descriptor!
With lots of reading of GIO's documentation, I came up with the following (hopefully self-explanatory; but also please read https://github.com/pavouk/lgi/blob/master/docs/gio.md) example:
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)()
If you want, you can turn the above into something synchronous by replacing calls to async_foo
with calls to foo_sync
. That also allows to get rid of the hack to make bus_get_async()
work and the Gio.Async.call
wrapper around everything.