Skip to content
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

GTK4 doesn't have Gtk.Builder.connectSignals #308

Open
rexkogitans opened this issue Aug 12, 2021 · 6 comments
Open

GTK4 doesn't have Gtk.Builder.connectSignals #308

rexkogitans opened this issue Aug 12, 2021 · 6 comments

Comments

@rexkogitans
Copy link

rexkogitans commented Aug 12, 2021

Sorry, I cannot reopen issue #305.

Your example uses GTK 3, however the GTK documentation clearly states that this function no longer exists:

https://docs.gtk.org/gtk4/migrating-3to4.html

Somehow, I have the feeling that there should be a language-specific implementation of Gtk.BuilderScope. Since Gtk.BuilderCScope is the C/C++ implementation, naming it Gtk.BuilderJSScope would make sense.

Originally posted by @rexkogitans in #305 (comment)

@romgrk
Copy link
Owner

romgrk commented Aug 12, 2021

If you want to provide a replacement for the deprecated function, PR:s are welcome. I don't have enough time to add an implementation myself. The first thing I would recommend though would be to carefully read the GTK documentation to see what their proposed migration solution is.

@romgrk romgrk changed the title Gtk.Builder not connecting signals from UI file GTK4 doesn't have Gtk.Builder.connectSignals Aug 12, 2021
@rexkogitans
Copy link
Author

I will try to create an implementation of what is GtkBuilderScopeInterface in C during the next weeks. Either I can write it in node or in C, maybe I will need some help. The resulting code should allow the creation of a class like what I have posted in issue #305, but with another name, something like:

class MyClass extends Gtk.BuilderJSScope { ... }

@romgrk
Copy link
Owner

romgrk commented Aug 16, 2021

Ok. Don't have time to look into this in details at the moment, but whatever you do make sure to check what PyGObject and GJS are doing, I try to stay as close to them as possible.

@rexkogitans
Copy link
Author

I am sorry to say that I do not make any progress with it. Obviously, I need to register the callback functions somehow. I tried to override the setScope method and started out with this:

  Gtk.Builder.prototype.setScope = function (scope) {
      const props = [];
      props.push(...Object.getOwnPropertyNames(scope));
      props.push(...Object.getOwnPropertyNames(Object.getPrototypeOf(scope)));
      for (let prop of props) {
        if (typeof scope[prop] == "function") console.log(prop)
      }
    }

This outputs all the functions of scope. So, as far as I understand, setScope needs to call some internal function or add them to an array to register the callbacks, so that addFromString can use it.

The intended usage looks like this:

    const builder = Gtk.Builder.new()
    builder.setScope(this)
    builder.addFromString(ui, -1)

@rexkogitans
Copy link
Author

rexkogitans commented Oct 18, 2021

@romgrk After reading tons of source code of the GTK project, a came to the conclusion that Gtk.Builder.setScope and Gtk.Builder.addCallbackSymbol should be used for language bindings where symbols (i.e. function names) are not in necessarily in global scope. So, I came up with this approach:

#!/usr/bin/env node

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


class MyTestApp {
  
  constructor() {
    console.log("constructor")
  }
  
  _onButtonClicked() {
    console.log("Yippie!");
  }
  
}

const loop = GLib.MainLoop.new(null, false)
const app = new Gtk.Application('rexkogitans.nodegtk.mwe-4', 0)
app.on('activate', onActivate)

const status = app.run([])

gi.startLoop()
loop.run()


console.log('Finished with status:', status)

function onActivate() {

  const window = new Gtk.ApplicationWindow(app)
  window.setTitle('Window')
  window.setDefaultSize(200, 200)


  const ui = `
    <?xml version="1.0" encoding="UTF-8"?>
    <interface>
      <requires lib="gtk" version="4.0"/>
        <object class="GtkBox" id="root">
          <property name="orientation">vertical</property>
          <child>
            <object class="GtkLabel" id="helloLabel">
              <property name="vexpand">1</property>
              <property name="label">Hello World!</property>
            </object>
          </child>
          <child>
            <object class="GtkButton" id="actionButton">
              <property name="label" translatable="yes">Action</property>
              <property name="receives_default">1</property>
              <signal name="clicked"
                      handler="_onButtonClicked"
                      swapped="no"
                      />
            </object>
          </child>
          <child>
            <object class="GtkButton" id="closeButton">
              <property name="label" translatable="yes">Close</property>
              <property name="receives_default">1</property>
            </object>
          </child>
        </object>
    </interface>
  `

  const builder = new Gtk.Builder()
  const myapp = new MyTestApp()
  const scope = new Gtk.BuilderCScope()
  builder.setScope(scope)
  scope.addCallbackSymbol("_onButtonClicked", myapp._onButtonClicked.bind(myapp))
  builder.addFromString(ui, -1)
  const root = builder.getObject('root')

  const closeButton = builder.getObject('closeButton')
  closeButton.on('clicked', () => window.close())

  window.setChild(root)
  window.show()
  window.present()

}


function onQuit() {
  loop.quit()
  app.quit()
  return false
}

This looks quite promising. When clicking the action button, it writes Yippie! to the console, as expected. However, when clicking the button a second time, the application crashes (core dump).
I did not go into it with Valgrind or any kind of debugging tool, since I know that my understanding is too low here. I hope it helps in pointing out that there may be a bug which should be fixed.

@TheDogHusky
Copy link

TheDogHusky commented Jun 16, 2024

Hey!
News about this?
I've been trying to use (import) GTK 4.0 and Adw 1 but I got an error that seems related to this issue:

    const handlerID = this.connect(event, callback, after)
                           ^

TypeError: Signal callback is not a function

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants