It is time again for a new gtk-rs release!

If you have been watching our crates on crates.io closely or if you have attended GUADEC you may already have noticed that we have released new versions of the gtk-rs crates.

The new versions contain less breaking changes than some of our previous releases, so updating will be easier. The release however does include some nice improvements that can simplify your application as well as support the latest API additions of the underlying libraries.

As anticipated in the previous release, this will likely be the last release of the gtk3-rs bindings and we recommend to everyone to upgrade to GTK4. If you require gtk3-rs to keep up with new versions of gtk-rs-core please consider volunteering to help with maintenance of the project.

Increase of the minimum supported Rust version (MSRV) §

With this release, Rust 1.70 is the minimum version required to compile and use the bindings.

Supported versions §

  • glib/gio: from version 2.56 to 2.78
  • cairo: 1.16
  • pango/pangocairo: from version 1.40 to the to be released 1.52
  • gdk-pixbuf: from version 2.36 to 2.42
  • graphene: from version 1.10 to 1.12
  • gtk4: from 4.0 to 4.12 with minimal support of the upcoming 4.14 release
  • gtk3: from 3.22

Documentation improvements §

In this release, we also started a slow but steady path towards automatically generating subclassing traits. The first step is to parse the corresponding virtual methods data from the GIR file and embed the documentation for these functions to their corresponding Rust functions like we do for normal functions/methods/types.

See https://gtk-rs.org/gtk4-rs/stable/latest/docs/gtk4/subclass/widget/trait.WidgetImpl.html#method.keynav_failed

We also now embed the documentation for Class methods. See https://gtk-rs.org/gtk4-rs/stable/latest/docs/gtk4/subclass/widget/trait.WidgetClassExt.html#method.install_property_action

Last but not least, libraries depending on gtk-rs libraries can now have their documentation published in docs.rs by adding the following to your Cargo.toml.

[package.metadata.docs.rs]
all-features = true
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
features = []

Switch to bitflags 2.0 §

With this release we switched to version 2 of the bitflags crate. While we regularly update our dependencies to the latest version, this is of particular note since flag types are often used in glib and GTK API.

We also re-export bitflags and once_cell from the glib crate so you can use them without directly depending on them.

gtk-rs-core §

New glib::derived_properties macro §

With the glib::Properties derive macro added in the last release, you still had to write these blanket functions manually

impl ObjectImpl for T {
    fn properties() -> &'static [glib::ParamSpec] {
        Self::derived_properties()
    }
    fn set_property(&self, id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
        self.derived_set_property(id, value, pspec)
    }
    fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value {
        self.derived_property(id, pspec)
    }
}

Now you can replace that code with

#[glib::derived_properties]
impl ObjectImpl for T {}

Replacement of glib::Continue / glib::Inhibit §

These two types were a bit difficult to understand, as you had to pass a boolean glib::Continue(true) / glib::Inhibit(false). We replaced them with new enums

glib::Continue(true) -> glib::ControlFlow::Continue
glib::Continue(false) -> glib::ControlFlow::Break
glib::Inhibit(true) -> glib::Propagation::Stop
glib::Inhibit(false) -> glib::Propagation::Proceed

Making the meaning of each value clearer to the developer. This should be the most annoying change you need to do during the update to this release.

Typed constructors §

In the past we had a bunch of constructors taking glib::Type as a parameter instead of T: impl StaticType / T: impl IsA<O>. For this release, we cleaned up several of those constructors.

let model = gio::ListStore::new(SomeObject::static_type()); // before
let model = gio::ListStore::new::<SomeObject>(); // after
let model = gio::ListStore::with_type(SomeObject::static_type()); // is available for specific use cases

Changed constructors:

  • glib::SignalGroup
  • glib::FlagsClass
  • glib::EnumClass

New glib::ValueDelegate macro §

Let’s say you want to create a wrapper around some type, but you want to retain ToValue, FromValue, and HasParamSpec implementations, which are especially necessary when you want to use a type as a property. This is where the glib::ValueDelegate macro comes in. Instead of having to manually implement the following:

