Open joseigor opened 3 years ago
Do you happen to have some C example code for me to translate?
Last time I looked at this, I gave up since I failed to figure out how "all the pieces fit together".
(From the top of my head: I also don't know how the subclassing works exactly. But hopefully I can figure this out when I don't have to figure out Gio's dbus code at the same time.)
@psychon thanks for the quick replay. In this moment I am able to create a instance of DBusInterfaceSkeleton, see code below, but now by some reason I get a SEGMENTATION FAULT when I try to add an interface to a object. I tried to debug the reason of the error but without success. Last line of code below just cause the SEGMENTATION FAULT.
local lgi = require("lgi")
local Gio = lgi.Gio
local GObject = lgi.GObject
local GLib = lgi.GLib
local MyApp = lgi.package 'MyApp'
MyApp:class('MyDBusInterfaceSkeleton', Gio.DBusInterfaceSkeleton)
-- Override get_info() method of Gio.DBusInterfaceSkeleton
function MyApp.MyDBusInterfaceSkeleton:do_get_info()
return Gio.DBusInterfaceInfo{
name = "org.test",
methods = nil,
signals = nil,
properties = nil,
annotations = nil
}
end
-- create a instace of MyDBusInterfaceSkeleton which implements Gio.DBusInterfaceSkeleton
local interface_ske = MyApp.MyDBusInterfaceSkeleton()
local obj_man = Gio.DBusObjectManagerServer{object_path ="/object"}
local obj_ske = Gio.DBusObjectSkeleton.new("/object/1")
obj_man:export(obj_ske)
-- Line below causes SEGMENTATION FAULT
obj_ske:add_interface(interface_ske)
Sorry, but that does not segfault here :-(
It works on you side? Weird, let me check again... Thanks for the feedback
Cold you share how you tested it?
$ cat > /tmp/t.lua && lua /tmp/t.lua
local lgi = require("lgi")
local Gio = lgi.Gio
local GObject = lgi.GObject
local GLib = lgi.GLib
local MyApp = lgi.package 'MyApp'
MyApp:class('MyDBusInterfaceSkeleton', Gio.DBusInterfaceSkeleton)
-- Override get_info() method of Gio.DBusInterfaceSkeleton
function MyApp.MyDBusInterfaceSkeleton:do_get_info()
return Gio.DBusInterfaceInfo{
name = "org.test",
methods = nil,
signals = nil,
properties = nil,
annotations = nil
}
end
-- create a instace of MyDBusInterfaceSkeleton which implements Gio.DBusInterfaceSkeleton
local interface_ske = MyApp.MyDBusInterfaceSkeleton()
local obj_man = Gio.DBusObjectManagerServer{object_path ="/object"}
local obj_ske = Gio.DBusObjectSkeleton.new("/object/1")
obj_man:export(obj_ske)
-- Line below causes SEGMENTATION FAULT
obj_ske:add_interface(interface_ske)
First line is what I entered in my shell. The rest is copy&paste from your post (with a final ctrl+d
for "end of file). I tested this with all of lua5.1, 5.2, 5.3 and luajit.
Now I see, actually I narrowed down the case of segmentation fault, it happens when set the dbus-connection to object manager. I put all code I used to test below. And indeed the way you tested there is no segfault. If you try the code below just after we set the connection to the object-manager segfault happens in the line obj_ske:add_interface(interface_ske)
. Still not clear to me why.
local lgi = require("lgi")
local Gio = lgi.Gio
local GObject = lgi.GObject
local GLib = lgi.GLib
local MyApp = lgi.package 'MyApp'
MyApp:class('MyDBusInterfaceSkeleton', Gio.DBusInterfaceSkeleton)
-- Override get_info() method of Gio.DBusInterfaceSkeleton
function MyApp.MyDBusInterfaceSkeleton:do_get_info()
return Gio.DBusInterfaceInfo{
name = "org.test",
methods = nil,
signals = nil,
properties = nil,
annotations = nil
}
end
-- create a instace of MyDBusInterfaceSkeleton which implements Gio.DBusInterfaceSkeleton
local interface_ske = MyApp.MyDBusInterfaceSkeleton()
local obj_man = Gio.DBusObjectManagerServer{object_path ="/object"}
local obj_ske = Gio.DBusObjectSkeleton.new("/object/1")
obj_man:export(obj_ske)
local function on_bus_acquire(conn, _, _)
obj_man:set_connection(conn)
-- Line below causes SEGMENTATION FAULT
obj_ske:add_interface(interface_ske)
end
local function on_name_lost(conn, _, _)
-- if con is nil, then no connection to the bus could be made
if (conn) then
print('Could not acquire the requested name.')
else
print('Connection to the bus cannot be established.')
end
end
local mainloop
local function main()
Gio.bus_own_name(
Gio.BusType.SESSION,
"com.org.luadbus1",
Gio.BusNameOwnerFlags.NONE,
GObject.Closure(on_bus_acquire), nil, GObject.Closure(on_name_lost)
)
mainloop = GLib.MainLoop.new()
print("daemon started")
mainloop:run()
dbus_service.stop()
print("daemon stopped")
end
main()
If we change the order of the calls, then segfault happens on obj_man:set_connection(conn)
.
local lgi = require("lgi")
local Gio = lgi.Gio
local GObject = lgi.GObject
local GLib = lgi.GLib
local MyApp = lgi.package 'MyApp'
MyApp:class('MyDBusInterfaceSkeleton', Gio.DBusInterfaceSkeleton)
-- Override get_info() method of Gio.DBusInterfaceSkeleton
function MyApp.MyDBusInterfaceSkeleton:do_get_info()
return Gio.DBusInterfaceInfo{
name = "org.test",
methods = nil,
signals = nil,
properties = nil,
annotations = nil
}
end
-- create a instace of MyDBusInterfaceSkeleton which implements Gio.DBusInterfaceSkeleton
local interface_ske = MyApp.MyDBusInterfaceSkeleton()
local obj_man = Gio.DBusObjectManagerServer{object_path ="/object"}
local obj_ske = Gio.DBusObjectSkeleton.new("/object/1")
obj_man:export(obj_ske)
local function on_bus_acquire(conn, _, _)
obj_ske:add_interface(interface_ske)
-- Line below causes SEGMENTATION FAULT
obj_man:set_connection(conn)
end
local function on_name_lost(conn, _, _)
-- if con is nil, then no connection to the bus could be made
if (conn) then
print('Could not acquire the requested name.')
else
print('Connection to the bus cannot be established.')
end
end
local mainloop
local function main()
Gio.bus_own_name(
Gio.BusType.SESSION,
"com.org.luadbus1",
Gio.BusNameOwnerFlags.NONE,
GObject.Closure(on_bus_acquire), nil, GObject.Closure(on_name_lost)
)
mainloop = GLib.MainLoop.new()
print("daemon started")
mainloop:run()
dbus_service.stop()
print("daemon stopped")
end
main()
Below I put the code implementationo of GIO g_dbus_object_manager_server_set_connection
/**
* g_dbus_object_manager_server_set_connection:
* @manager: A #GDBusObjectManagerServer.
* @connection: (nullable): A #GDBusConnection or %NULL.
*
* Exports all objects managed by @manager on @connection. If
* @connection is %NULL, stops exporting objects.
*/
void
g_dbus_object_manager_server_set_connection (GDBusObjectManagerServer *manager,
GDBusConnection *connection)
{
g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
g_return_if_fail (connection == NULL || G_IS_DBUS_CONNECTION (connection));
g_mutex_lock (&manager->priv->lock);
if (manager->priv->connection == connection)
{
g_mutex_unlock (&manager->priv->lock);
goto out;
}
if (manager->priv->connection != NULL)
{
unexport_all (manager, FALSE);
g_object_unref (manager->priv->connection);
manager->priv->connection = NULL;
}
manager->priv->connection = connection != NULL ? g_object_ref (connection) : NULL;
if (manager->priv->connection != NULL)
export_all (manager);
g_mutex_unlock (&manager->priv->lock);
g_object_notify (G_OBJECT (manager), "connection");
out:
;
}
Once again, thank you so much for the support!
The crash happens here:
GDBusInterfaceVTable *
g_dbus_interface_skeleton_get_vtable (GDBusInterfaceSkeleton *interface_)
{
GDBusInterfaceVTable *ret;
g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
ret = G_DBUS_INTERFACE_SKELETON_GET_CLASS (interface_)->get_vtable (interface_);
g_warn_if_fail (ret != NULL);
return ret;
}
Specifically, it happens when calling the get_vtable
function. This function pointer is NULL
.
Hm... I tried to add the following, but the function is not called (still same NULL
pointer as before). Now I am back in "I do not know how this work and would like to have a working example in C that can be translated". Sorry.
function MyApp.MyDBusInterfaceSkeleton:do_get_vtable()
print("You have to somehow implement this method")
end
Hi @psychon as per my investigation it seems the LGI lua bidding do not implement the get_vtable
which is required, so it does not work if we try to override because it is not part of the DBusInterfaceSkeleton
generated by lig
this is the reason I guess it is NULL
.
Regarding a work example please find below attached files from the official GIO repository.
https://drive.google.com/drive/folders/1B3iyrStz2rVw8alPOr9TMjkgHfC5Ylhw?usp=sharing
Hrm. Sorry, I give up. That's 3.8k lines of code, 3.1k of which come from a code generator. Gio's DBus code is just not meant to be used from anything other than C.
Here is my state when I gave up:
local lgi = require("lgi")
local Gio = lgi.Gio
local GObject = lgi.GObject
local GLib = lgi.GLib
local MyApp = lgi.package 'MyApp'
MyApp:class('ExampleObjectSkeleton', Gio.DBusObjectSkeleton)
MyApp:class('ExampleAnimalSkeleton', Gio.DBusInterfaceSkeleton)
MyApp.ExampleAnimalSkeleton._property.mood = GObject.ParamSpecString("mood", "Mood", "Mood", nil, { "READWRITE" })
MyApp.ExampleObjectSkeleton._property.animal = GObject.ParamSpecObject("animal", "animal", "animal", MyApp.ExampleAnimalSkeleton, { "READWRITE" })
function MyApp.ExampleAnimalSkeleton._property_set:mood(value)
self.priv.mood = value
end
function MyApp.ExampleAnimalSkeleton:set_mood(value)
self.mood = value
end
local vtable = Gio.DBusInterfaceVTable{
method_call = function(...) print("method call", ...) end,
get_property = function(...) print("get property", ...) end,
set_property = function(...) print("set property", ...) end
}
function MyApp.ExampleAnimalSkeleton:do_get_vtable()
print("get vtable 1 - WHY THE HECK IS THIS NEVER CALLED?")
end
local info = Gio.DBusInterfaceInfo {
name = "org.gtk.GDBus.Example.ObjectManager.Cat",
-- Lots of NULLs follow
}
function MyApp.ExampleAnimalSkeleton:do_get_info()
return info
end
function MyApp.ExampleObjectSkeleton._property_set:animal(value)
self.priv.animal = value
-- Not sure if I got this right... In fact, I am almost sure I got this wrong
self:add_interface(value)
end
function MyApp.ExampleObjectSkeleton:set_animal(value)
self.animal = value
end
local function example_object_skeleton_new(path)
return MyApp.ExampleObjectSkeleton{["g-object-path"] = path}
end
local function example_animal_skeleton_new()
return MyApp.ExampleAnimalSkeleton()
end
local function on_animal_poke(animal, invocation, make_sad, make_happy, ...)
print("on_animal_poke", animal, invocation, make_sad, make_happy)
if (make_sad and make_happy) or (not make_sad and not make_happy) then
invocation:return_dbus_error("org.gtk.GDBus.Examples.ObjectManager.Error.Failed", "Exactly one of make_sad or make_happy must be TRUE")
return true -- The C code uses a constant for this, but I did not find this anywhere
end
if make_sad then
if animal:get_mood() == "Sad" then
invocation:return_dbus_error("org.gtk.GDBus.Examples.ObjectManager.Error.SadAnimalIsSad", "Sad animal is already sad")
return true
end
animal:set_mood("Sad")
animal:complete_poke(animal, invocation)
elseif make_happy then
if animal:get_mood() == "Happy" then
invocation:return_dbus_error("org.gtk.GDBus.Examples.ObjectManager.Error.HappyAnimalIsHappy", "Happy animal is already happy")
return true
end
animal:set_mood("Happy")
animal:complete_poke(animal, invocation)
end
assert(0)
end
local function on_bus_acquired(conn, name, data)
print("Acquired a message bus connection")
manager = Gio.DBusObjectManagerServer.new("/example/Animals")
for n = 0, 10 do
local object = example_object_skeleton_new(string.format("/example/Animals/%03d", n))
local animal = example_animal_skeleton_new()
animal:set_mood("Happy")
object:set_animal(animal)
--[[ No thanks, let's skip this for now
if n % 2 == 1 then
local cat = example_cat_skeleton_new()
object:set_cat(cat)
end
--]]
-- FIXME: How to I add the handle-poke signal?!?
--animal.on_handle_poke = on_animal_poke
manager:export(object)
end
manager:set_connection(conn)
end
local function on_name_acquired(conn, name, data)
print("Acquired the name", con, name, data)
end
local function on_name_lost(conn, name, data)
print("Lost the name", con, name, data)
end
-- main
local loop = GLib.MainLoop.new(nil, false)
id = Gio.bus_own_name(Gio.BusType.SESSION,
"org.gtk.GDBus.Examples.ObjectManager",
Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT + Gio.BusNameOwnerFlags.REPLACE,
GObject.Closure(on_bus_acquired), GObject.Closure(on_name_lost), GObject.Closure(loop), nil)
loop:run()
Gio.bus_unown_name(id)
print("end of main")
Perhaps the following code helps you? It shows how to use Gio without using DBusInterfaceSkeleton
(but of course you then lose its automatic introspection capabilities): https://github.com/awesomeWM/awesome/blob/ebc9b99ae2817ddd95b5b9b2238881fcd5c777e0/lib/naughty/dbus.lua#L429-L430
Hi all,
I am working in a project using lgi where I need to implement a instance of the abstract class DBusInterfaceSkeleton. After many trails I still did not get any success so I was wondering if anyone could help me. I found some documentation of how to implement a sublcass using lgi.package but still not clear for me how I can get a instance of the class DBusInterfaceSkeleton.
Just to put in context I need a instance of this class in order to add a DBUS interface to a DBUS object using Gio.DBusObjectSkeleton.add_interface(...) method.
Best Regards,