romgrk / node-gtk

GTK+ bindings for NodeJS (via GObject introspection)
MIT License
493 stars 41 forks source link

Virtual functions don't work #354

Closed clayrisser closed 6 months ago

clayrisser commented 8 months ago

How to override vfuncs?

clayrisser commented 8 months ago

After doing more research and running the examples, it seems that virtual functions only work directly on a Gtk.Widget. They are not working for other gtk widgets (for example I'm not able to override virtual functions for a Gtk.Button).

clayrisser commented 8 months ago

@romgrk ???

clayrisser commented 8 months ago

While I was able to get the gtk-4-custom-widget.js example to work on linux (again only with Gtk.Widget), it doesn't work on OSX.

It gives a bus error on OSX.

Screenshot 2023-12-21 at 12 09 40 PM
clayrisser commented 8 months ago

I think it has something to do with the fact that most of the new gtk 4 widgets are using layouts, so the measure virtual function is actually in the layout. I tried testing this by using a FixedWidget and changing it's layout to use a custom FixedLayout and then overrode the measure virtual function in FixedLayout, but that didn't seem to work.

romgrk commented 8 months ago

Do you have an example?

And did you call gi.registerClass(CustomButton)? It's required to create a new GObject, which is how virtual functions are able to work. There isn't a way to avoid the runtime call, because V8 doesn't provide a hook or callback for us to know when a new class is derived from an existing GObject class.

https://github.com/romgrk/node-gtk/blob/6583bb93114eb829dd86c900a2b3664d267185ac/lib/register-class.js#L14-L19

romgrk commented 8 months ago

Relevant doc section: https://github.com/romgrk/node-gtk/blob/master/doc/index.md#inheritance

clayrisser commented 8 months ago

I did that though. I"m setting

static GTypeName = 'FixedLayout'

and adding

gi.registerClass(FixedLayout)

I'm trying to set the measure virtual function but it won't work.

romgrk commented 8 months ago

Do you have a code example that doesn't work? Is gtk-4-custom-widget.js representative of what you're trying to do?

clayrisser commented 8 months ago

Yes, here is an example below. I'm using gi.registerClass(). The measure virtual function should be overloaded in the CustomFixedLayout (which should log "measure"), but when you run it, the measure function is not overloaded.

/*
 * test-gtk-4.js
 */

const gi = require("../lib");
const GLib = gi.require("GLib", "2.0");
const Gtk = gi.require("Gtk", "4.0");

Gtk.init();

class CustomFixedLayout extends Gtk.FixedLayout {
  static GTypeName = "CustomFixedLayout";

  measure(orientation, forSize) {
    console.log("measure");
    return super.measure(orientation, forSize);
  }
}

class CustomFixed extends Gtk.Fixed {
  static GTypeName = "CustomFixed";

  constructor() {
    super();
    this.setLayoutManager(new CustomFixedLayout());
  }
}

gi.registerClass(CustomFixedLayout);
gi.registerClass(CustomFixed);

/* Setup & start the application */

const loop = GLib.MainLoop.new(null, false);
const app = new Gtk.Application("com.github.romgrk.node-gtk.demo", 0);
app.on("activate", onActivate);
const status = app.run();

function onActivate() {
  const window = new Gtk.ApplicationWindow(app);
  window.on("close-request", onQuit);

  const cssProvider = new Gtk.CssProvider();
  const customFixedCss = `
  #custom-fixed {
    background-color: red;
  }
`;

  const customFixed = new CustomFixed();
  customFixed.setName("custom-fixed");
  cssProvider.loadFromData(customFixedCss, customFixedCss.length);
  customFixed
    .getStyleContext()
    .addProvider(cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER);

  window.setChild(customFixed);
  window.present();

  gi.startLoop();
  loop.run();
}

function onQuit() {
  loop.quit();
  app.quit();
  return false;
}
romgrk commented 8 months ago

The vfunc issue should be dealt with in #355. Your code example still doesn't run, but it's missing a parameter, widget:

  measure(widget, orientation, forSize) {
    console.log("measure");
    return super.measure(widget, orientation, forSize);
  }

Note that this will cause a stack overflow, because for some reason super.measure calls measure. To be honest vfuncs is the last thing I implemented and one aspect of GIR I don't understand very well, so I don't know what's going on behind the scenes. If you absolutely need access to the virtual measure implemented by GtkFixedLayout, I could try to allocate some time soon to make things work.

clayrisser commented 8 months ago

I will need it to work because I'm adding Flex layout support with yoga, and I need to use measure to make it work.

clayrisser commented 8 months ago

Any eta for the #355 PR?