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

GLib-GObject-CRITICAL on shutdown of app with root SimpleAsyncComponent and AsyncController with adw::PreferencesWindow #626

Open
lessneek opened this issue Mar 30, 2024 · 1 comment

Comments

@lessneek
Copy link

There is a GLib-GObject-CRITICAL error on main window closing within SimpleAsyncComponent when there is a transient adw::PreferencesWindow within another SimpleAsyncComponent.

There is no error if the root component is SimpleComponent (not async).
There is no error if a child component root is adw::Window (not adw::PreferencesWindow).
There is no error if there is no calling for .transient_for(...) of a child component builder.

Logs and code files:

(relm4-gtk-bug-1:224499): GLib-GObject-CRITICAL **: 15:56:25.340: instance with invalid (NULL) class pointer

(relm4-gtk-bug-1:224499): GLib-GObject-CRITICAL **: 15:56:25.340: g_signal_handlers_disconnect_matched: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

(relm4-gtk-bug-1:224499): GLib-GObject-CRITICAL **: 15:56:25.340: instance with invalid (NULL) class pointer

(relm4-gtk-bug-1:224499): GLib-GObject-CRITICAL **: 15:56:25.340: g_signal_handlers_disconnect_matched: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

(relm4-gtk-bug-1:224499): GLib-GObject-CRITICAL **: 15:56:25.340: instance with invalid (NULL) class pointer

(relm4-gtk-bug-1:224499): GLib-GObject-CRITICAL **: 15:56:25.340: g_signal_handlers_disconnect_matched: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

(relm4-gtk-bug-1:224499): GLib-GObject-CRITICAL **: 15:56:25.340: instance with invalid (NULL) class pointer

(relm4-gtk-bug-1:224499): GLib-GObject-CRITICAL **: 15:56:25.340: g_signal_handlers_disconnect_matched: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed
cargo.toml
[package]
name = "relm4-gtk-bug-1"
version = "0.1.0"
edition = "2021"

[dependencies]
adw = { version = "0.6.0", package = "libadwaita" }
relm4 = { version = "0.8.1", features = ["all", "libadwaita", "gnome_45"] }
preferences.rs
use super::AppInput;
use adw::prelude::*;
use relm4::{
    component::{AsyncComponentParts, SimpleAsyncComponent},
    *,
};

#[derive(Debug)]
pub struct PreferencesModel {
    window: adw::PreferencesWindow,
}

#[derive(Debug)]
pub enum PreferencesMsg {
    Show,
    Close,
}

#[relm4::component(async, pub)]
impl SimpleAsyncComponent for PreferencesModel {
    type Init = ();
    type Input = PreferencesMsg;
    type Output = AppInput;
    type Widgets = PreferencesWidgets;

    view! {
        adw::PreferencesWindow {
            connect_close_request[sender] => move |_| {
                sender.input(PreferencesMsg::Close);
                gtk::glib::Propagation::Stop
            },
        }
    }

    async fn init(
        _: Self::Init,
        root: Self::Root,
        sender: AsyncComponentSender<Self>,
    ) -> AsyncComponentParts<Self> {
        let model = PreferencesModel {
            window: root.clone(),
        };

        let widgets = view_output!();

        AsyncComponentParts { model, widgets }
    }

    async fn update(&mut self, message: Self::Input, _sender: AsyncComponentSender<Self>) {
        match message {
            PreferencesMsg::Show => self.window.present(),
            PreferencesMsg::Close => self.window.set_visible(false),
        }
    }
}
main.rs
mod preferences;

use std::convert::identity;

use adw::prelude::*;
use relm4::prelude::*;

use preferences::{PreferencesModel, PreferencesMsg};

struct AppModel {
    preferences: AsyncController<PreferencesModel>,
}

#[derive(Debug)]
pub enum AppInput {
    Pref,
}

#[relm4::component(async)]
impl SimpleAsyncComponent for AppModel {
    type Init = ();
    type Output = ();
    type Input = AppInput;

    view! {
        adw::Window {
            set_title: Some("relm4.gtk.bug1"),
            set_default_size: (300, 600),

            gtk::Box {
                set_orientation: gtk::Orientation::Vertical,

                adw::HeaderBar {},

                gtk::Button {
                    set_label: "Pref",
                    set_margin_all: 10,
                    connect_clicked => AppInput::Pref,
                }
            }
        }
    }

    async fn init(
        _init: Self::Init,
        root: Self::Root,
        sender: AsyncComponentSender<Self>,
    ) -> AsyncComponentParts<Self> {
        let model = AppModel {
            preferences: PreferencesModel::builder()
                .transient_for(&root)
                .launch(())
                .forward(sender.input_sender(), identity),
        };
        let widgets = view_output!();

        AsyncComponentParts { model, widgets }
    }

    async fn update(&mut self, message: Self::Input, _sender: AsyncComponentSender<Self>) {
        match message {
            AppInput::Pref => {
                self.preferences.emit(PreferencesMsg::Show);
            }
        }
    }
}

fn main() {
    let app = relm4::RelmApp::new("relm4.gtk.bug1");
    app.run_async::<AppModel>(());
}
@AaronErhardt
Copy link
Member

I could narrow the cause down to the shutdown code that shuts down all components when your app quits, called here.

The error shouldn't be problematic though because it's just before the app quits anyway. It's obviously annoying, but I don't know how I can further debug this from the Relm4 side. Our code does nothing unsafe or unexpected but we sometimes use gtk-rs in ways regular gtk-rs apps never do. It wouldn't be the first bug in GTK/gtk-rs we uncovered with Relm4, but I'm not sure how to report this one. But it seems to be related to adw::PreferencesWindow...

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

2 participants