Hello, I have an issue and I am looking for help with it please.
I am using gtk-rs and the Composite Template feature.
I create 2 custom widgets:
- MainWindow subclass of adw::ApplicationWindow
- State subclass of gtk::Widget: This widget has only data fields and has no graphic representation. Hence the choice of subclassing only gtk::Widget because it is the smallest subset I need (or so I think).
Problem: The State widget’s instance has no root or parent.
State Widget code:
#[derive(Debug, Default, CompositeTemplate)]
#[template(resource = "/ui/state.ui")]
pub struct State {
// Some data fields
}
#[glib::object_subclass]
impl ObjectSubclass for State {
const NAME: &'static str = "State";
type Type = super::State;
type ParentType = gtk::Widget;
fn class_init(klass: &mut Self::Class) {
klass.bind_template();
}
fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
}
impl ObjectImpl for State {
fn constructed(&self) {
self.parent_constructed();
}
}
impl WidgetImpl for State {}
}
glib::wrapper! {
pub struct State(ObjectSubclass<imp::State>)
@extends gtk::Widget,
@implements gtk::Accessible;
}
impl Default for State {
fn default() -> Self {
Self::new()
}
}
impl State {
pub fn foo(&self) {
// This line panic on a None value.
let root = self.root().unwrap();
let mainwindow = root.downcast::<MainWindow>().unwrap();
// Do something...
}
}
XML definition of State (Complete there is nothing else)
<?xml version='1.0' encoding='UTF-8'?>
<interface>
<template class="State" parent="GtkWidget">
</template>
</interface>
A call to State::foo() function returns a panic:
thread ‘main’ panicked at ‘called
Option::unwrap()
on aNone
value’.
To correct this, I set State’s parent myself in his parent construction function. MainWindow is the parent and root Widget.
Here is MainWindow widget subclass of adw::ApplicationWindow.
MainWindow widget code:
#[derive(Debug, Default, CompositeTemplate)]
#[template(resource = "/ui/window.ui")]
pub struct MainWindow {
#[template_child]
pub state: TemplateChild<State>,
// Others fields with template widgets
}
#[glib::object_subclass]
impl ObjectSubclass for MainWindow {
const NAME: &'static str = "MainAppWindow";
type Type = super::MainWindow;
type ParentType = adw::ApplicationWindow;
fn class_init(klass: &mut Self::Class) {
State::ensure_type();
klass.bind_template();
klass.bind_template_instance_callbacks();
}
fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
}
impl ObjectImpl for MainWindow {
fn constructed(&self) {
self.parent_constructed();
// For unknown reasons, at creation time, the State Widget has no root or parent widget.
// We set MainWindow as the parent for state Widget
let obj = self.obj();
self.obj().imp().state.set_parent(&*obj);
}
// Other implementations
}
#[gtk::template_callbacks]
impl MainWindow {
#[template_callback]
fn file_open_response(&self, res: i32) {
// Some code...
let state = &self.imp().state;
state.foo();
}
}
XML definition of MainWindow:
<?xml version='1.0' encoding='UTF-8'?>
<interface>
<template class="MainAppWindow" parent="AdwApplicationWindow">
<object class="State" id="state"/>
<child>
<object class="AdwToastOverlay" id="something">
...
</template>
</interface>
Having set the root of State myself, the application doesn’t panic anymore but I get another gtk warning:
Trying to snapshot State 0x55b3795d4050 without a current allocation.
I suspect this has something to do with size allocation for my custom State widget but I am not sure and I don’t know how I can get rid of it.
My questions are:
- Why MainApplication widget isn’t automatically set as the State’s parent or root as in the XML file? What did I miss?
- What is the meaning of the warning: Trying to snapshot State 0x55b3795d4050 without a current allocation. How do I create a custom gtk::Widget without getting this warning?
Thank you for spending time on my problem