[gnome-builder/gnome-builder-41] meson-templates: Add GTK4 Rust template



commit b2bd0ade91a98b051425c0b171c1e3439ad30a2f
Author: Marco Melorio <marco melorio protonmail com>
Date:   Thu Oct 28 20:25:26 2021 +0200

    meson-templates: Add GTK4 Rust template
    
    This is based on the current GTK4 C template.

 .../meson-templates/meson-templates.gresource.xml  |  6 ++
 src/plugins/meson-templates/meson_templates.py     | 13 +--
 .../meson-templates/resources/src/Cargo-gtk4.toml  |  8 ++
 .../meson-templates/resources/src/application.rs   | 92 ++++++++++++++++++++++
 .../resources/src/config-gtk4.rs.in                |  4 +
 .../meson-templates/resources/src/main-gtk4.rs     | 35 ++++++++
 .../resources/src/meson-rs-gtk4.build              | 57 ++++++++++++++
 .../meson-templates/resources/src/window-gtk4.rs   | 50 ++++++++++++
 8 files changed, 259 insertions(+), 6 deletions(-)
---
diff --git a/src/plugins/meson-templates/meson-templates.gresource.xml 
b/src/plugins/meson-templates/meson-templates.gresource.xml
index 3f96c5871..57620d8ca 100644
--- a/src/plugins/meson-templates/meson-templates.gresource.xml
+++ b/src/plugins/meson-templates/meson-templates.gresource.xml
@@ -13,10 +13,12 @@
     <file compressed="true">resources/src/meson-clib.build</file>
     <file compressed="true">resources/src/meson-js.build</file>
     <file compressed="true">resources/src/meson-rs.build</file>
+    <file compressed="true">resources/src/meson-rs-gtk4.build</file>
     <file compressed="true">resources/src/hello.c</file>
     <file compressed="true">resources/src/hello.h</file>
     <file compressed="true">resources/src/application.c</file>
     <file compressed="true">resources/src/application.h</file>
+    <file compressed="true">resources/src/application.rs</file>
     <file compressed="true">resources/src/__init__.py</file>
     <file compressed="true">resources/src/meson-c-vala.build</file>
     <file compressed="true">resources/src/meson-empty.build</file>
@@ -33,17 +35,21 @@
     <file compressed="true">resources/src/window.py</file>
     <file compressed="true">resources/src/window.vala</file>
     <file compressed="true">resources/src/config.rs.in</file>
+    <file compressed="true">resources/src/config-gtk4.rs.in</file>
     <file compressed="true">resources/src/window.rs</file>
+    <file compressed="true">resources/src/window-gtk4.rs</file>
     <file compressed="true">resources/src/main.vala</file>
     <file compressed="true">resources/src/main-cli.vala</file>
     <file compressed="true">resources/src/hello.py.in</file>
     <file compressed="true">resources/src/main.py</file>
     <file compressed="true">resources/src/main.rs</file>
+    <file compressed="true">resources/src/main-gtk4.rs</file>
     <file compressed="true">resources/src/main-cli.rs</file>
     <file compressed="true">resources/src/application.in</file>
     <file compressed="true">resources/src/main.cs</file>
     <file compressed="true">resources/src/Cargo.lock</file>
     <file compressed="true">resources/src/Cargo.toml</file>
+    <file compressed="true">resources/src/Cargo-gtk4.toml</file>
     <file compressed="true">resources/src/Cargo-cli.toml</file>
     <file compressed="true">resources/src/meson-cs.build</file>
     <file compressed="true">resources/build-aux/cargo.sh</file>
diff --git a/src/plugins/meson-templates/meson_templates.py b/src/plugins/meson-templates/meson_templates.py
index f4be02cb3..4f465b244 100644
--- a/src/plugins/meson-templates/meson_templates.py
+++ b/src/plugins/meson-templates/meson_templates.py
@@ -330,7 +330,7 @@ class GnomeGTK4ProjectTemplate(MesonTemplate):
             _('GNOME Application'),
             'pattern-gnome',
             _('Create a GNOME application with GTK 4'),
-            ['C'],
+            ['C', 'Rust'],
             0
          )
 
@@ -389,13 +389,14 @@ class GnomeGTK4ProjectTemplate(MesonTemplate):
             files['resources/src/main.py'] = 'src/main.py'
             meson_file = 'resources/src/meson-py.build'
         elif self.language == 'rust':
-            files['resources/src/config.rs.in'] = 'src/config.rs.in'
-            files['resources/src/main.rs'] = 'src/main.rs'
-            files['resources/src/window.rs'] = 'src/window.rs'
+            files['resources/src/application.rs'] = 'src/application.rs'
+            files['resources/src/config-gtk4.rs.in'] = 'src/config.rs.in'
+            files['resources/src/main-gtk4.rs'] = 'src/main.rs'
+            files['resources/src/window-gtk4.rs'] = 'src/window.rs'
             files['resources/src/Cargo.lock'] = 'Cargo.lock'
-            files['resources/src/Cargo.toml'] = 'Cargo.toml'
+            files['resources/src/Cargo-gtk4.toml'] = 'Cargo.toml'
             files['resources/build-aux/cargo.sh'] = 'build-aux/cargo.sh'
-            meson_file = 'resources/src/meson-rs.build'
+            meson_file = 'resources/src/meson-rs-gtk4.build'
 
         if resource_name:
             files['resources/src/hello.gresource.xml'] = resource_name
diff --git a/src/plugins/meson-templates/resources/src/Cargo-gtk4.toml 
b/src/plugins/meson-templates/resources/src/Cargo-gtk4.toml
new file mode 100644
index 000000000..c8c9ce406
--- /dev/null
+++ b/src/plugins/meson-templates/resources/src/Cargo-gtk4.toml
@@ -0,0 +1,8 @@
+[package]
+name = "{{name}}"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
+gettext-rs = { version = "0.7", features = ["gettext-system"] }
+gtk = { version = "0.3", package = "gtk4" }
diff --git a/src/plugins/meson-templates/resources/src/application.rs 
b/src/plugins/meson-templates/resources/src/application.rs
new file mode 100644
index 000000000..1f13b37f6
--- /dev/null
+++ b/src/plugins/meson-templates/resources/src/application.rs
@@ -0,0 +1,92 @@
+use glib::clone;
+use gtk::prelude::*;
+use gtk::subclass::prelude::*;
+use gtk::{gio, glib};
+
+use crate::config::VERSION;
+use crate::{{PreFix}}Window;
+
+mod imp {
+    use super::*;
+
+    #[derive(Debug, Default)]
+    pub struct {{PreFix}}Application {}
+
+    #[glib::object_subclass]
+    impl ObjectSubclass for {{PreFix}}Application {
+        const NAME: &'static str = "{{PreFix}}Application";
+        type Type = super::{{PreFix}}Application;
+        type ParentType = gtk::Application;
+    }
+
+    impl ObjectImpl for {{PreFix}}Application {
+        fn constructed(&self, obj: &Self::Type) {
+            self.parent_constructed(obj);
+
+            obj.setup_gactions();
+            obj.set_accels_for_action("app.quit", &["<primary>q"]);
+        }
+    }
+
+    impl ApplicationImpl for {{PreFix}}Application {
+        // We connect to the activate callback to create a window when the application
+        // has been launched. Additionally, this callback notifies us when the user
+        // tries to launch a "second instance" of the application. When they try
+        // to do that, we'll just present any existing window.
+        fn activate(&self, application: &Self::Type) {
+            // Get the current window or create one if necessary
+            let window = if let Some(window) = application.active_window() {
+                window
+            } else {
+                let window = {{PreFix}}Window::new(application);
+                window.set_default_size(600, 300);
+                window.upcast()
+            };
+
+            // Ask the window manager/compositor to present the window
+            window.present();
+        }
+    }
+
+    impl GtkApplicationImpl for {{PreFix}}Application {}
+}
+
+glib::wrapper! {
+    pub struct {{PreFix}}Application(ObjectSubclass<imp::{{PreFix}}Application>)
+        @extends gio::Application, gtk::Application,
+        @implements gio::ActionGroup, gio::ActionMap;
+}
+
+impl {{PreFix}}Application {
+    pub fn new(application_id: &str, flags: &gio::ApplicationFlags) -> Self {
+        glib::Object::new(&[("application-id", &application_id), ("flags", flags)])
+            .expect("Failed to create {{PreFix}}Application")
+    }
+
+    fn setup_gactions(&self) {
+        let quit_action = gio::SimpleAction::new("quit", None);
+        quit_action.connect_activate(clone!(@weak self as app => move |_, _| {
+            app.quit();
+        }));
+        self.add_action(&quit_action);
+
+        let about_action = gio::SimpleAction::new("about", None);
+        about_action.connect_activate(clone!(@weak self as app => move |_, _| {
+            app.show_about();
+        }));
+        self.add_action(&about_action);
+    }
+
+    fn show_about(&self) {
+        let window = self.active_window().unwrap();
+        let dialog = gtk::AboutDialogBuilder::new()
+            .transient_for(&window)
+            .modal(true)
+            .program_name("{{name}}")
+            .version(VERSION)
+            .authors(vec!["{{author}}".into()])
+            .build();
+
+        dialog.present();
+    }
+}
diff --git a/src/plugins/meson-templates/resources/src/config-gtk4.rs.in 
b/src/plugins/meson-templates/resources/src/config-gtk4.rs.in
new file mode 100644
index 000000000..1a24858ed
--- /dev/null
+++ b/src/plugins/meson-templates/resources/src/config-gtk4.rs.in
@@ -0,0 +1,4 @@
+pub static VERSION: &str = @VERSION@;
+pub static GETTEXT_PACKAGE: &str = @GETTEXT_PACKAGE@;
+pub static LOCALEDIR: &str = @LOCALEDIR@;
+pub static PKGDATADIR: &str = @PKGDATADIR@;
diff --git a/src/plugins/meson-templates/resources/src/main-gtk4.rs 
b/src/plugins/meson-templates/resources/src/main-gtk4.rs
new file mode 100644
index 000000000..abafbd171
--- /dev/null
+++ b/src/plugins/meson-templates/resources/src/main-gtk4.rs
@@ -0,0 +1,35 @@
+mod application;
+mod config;
+mod window;
+
+use self::application::{{PreFix}}Application;
+use self::window::{{PreFix}}Window;
+
+use config::{GETTEXT_PACKAGE, LOCALEDIR, PKGDATADIR};
+use gettextrs::{bind_textdomain_codeset, bindtextdomain, textdomain};
+use gtk::gio;
+use gtk::prelude::*;
+
+fn main() {
+    // Set up gettext translations
+    bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR).expect("Unable to bind the text domain");
+    bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8")
+        .expect("Unable to set the text domain encoding");
+    textdomain(GETTEXT_PACKAGE).expect("Unable to switch to the text domain");
+
+    // Load resources
+    let resources = gio::Resource::load(PKGDATADIR.to_owned() + "/{{name}}.gresource")
+        .expect("Could not load resources");
+    gio::resources_register(&resources);
+
+    // Create a new GtkApplication. The application manages our main loop,
+    // application windows, integration with the window manager/compositor, and
+    // desktop features such as file opening and single-instance applications.
+    let app = {{PreFix}}Application::new("{{appid}}", &gio::ApplicationFlags::empty());
+
+    // Run the application. This function will block until the application
+    // exits. Upon return, we have our exit code to return to the shell. (This
+    // is the code you see when you do `echo $?` after running a command in a
+    // terminal.
+    std::process::exit(app.run());
+}
diff --git a/src/plugins/meson-templates/resources/src/meson-rs-gtk4.build 
b/src/plugins/meson-templates/resources/src/meson-rs-gtk4.build
new file mode 100644
index 000000000..c3e937bb0
--- /dev/null
+++ b/src/plugins/meson-templates/resources/src/meson-rs-gtk4.build
@@ -0,0 +1,57 @@
+pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
+gnome = import('gnome')
+
+gnome.compile_resources('{{name}}',
+  '{{prefix}}.gresource.xml',
+  gresource_bundle: true,
+  install: true,
+  install_dir: pkgdatadir,
+)
+
+conf = configuration_data()
+conf.set_quoted('VERSION', meson.project_version())
+conf.set_quoted('GETTEXT_PACKAGE', '{{name}}')
+conf.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
+conf.set_quoted('PKGDATADIR', pkgdatadir)
+
+configure_file(
+    input: 'config.rs.in',
+    output: 'config.rs',
+    configuration: conf
+)
+
+# Copy the config.rs output to the source directory.
+run_command(
+  'cp',
+  join_paths(meson.build_root(), 'src', 'config.rs'),
+  join_paths(meson.source_root(), 'src', 'config.rs'),
+  check: true
+)
+
+rust_sources = files(
+  'application.rs',
+  'config.rs',
+  'main.rs',
+  'window.rs',
+)
+
+sources = [cargo_sources, rust_sources]
+
+cargo_script = find_program(join_paths(meson.source_root(), 'build-aux/cargo.sh'))
+cargo_release = custom_target(
+  'cargo-build',
+  build_by_default: true,
+  input: sources,
+  output: meson.project_name(),
+  console: true,
+  install: true,
+  install_dir: get_option('bindir'),
+  command: [
+    cargo_script,
+    meson.build_root(),
+    meson.source_root(),
+    '@OUTPUT@',
+    get_option('buildtype'),
+    meson.project_name(),
+  ]
+)
diff --git a/src/plugins/meson-templates/resources/src/window-gtk4.rs 
b/src/plugins/meson-templates/resources/src/window-gtk4.rs
new file mode 100644
index 000000000..0ef2d37c2
--- /dev/null
+++ b/src/plugins/meson-templates/resources/src/window-gtk4.rs
@@ -0,0 +1,50 @@
+use gtk::prelude::*;
+use gtk::subclass::prelude::*;
+use gtk::{gio, glib, CompositeTemplate};
+
+mod imp {
+    use super::*;
+
+    #[derive(Debug, Default, CompositeTemplate)]
+    #[template(resource = "{{appid_path}}/{{ui_file}}")]
+    pub struct {{PreFix}}Window {
+        // Template widgets
+        #[template_child]
+        pub header_bar: TemplateChild<gtk::HeaderBar>,
+        #[template_child]
+        pub label: TemplateChild<gtk::Label>,
+    }
+
+    #[glib::object_subclass]
+    impl ObjectSubclass for {{PreFix}}Window {
+        const NAME: &'static str = "{{PreFix}}Window";
+        type Type = super::{{PreFix}}Window;
+        type ParentType = gtk::ApplicationWindow;
+
+        fn class_init(klass: &mut Self::Class) {
+            Self::bind_template(klass);
+        }
+
+        fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
+            obj.init_template();
+        }
+    }
+
+    impl ObjectImpl for {{PreFix}}Window {}
+    impl WidgetImpl for {{PreFix}}Window {}
+    impl WindowImpl for {{PreFix}}Window {}
+    impl ApplicationWindowImpl for {{PreFix}}Window {}
+}
+
+glib::wrapper! {
+    pub struct {{PreFix}}Window(ObjectSubclass<imp::{{PreFix}}Window>)
+        @extends gtk::Widget, gtk::Window, gtk::ApplicationWindow,
+        @implements gio::ActionGroup, gio::ActionMap;
+}
+
+impl {{PreFix}}Window {
+    pub fn new<P: glib::IsA<gtk::Application>>(application: &P) -> Self {
+        glib::Object::new(&[("application", application)])
+            .expect("Failed to create {{PreFix}}Window")
+    }
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]