gtk-rs / gtk

DEPRECATED, use https://github.com/gtk-rs/gtk3-rs repository instead!

Home Page:https://gtk-rs.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

gtk::Application created by gtk::ApplicationBuilder doesn't initialize GTK

andy128k opened this issue · comments

Here is a repository which reproduction of an error.
https://github.com/andy128k/reproduce_error_gtk_rs_application_builder

@antoyo This happens because the builder goes just via glib::Object::new() and does not mark things as initialized, like the gtk::Application::new() constructor does here:

try!(rt::init());

glib::Object::new() should not be an issue. Error is thrown by Gtk-rs, not by Gtk.

IMHO, Gtk-rs should not track initialization itself here but rely on Gtk using this or similar API.

glib::Object::new() should not be an issue. Error is thrown by Gtk-rs, not by Gtk.

Yes, because of that line missing :)

IMHO, Gtk-rs should not track initialization itself here but rely on Gtk using this or similar API.

That API only exists in GTK 4 unfortunately, otherwise I would agree with you.

What would be the proper way to fix this? Not sure how to override only new() while keeping the rest of the builders generation.

I don't know, this case was not considered when adding the builders. It assumes that g_object_new() is sufficient (which is also not the case for a few other types btw).

One of the options is to remove gtk::ApplicationBuilder.

Theoretically checking if Gtk is initialized in new or build is not correct. Application initializes Gtk in a startup handler, not in a constructor.

Is the reason for calling this from Application::new() merely to simplify the examples to not include a call to rt::init() ? If so then my vote would be to stop Application::new() from calling this and instead expect callers to initialise for themselves. If that's too big of a leap, or if really there's a variety of builders which would benefit from it, then I propose adding to the gir tool a facility to add a pre-construction statement in Gir.toml which will be inserted before the glib::Object::new() invocation in the build() method.

rt::init() is unsafe code and ideally we wouldn't require every GTK application to have unsafe code just for this :)

In what way is it unsafe, rt::init() is NOT marked unsafe which means safety guarantees are meant to hold for anyone to call it.

For clarity, while there is an unsafe {} block in Application::new() the call to try!(rt::init()) is ouside the unsafe {} block.

Ah even worse. We shouldn't initialize GTK separately but let gtk::Application do it and then call rt::set_initialized() (that's the unsafe one).

Okay, so really what we should do is ensure that gtk::Application in gtk-rs has a startup handler which calls rt::set_initialized() and then it shouldn't call rt::init() itself in Application::new() meaning we can likely drop that special case from the Gir.toml ?

My understanding of how the gtk::Application stuff comes into being was flawed, we still need the special case because it mustn't assert initialised.

We have three cases to consider, all of which need to ensure rt::set_initialized() is called at the start of the callback chain for the startup signal on the application:

  1. Application::new() generated applications
  2. ApplicationBuilder::build() generated applications
  3. Instances of subclasses of gtk::Application

In theory we could do this by hiding the official gtk::Application class and subclassing it ourselves in gtk-rs, ensuring we register a callback, and then having what anyone else sees as gtk::Application actually be the subclass we have from gtk-rs. Perhaps there's something cleaner? I'm not fully au-fait with gtk/glib objects. If we could hook the creation of any instance of or subclass of gtk::Application we could register the signal handler at that point instead.

So the first of those could be done like this: kinnison@804b919 and the third like this: kinnison@6e2a2e3 but I've not yet worked out how to do the second without poking at the gir crate to add some kind of "post build filter"

(For the record, I've tested both of those approaches by hand locally)

I've not yet worked out how to do the second without poking at the gir crate to add some kind of "post build filter"

I don't think there's another way. The other two commits look good to me

Okay, proposed approach, given the above linked gir change is:

  1. For Application::new() instances - kinnison@d8a50c6
  2. For ApplicationBuilder::build() instances - kinnison@0392dc8
  3. For subclasses of gtk::Application - kinnison@aaed97a

If @sdroege and @GuillaumeGomez think that looks sane, then I'll sort a PR as soon as the gir change is settled.

For reference the 'gir change' mentioned above is gtk-rs/gir#912

Looks good to me