Need help in understanding autoconnecting signals from builder in GTK 4

In GTK 3, there was gtk_signal_connect() to connect the signals of an XML file loader by gtk_builder_* functions automatically to same-named functions. This worked also in Python in OOP. Now I want to try to achieve the same in node-js. I am developing an own small project by using node-gtk (not: GJS).

I think that node-gtk is missing a class resembling gtk_buildercscope, something named like Gtk.BilderJSScope. However, I wanted to understand how this works in GTKMM before I do anything in node-gtk, but I don’t get it. All examples which use a builder file connect all signals one by one, not by using a single function which connects all at once. Can someone please show me a MWE in either C++ or Python (because these are two languages I roughly understand) where GTK 4 is used with a builder UI file and uses a single function to connect signals?

1 Like

Adapt to GtkBuilder API changes

gtk_builder_connect_signals() no longer exists. Instead, signals are always connected automatically. If you need to add user data to your signals, gtk_builder_set_current_object() must be called. An important caveat is that you have to do this before loading any XML. This means if you need to use gtk_builder_set_current_object(), you can no longer use gtk_builder_new_from_file(), gtk_builder_new_from_resource(), or gtk_builder_new_from_string(). Instead, you must use vanilla gtk_builder_new(), then call gtk_builder_set_current_object(), then load the XML using gtk_builder_add_from_file(), gtk_builder_add_from_resource(), or gtk_builder_add_from_string(). You must check the return value for failure and manually abort with g_error() if something went wrong.

You only have to worry about this if you were previously using gtk_builder_connect_signals(). If you are using templates, then gtk_widget_init_template() will call gtk_builder_set_current_object() for you, so templates work like before.

PyGObject defines it’s BuilderScope here, as far as I know Gtkmm doesn’t have one (how would that even work?)

1 Like

A C++ BuilderScope might be necessary to translate the C++ type names into GType, not just for creating closures for a given function name.

Ok, these are two different things to consider: Either Using gtk_builder_set_current_object or templates. As far as I understood, as long as I do not have to pass user data, templates is the way to go.

So, let us start with templates: Can someone please provide me a minimum working example using templates, preferably in Python, because it is OOP just as JavaScript is?

Well anything GObject is OOP but sure

Gtk.Template / Examples

xml = """\
<interface>
  <template class="example1" parent="GtkBox">
    <child>
      <object class="GtkButton" id="hello_button">
        <property name="label">Hello World</property>
        <signal name="clicked" handler="hello_button_clicked" swapped="no" />
      </object>
    </child>
  </template>
</interface>
"""

@Gtk.Template(string=xml)
class Foo(Gtk.Box):
    __gtype_name__ = "example1"

    hello_button = Gtk.Template.Child()

    @Gtk.Template.Callback()
    def hello_button_clicked(self, *args):
        pass
1 Like

Thank you so far. I will give you feedback during the next days if I come up with a solution or I need further help.

Regarding the other option, using gtk_builder_set_current_object, I will create a separate thread.

Well anything GObject is OOP but sure

I would not call programming in C OOP, but well, if you expand the term a bit, it is.

Sorry, but since I am quite new to Phyton, I have a problem in understanding the class decorator. Does this mean that the class Foo is derived from Gtk.Template? I try to translate this code into JavaScript. In node-gtk, I started out with this:

class Foo extends Gtk.Box

What do I do with the constructor then? I think there is something called implicitly in Python, and I guess it is this parameter string=xml which should give me a clue, but I cannot work it out. Somehow, a superclass might invoke gtk_widget_init_template (whatever its Python equivalent is called).

This is my entire code:

#!/usr/bin/env node

const gi = require('node-gtk')
const GLib = gi.require('GLib', '2.0')
const Gtk = gi.require('Gtk', '4.0')

class Foo extends Gtk.Box {
    
    GTypeName = "example1"
    __gtype__ = "example1"  // I think that this is correct
    #btn_hello = null;
    
    constructor() {
        let xml = `<interface>
  <template class="example1" parent="GtkBox">
    <child>
      <object class="GtkButton" id="hello_button">
        <property name="label">Hello World</property>
        <signal name="clicked" handler="hello_button_clicked" swapped="no" />
      </object>
    </child>
  </template>
</interface>
`
        super()
        this.setTemplate(xml)  // does not work
        //this.initTemplate()
    }
    
    btn_hello_clicked() {
        console.log("btn clicked")
    }
    
}

var myapp = null;

function onActivate() {
    myapp = new Foo()
}


const loop = GLib.MainLoop.new(null, false)
const app = new Gtk.Application("rexkogitans.mwe-node-gtk", 0)
app.on('activate', onActivate)
const status = app.run([])

gi.startLoop()


loop.run()

However, this does not load the XML. I don’t understand how the XML comes into play now.

No, it’s just a decorator providing sugar (such as hiding gtk_widget_class_set_template, gtk_widget_init_template, … )

You’d need to ask someone who knows about node-gtk, no idea if they even support the needed calls

It is this “providing sugar” I want to understand what happens under the hood, because I fear that this is not implemented in node-gtk. If so, I want to try to improve node-gtk, but first I need to be sure what do exactly instead of tinkering around. @zbrown says, it is hiding gtk_widget_class_set_template and gtk_widget_init_template. Can someome give me exact details (a code snippet) of what is hidden?