Description
Hi All,
I'm not sure to which degree these behaviors are expected, but I've found some difficulty in connecting, and then disconnecting a signal with a Gtk.Widget
. I have a feeling this extends to every GObject
that implements signals
-
Using the signal assignment (
widget.on_<signal> = fn
) syntax does not disconnect any previous assignments. This runs contrary to any assignment logic anywhere else in lua. In my demo, this isbutton_1
(top button) -
No signal disconnection methods seem to exist. I couldn't find anyhting of the sort in the guide. I checked "disconnect", "disconnect_by_func", "handler_disconnect", and "handlers_disconnect_by_func". I assume
widget.on_<signal>:connect(fn)
usesGObject.signal_connect(object, signal, fn)
under the hood, but it's unfortunate that the memory management functions associated with signals are not exposed, as far as I can tell. In my demo I useGObject.signal_handler_disconnect(handler_id)
to accomplish this, where handler_id is the return value ofwidget.on_<signal>:connect(fn)
. In my demo, this isbutton_2
(bottom button)
Here's the code for my demo:
local lgi = require("lgi")
local Gtk = lgi.require("Gtk", "3.0")
local GObject = lgi.GObject
-- This button demonstrates that re-assigning a signal handler doesn't disconnect the previous assignment:
local button_1 = Gtk.Button.new_with_label("I can be clicked multiple times, but I have multiple handlers")
---@diagnostic disable-next-line:duplicate-set-field
button_1.on_clicked = function ()
print("Button 2 Click handler 1!")
end
---@diagnostic disable-next-line:duplicate-set-field
button_1.on_clicked = function ()
print("Button 2 Click handler 2!")
end
-- This button demonstrates the difficulty in disconnecting a signal:
local button_2 = Gtk.Button.new_with_label("I can be clicked once!")
local handler_id
-- using widget.<signal>:connect from https://github.com/lgi-devs/lgi/blob/master/docs/guide.md#341-connecting-signals
handler_id = button_2.on_clicked:connect(function(widget)
print("Button 1 Clicked!")
widget:set_label("I can no longer be clicked!")
do
-- Checking for any signal disconnection methods attached to our widget:
local widget_truncated = tostring(widget):match("^lgi.obj 0x[%w]+:([^%(]+)")
for _, fn_name in ipairs({
"disconnect",
"disconnect_by_func",
"handler_disconnect",
"handlers_disconnect_by_func"
}) do
local ok, ret = pcall(function ()
return widget.on_clicked[fn_name]
end)
if not ok or not ret then
print(string.format("\t%s does not provide %q", widget_truncated, fn_name))
end
end
end
-- Ideally, I'd use
--widget:disconnect(handler_id)
-- as that uses the same object-oriented syntax lgi has lead me to expect
print("Disconnecting signal using GObject")
GObject.signal_handler_disconnect(widget, handler_id)
end)
local window = Gtk.Window {
title = "GitHub issue demo",
default_width = 400,
default_height = 300,
on_destroy = Gtk.main_quit,
child = Gtk.VBox {
button_1,
button_2
},
}
window:present()
window:show_all()
Gtk.main()
Edit: I was using widget[fn_name]
which would always fail - oops! now using widget.on_clicked[fn_name]