pub struct Uid(String);

impl glib::types::StaticType for Uid {
    fn static_type() -> glib::types::Type {
        <String as glib::types::StaticType>::static_type()
    }
}

impl glib::value::ToValue for Uid {
    fn to_value(&self) -> glib::value::Value {
        glib::value::ToValue::to_value(&self.0)
    }

    fn value_type(&self) -> glib::types::Type {
        glib::value::ToValue::value_type(&self.0)
    }
}

impl From<Uid> for glib::value::Value {
    fn from(uid: Uid) -> Self {
        glib::value::Value::from(uid.0)
    }
}

unsafe impl<'a> glib::value::FromValue<'a> for Uid {
    type Checker = <String as glib::value::FromValue<'a>>::Checker;
    unsafe fn from_value(value: &'a glib::value::Value) -> Self {
        Uid(<String as glib::value::FromValue<'a>>::from_value(value))
    }
}

impl glib::HasParamSpec for Uid {
    type ParamSpec = <String as glib::HasParamSpec>::ParamSpec;
    type SetValue = Self;
    type BuilderFn = <String as glib::HasParamSpec>::BuilderFn;
    fn param_spec_builder() -> Self::BuilderFn {
        <String as glib::HasParamSpec>::param_spec_builder()
    }
}

you can simply use the macro as follows:

#[derive(glib::ValueDelegate)]
pub struct Uid(String);

For more complex cases, see the documentation.

You could also achieve the same by using glib::Boxed, but glib::ValueDelegate provides a thinner wrapper as it only calls to the inner implementation instead of using GBoxed. Additionally, glib::ValueDelegate propagates the GType to the wrapper instead of creating a new GType.

gtk4-rs §

The bindings now support GTK 4.12 with v4_12 feature flag. Other than that they didn’t see many user facing changes. The development mainly focused on various cleanups and bug fixes.

Blueprint support in gtk::CompositeTemplate §

You can now use blueprint with both string and file attributes of the gtk::CompositeTemplate macro. This requires having the blueprint-compiler binary installed.

use gtk::{glib, prelude::*, subclass::prelude::*};

mod imp {
    use super::*;

    #[derive(Debug, Default, gtk::CompositeTemplate)]
    #[template(string = "
    template MyWidget : Widget {
        Label label {
            label: 'foobar';
        }

        Label my_label2 {
            label: 'foobaz';
        }
    }
    ")]
    pub struct MyWidget {
        #[template_child]
        pub label: TemplateChild<gtk::Label>,
        #[template_child(id = "my_label2")]
        pub label2: gtk::TemplateChild<gtk::Label>,
    }

    #[glib::object_subclass]
    impl ObjectSubclass for MyWidget {
        const NAME: &'static str = "MyWidget";
        type Type = super::MyWidget;
        type ParentType = gtk::Widget;
        fn class_init(klass: &mut Self::Class) {
            klass.bind_template();
        }
        fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
            obj.init_template();
        }
    }

    impl ObjectImpl for MyWidget {
        fn dispose(&self) {
            while let Some(child) = self.obj().first_child() {
                child.unparent();
            }
        }
    }
    impl WidgetImpl for MyWidget {}
}

glib::wrapper! {
    pub struct MyWidget(ObjectSubclass<imp::MyWidget>) @extends gtk::Widget;
}

Stop using deprecated StyleContext APIs §

The gtk::StyleContext::add_provider_for_display / gtk::StyleContext::remove_provider_for_display functions were never supposed to be part of the gtk::StyleContext type. Since that type was deprecated upstream in GTK 4.10, the developers now annoyingly had to use #[allow(deprecated)], even though those two functions were not deprecated at all.

We have added gtk::style_context_add_provider_for_display / gtk::style_context_remove_provider_for_display as a replacement for them.

Detailed Changes §

Here is the full list of the merged pull requests:

gtk-rs-core:

gtk3-rs:

gtk4-rs:

All this was possible thanks to the gtk-rs/gir project as well:

Thanks to all of our contributors for their (awesome!) work on this release: