-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Example of how to implement *DBusInterfaceSkeleton* abstract class #275
Comments
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? |
First line is what I entered in my shell. The rest is copy&paste from your post (with a final |
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 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 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:
* @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:
Specifically, it happens when calling the |
Hm... I tried to add the following, but the function is not called (still same 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 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 |
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,
The text was updated successfully, but these errors were encountered: