gtk-rust-app 0.3.0

Framework for writing flatpak apps with GTK in Rust
docs.rs failed to build gtk-rust-app-0.3.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: gtk-rust-app-0.2.3

Rust GTK App Framework

pipeline status API

icon.svg"

(Yes that's the icon)

This libaray aims to provide a framework for adaptive GTK4 and libadwaita apps written in Rust.

Writing flatpak apps requires several files (.desktop file, appdata.xml, flatpak manifest). gtk-rust-app and its CLI gra allow to generate these files based on an extended Cargo.toml.

Getting started

Creating apps with gtk-rust-app requires to

  1. Add more metadata to the Cargo.toml
  2. Write some boilerplate code in main.rs
  3. Define App pages
  4. Optional: Define a build.rs script
  5. Install cargo-gra subcommand

Cargo.toml

Define app metadata and the dependency to gtk-rust-app in your Cargo.toml (see Manifest for more information):

# Cargo.toml

[package]
...

[app]
# Metadata of your app

[settings]
# global settings

[actions]
# global GTK actions

[dependencies]

# as usual

gtk-rust-app = { git = "https://gitlab.com/loers/gtk-rust-app.git", features = [ "ui" ] }

# If you want to automatically update generated files you can add this build dependency
[build-dependencies]
gtk-rust-app = { git = "https://gitlab.com/loers/gtk-rust-app.git", features = [ "build" ] }

App boilerplate code

Create the file main.rs:

// src/main.rs

#[macro_use]
extern crate gtk_rust_app;
#[macro_use]
extern crate log;

use gettextrs::gettext;
use gtk::prelude::*;
use gtk_rust_app::widgets::LeafletLayout;

use crate::home::Home;

// This module will contain our home page
mod card;
mod home;

fn main() {
    env_logger::init();

    info!("{}", gettext("Check po/ dir for translations."));

    // call app builder with metadata from your Cargo.toml and the gresource file compiled by the `gtk_rust_app::build` script (see below).
    gtk_rust_app::builder::builder(
        include_bytes!("../Cargo.toml"),
        include_bytes!("../target/gra-gen/compiled.gresource"),
    )
    // include your style sheets here
    .styles(include_str!("styles.css"))
    .build(
        |application, _project_descriptor, settings| {
            // setup custom types
            card::Card::static_type();

            // The pages will be placed in this predefined adaptive layout.
            let leaflet_layout = LeafletLayout::builder(settings)
                .add_page(Home::new())
                .build();

            // LeafletLayout contains a toast overlay
            leaflet_layout.show_message("Hello world");

            // and we use the leaflet layout as root content in the apps window.
            let window = gtk_rust_app::window(
                application,
                gettext("Example"),
                settings,
                leaflet_layout.upcast_ref(),
            );
            window.show();
        },
        |app, _project_descriptor, _settings| {
            if let Some(action) = app.lookup_action("quit") {
                let simple_action: gdk4::gio::SimpleAction = action.downcast().unwrap();
                simple_action.connect_activate(glib::clone!(@weak app => move |_, _| {
                    app.quit();
                }));
            }
        },
    );
}

Define app pages

The home page:

//src/home.rs

use gdk4::subclass::prelude::ObjectSubclassIsExt;
use gtk::prelude::*;
use gettextrs::gettext;
use crate::card::Card;

// Define a page of your app as a new widget
#[widget(gtk::Box)]
#[template(file = "home.ui")]
struct Home {
    #[template_child]
    pub card: TemplateChild<Card>,
}

impl Home {
    pub fn constructed(&self) {
        self.imp().card.connect_card_clicked(|card| {
            println!("Text prop: {:?}", card.text());
        });
    }

    pub fn new() -> Home {
        glib::Object::new(&[]).expect("Failed to create Home")
    }
}

impl gtk_rust_app::widgets::Page for Home {
    fn name(&self) -> &'static str {
        "home"
    }

    fn title_and_icon(&self) -> Option<(String, String)> {
        Some((gettext("Home"), "go-home-symbolic".into()))
    }
}
// home.ui
<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <template class="Home" parent="GtkBox">
    <property name="hexpand">True</property>
    <property name="vexpand">True</property>
    <property name="orientation">vertical</property>
    <style>
      <class name="home" />
    </style>

    <child>
      <object class="Card" id="card"></object>
    </child>

  </template>
</interface>

Optional: Build script

Define the build script:

// build.rs
pub fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=Cargo.toml");
    println!("cargo:rerun-if-changed=src");
    println!("cargo:rerun-if-changed=assets");
    println!("cargo:rerun-if-changed=po");
    gtk_app_framework::build(None);
}

Install cargo-gra

cargo install cargo-gra 

Prepare the app build via:

cargo gra setup

and build it as usual:

cargo build --release

You can build a flatpak app via:

cargo gra flatpak

That's it. You will see an app like this:

screenshot1.png

The app has adaptive behaviour per default.

screenshot2.png

Run with different language

LANGUAGE="de_DE:de" LANG="de_DE.utf8" TEXT_DOMAIN="target" cargo run

Build

# build your binary release
cargo build --release
# create a flatpak
make -C out flat

Requirements

Debian dependencies:

sudo apt install libgraphene-1.0-dev libgtk-4-dev flatpak-builder

Arch dependencies:

pacman

To build a flatpak you need the to install gnome-nightly remote. Download https://nightly.gnome.org/gnome-nightly.flatpakrepo.

flatpak remote-add --if-not-exists gnome-nightly gnome-nightly.flatpakrepo
flatpak install org.gnome.Sdk//master
flatpak install org.gnome.Platform//master
flatpak install org.freedesktop.Sdk.Extension.rust-stable//21.08