It’s been a long time since the last release, and, as you can guess, a lot of things happened in this span of time. Let’s start with the most important one:

gtk-rs now provides bindings for GTK4 libraries!

They are all available in the gtk4-rs repository.

We also wrote an introductory book to teach users how to use gtk4-rs. You can read it here. A more detailed blog post about GTK4 will follow in the next days.

We used this occasion to completely re-design the website and also make a logo. Since you’re already here, don’t hesitate to go take a look around!

GNOME Circle §

gtk-rs is now part of the GNOME Circle! It allows our contributors to join the GNOME foundation if they want to in addition to some other benefits. Check the website for more details.

Repositories changes §

This release also saw changes to the gtk-rs repositories structure. We now have three main repositories:

  • gtk-rs-core: It contains crates which are considered “core” because they are used by both GTK3 and GTK4, but also by other projects such as gstreamer-rs:
    • cairo
    • gdk-pixbuf
    • gio
    • glib
    • glib-macros
    • graphene
    • pango
    • pangocairo
  • gtk3-rs: Contains crates which are part of the GTK3 ecosystem:
    • atk
    • gdk
    • gdkx11
    • gtk3-macros
  • gtk4-rs: Contains crates which are part of the GTK4 ecosystem:
    • gdk4
    • gdk4-wayland
    • gdk4-x11
    • gsk4
    • gtk4
    • gtk4-macros

Another important point about this: all crates in one repository share the same version number now. Before it was a bit of a mess so we decided to simplify it. So here are the version numbers for each repository:

Documentation improvements §

gtk-rs crates use the C documentation, however we improved its rendering a bit to make it even more useful for Rust developers:

  • The items’ links are now correctly generated.
  • If code examples are not written in Rust, we now add warnings to avoid confusion.
  • We added doc aliases, so you can now search signal names and even C function names directly.
  • Global functions, builder patterns, constants and statics are now documented as well.
  • Arguments which are C specific and therefore not used in the Rust bindings are not rendered anymore.

Dependencies are re-exported §

Instead of a long explanation, let’s take an example. You have a GTK application and you also use Cairo and GDK. Before this release, you would add all the 3 dependencies to your Cargo.toml file to be able to use them. Now, you only need to import GTK and then you can do:

use gtk::{cairo, gdk};

And that’s it! It’ll make your management of dependencies much simpler. To be noted, relevant traits are also re-exported in the prelude, so importing it will give you access to them:

use gtk::gdk;
use gtk::prelude::*;

// ...
// This uses the `gdk::prelude::WindowExtManual` trait, through the prelude.
let w = gdk::Window::default_root_window();

Last note about the re-exports: the -sys crates are also re-exported under the name ffi:

use gtk::ffi;

// You now have access to all raw C-functions of GTK.

The Value trait was refactored §

The main change is that for non-nullable types Value::get() will never ever return None, replacing the previous confusing Value::get_some().

In addition it is now possible to Value::get() a nullable type directly without Option wrapping. If the value was actually None this would return an Err. In cases where the value being None was unexpected this avoids one layer of unwrapping.

There is also a new generic ValueType trait that is implemented by all types that can be used inside a Value and that allows storing/retrieving types of this value into/from a Value.

Added GTK composite template support §

For constructing widgets from a UI file, you can either use gtk::Builder or composite templates. With the former, you have to keep an instance of gtk::Builder around. While with composite templates, you make your custom widget (a subclass of gtk::Widget) use the template internally and with the difference of being able to use your CustomWidget in a different UI file by defining:

<object class="CustomWidget">
  <property name="some-property">some-value</property>
</object>

You can now make your CustomWidget use the #[CompositeTemplate] derive macro. The work was done initially for GTK4 Rust bindings, but was backported to GTK3 as well. See here or here for examples.

Composite templates also allow you to use methods defined on your CustomWidget as a callback to a signal directly from the UI file, even though the macro doesn’t support that for now for both GTK3/GTK4 bindings… But don’t worry, we’re working on it!

New and improved macros §

In addition to the glib::object_subclass attribute macro (see link to paragraph about subclassing improvements), glib provides a couple of other macros now for making application development easier and with less boilerplate:

  • glib::clone!: This macro allows automatic cloning or creation of weak references plus upgrading for closures and greatly simplifies creation of signal handler closures. The documentation contains a couple of examples. While this macro existed in the last release already, it was completely rewritten and made more powerful and got a companion derive macro glib::Downgrade that extends custom types with the required machinery to be used for weak references in the context of the clone! macro.
  • glib::GBoxed and glib::GSharedBoxed: These derive macros allow using custom Rust types inside glib::Values, which is required for example for GObject properties and signal parameters/return values or the content of GTK tree views. The first macro always clones the underlying value when necessary while the second makes use of reference counting instead of normal cloning.
  • glib::gflags! and glib::GEnum: These macros allow using Rust enums and bitflags to be used inside glib::Values. See the subclassing docs for examples.
  • glib::GErrorDomain: This derive macro allows using a suitable Rust enum to be used as an error domain for glib::Errors.

See also the subclassing docs for more examples about the glib::GBoxed, glib::gflags and glib::GEnum macros.

Improvements to subclassing §

Implementing a GObject is simpler, thanks to the introduction of the glib::object_subclass derive macro. Additionally registering properties and signals now requires less boiler plate. Refer to this page for a complete example but a minimal example would look as follows now:

mod imp {
    #[derive(Default)]
    pub struct MyObject;

    #[glib::object_subclass]
    impl ObjectSubclass for MyObject {
        const NAME: &'static str = "MyObject";

        type Type = super::MyObject;
        type ParentType = glib::Object;
    }

    impl ObjectImpl for MyObject {}
}

glib::wrapper! {
    pub struct MyObject(ObjectSubclass<imp::MyObject>);
}

impl MyObject {
    pub fn new() -> Self {
        glib::Object::new(&[]).unwrap()
    }
}

Better cairo error handling §

Using cairo is now more ergonomic: functions like fill() or stroke() return a Result instead of requiring to manually check the Context::status(). Additionally, all internal calls to expect() on the cairo status were removed, enabling the caller to handle error conditions, rather than causing a panic.

Gir tutorial §

gtk-rs crates are mostly generated automatically thanks to the gir project. If you also want to generate your own GObject-based crate bindings, you can use it as well! To help you, we started a tutorial book that is available here.

Naming improvements §

We renamed a lot of functions/methods in order to make them more Rust-compliant. Specifically, getter functions were renamed from get_something() to just something() or is_something() while the setters stayed as set_something(). In addition GObject property getters/setters lost their property designation from the name (i.e. set_property_something() was replaced by set_something()).

On this note:

Note to applications developers §

Applications developers should use fix-getters-calls to ease migration of their applications. Use fix-getters-def if you also want your get functions definition to comply with the API standards applied in this release.

Minimum supported versions §

Rust minimum supported version is now 1.51.

  • ATK: 2.18
  • Cairo: 1.14
  • GDK3: 3.18
  • GDK4: 4.0
  • GDK4-Wayland: 4.0
  • GDKX11: 3.18
  • GDK4-X11: 4.0
  • GDK-Pixbuf: 2.32
  • Gio: 2.48
  • GLib: 2.48
  • Graphene: 1.10
  • GSK4: 4.0
  • GTK3: 3.20
  • GTK4: 4.0
  • Pango: 1.38
  • PangoCairo: 1.38

Migration to the Rust 2018 edition §

The gtk-rs crates all migrated to the Rust 2018 edition. Just in time because the 2021 edition is getting close!

Changes §

For the interested ones, here is the list of the merged pull requests:

gtk-rs-core:

gtk3-rs:

gtk4-rs:

All this was possible thanks to the gir project as well:

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