How to access application object inside `startup()` whilst subclassing

Obviously, the basic_subclass example works fine as is.

Inside startup(), It seems to access the application object via self.obj():

let window = SimpleWindow::new(&self.obj());

However, that only seems to work once. A second call (e.g. self.obj().set_app_menu()) produces:

error[E0599]: the method `add_action` exists for struct `BorrowedObject<'_, application::SpApplication>`, but its trait bounds were not satisfied
    --> src/application/imp.rs:98:20
     |
98   |           self.obj().add_action(&action_open);
     |                      ^^^^^^^^^^ method cannot be called on `BorrowedObject<'_, application::SpApplication>` due to unsatisfied trait bounds

I had expected self to be the object, but using that produces:

error[E0599]: the method `set_app_menu` exists for reference `&imp::SpApplication`, but its trait bounds were not satisfied
  --> src/application/imp.rs:73:14
   |
15 | pub struct SpApplication {
   | ------------------------
   | |
   | doesn't satisfy `_: gtk::prelude::GtkApplicationExt`
   | doesn't satisfy `imp::SpApplication: IsA<gtk::Application>`
...
73 |         self.set_app_menu(Some(&app_menu));
   |              ^^^^^^^^^^^^ method cannot be called on `&imp::SpApplication` due to unsatisfied trait bounds

How can I access the application object (multiple times) inside startup() whilst subclassing?

You’re missing the @implements gio::ActionMap part in the glib::wrapper! macro usage. Without that it’s not known that your subclass implements that interface.

As the actionmap API is not used in that specific example it was not listed there. IMHO all the superclasses and interfaces should be listed there always, even if they are currently not used.

Thanks. That worked, but gave me a new problem. Although I’ve used the clone! macro, it is still complaining about window being borrowed after move:

error[E0382]: borrow of moved value: `window`
  --> src/application/imp.rs:78:38
   |
61 |           let window: ApplicationWindow = builder.object("appwindow").expect("Couldn't get appwindow");
   |               ------ move occurs because `window` has type `ApplicationWindow`, which does not implement the `Copy` trait
...
64 |               .set(window)
   |                    ------ value moved here
...
78 |           action_open.connect_activate(clone!(@weak window, @weak model => move |_, _| {
   |  ______________________________________^
79 | |             let file_chooser = FileChooserDialog::with_buttons(
80 | |                 Some("Open image"),
81 | |                 Some(&window),
...  |
96 | |             file_chooser.show();
97 | |         }));
   | |__________^ value borrowed here after move

Why does this not work?

And indeed replacing

    self.window
        .set(window)
        .expect("Failed to initialize application window");

with

window.set_application(Some(&self));

gives me:

error[E0277]: the trait bound `&imp::SpApplication: IsA<gtk::Application>` is not satisfied
   --> src/application/imp.rs:62:32
    |
62  |         window.set_application(Some(&self));
    |                --------------- ^^^^^^^^^^^ the trait `IsA<gtk::Application>` is not implemented for `&imp::SpApplication`
    |                |
    |                required by a bound introduced by this call

Hard to say without more context, i.e. the surrounding code.

Thanks for the reply. I’m new to Rust, so I’m making some beginner’s mistakes. I fixed the borrow problem by replacing:

    self.window
        .set(window)
        .expect("Failed to initialize application window");

with:

    self.window
        .set(window.clone())
        .expect("Failed to initialize application window");

I’ve been now able to connect the Application to the ApplicationWindow with:

    app.add_window(&window);

But I don’t understand why this didn’t work instead:

    window.set_application(Some(&app));

Which produced the following:

error[E0277]: the trait bound `BorrowedObject<'_, application::SpApplication>: IsA<gtk::Application>` is not satisfied
   --> src/application/imp.rs:64:32
    |
64  |         window.set_application(Some(&app));
    |                --------------- ^^^^^^^^^^ the trait `IsA<gtk::Application>` is not implemented for `BorrowedObject<'_, application::SpApplication>`
    |                |
    |                required by a bound introduced by this call
    |
    = help: the following other types implement trait `IsA<T>`:
              <AboutDialog as IsA<AboutDialog>>
              <AboutDialog as IsA<Bin>>
              <AboutDialog as IsA<Buildable>>
              <AboutDialog as IsA<Container>>
              <AboutDialog as IsA<glib::Object>>
              <AboutDialog as IsA<gtk::Dialog>>
              <AboutDialog as IsA<gtk::Widget>>
              <AboutDialog as IsA<gtk::Window>>
            and 1526 others
note: required by a bound in `gtk::prelude::GtkWindowExt::set_application`
   --> /home/jeff/.cargo/registry/src/github.com-1ecc6299db9ec823/gtk-0.16.2/src/auto/window.rs:958:57
    |
958 |     fn set_application(&self, application: Option<&impl IsA<Application>>);
    |                                                         ^^^^^^^^^^^^^^^^ required by this bound in `gtk::prelude::GtkWindowExt::set_application`

Am I still missing an @extends or @implements?

Instead, try one of the two following

window.set_application(Some(&*app));
window.set_application(Some(app.as_ref()));

The problem is that BorrowedObject does not directly implement the required traits, and Rust can’t figure out that it would all be fine after a deref because of this.

Both work. Thanks for the explanation!

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.