lgi-devs / lgi-devs/lgi

GObjects don't seem to provide an API for disconnecting signals, nor do so automatically on reassignment

Open
#333 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Lua
Stars
491
Forks
81
PR merge metrics
No merged PRs in 30d

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

  1. 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 is button_1 (top button)

  2. 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) uses GObject.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 use GObject.signal_handler_disconnect(handler_id) to accomplish this, where handler_id is the return value of widget.on_<signal>:connect(fn). In my demo, this is button_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]

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the signal-connection section in docs/guide.md (§3.4.1) and the demonstrated GObject.signal_handler_disconnect call. Determine the supported behavior for reassignment and handler removal, then verify that the resulting API or documentation covers both cases described in the issue.

Written by the indexing model from the issue text.

Assessment

Tech stack
lua
Domain
desktop
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.