Skip to content

Commit

Permalink
gtk4-macros: Add blueprint support (#1238)
Browse files Browse the repository at this point in the history
* blueprint: Add blueprint support
  • Loading branch information
yuraiz authored Jan 16, 2023
1 parent c9b16a4 commit 9c9a611
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 5 deletions.
20 changes: 18 additions & 2 deletions gtk4-macros/src/attribute_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,23 @@ pub struct Template {
pub enum TemplateSource {
File(String),
Resource(String),
String(String),
Xml(String),
Blueprint(String),
}

impl TemplateSource {
fn from_string_source(source: String) -> Result<Self> {
for c in source.chars() {
if c.is_ascii_alphabetic() {
// blueprint code starts with some alphabetic letters
return Ok(Self::Blueprint(source));
} else if c == '<' {
// xml tags starts with '<' symbol
return Ok(Self::Xml(source));
}
}
bail!("Unknown lanuage")
}
}

pub fn parse_template_source(input: &DeriveInput) -> Result<Template> {
Expand Down Expand Up @@ -68,7 +84,7 @@ pub fn parse_template_source(input: &DeriveInput) -> Result<Template> {
let source = match ident.as_ref() {
"file" => TemplateSource::File(v),
"resource" => TemplateSource::Resource(v),
"string" => TemplateSource::String(v),
"string" => TemplateSource::from_string_source(v)?,
s => bail!("Unknown enum meta {}", s),
};
Ok(Template {
Expand Down
28 changes: 28 additions & 0 deletions gtk4-macros/src/blueprint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Take a look at the license at the top of the repository in the LICENSE file.

use anyhow::{bail, Result};
use std::io::{Read, Write};
use std::process::{Command, Stdio};

pub(crate) fn compile_blueprint(blueprint: &[u8]) -> Result<String> {
let mut compiler = Command::new("blueprint-compiler")
.args(["compile", "-"])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.unwrap_or_else(|_| panic!("blueprint-compiler not found"));

let mut stdin = compiler.stdin.take().unwrap();
stdin.write_all(b"using Gtk 4.0;\n")?;
stdin.write_all(blueprint)?;
drop(stdin);

let mut buf = String::new();
compiler.stdout.unwrap().read_to_string(&mut buf)?;

if !buf.starts_with('<') {
bail!(buf);
}

Ok(buf)
}
17 changes: 14 additions & 3 deletions gtk4-macros/src/composite_template_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use syn::Data;
use std::collections::HashMap;
use std::string::ToString;

use crate::{attribute_parser::*, util::*};
use crate::{attribute_parser::*, blueprint::*, util::*};

fn gen_set_template(source: &TemplateSource, crate_ident: &proc_macro2::Ident) -> TokenStream {
match source {
Expand All @@ -27,20 +27,31 @@ fn gen_set_template(source: &TemplateSource, crate_ident: &proc_macro2::Ident) -
&#resource,
);
},
TemplateSource::String(template) => quote! {
TemplateSource::Xml(template) => quote! {
#crate_ident::subclass::widget::WidgetClassSubclassExt::set_template_static(
klass,
#template.as_bytes(),
);
},
TemplateSource::Blueprint(blueprint) => {
let template =
compile_blueprint(blueprint.as_bytes()).expect("can't compile blueprint");

quote! {
#crate_ident::subclass::widget::WidgetClassSubclassExt::set_template_static(
klass,
#template.as_bytes(),
);
}
}
}
}

#[cfg(feature = "xml_validation")]
fn check_template_fields(source: &TemplateSource, fields: &[AttributedField]) {
#[allow(unused_assignments)]
let xml = match source {
TemplateSource::String(template) => template,
TemplateSource::Xml(template) => template,
_ => return,
};

Expand Down
1 change: 1 addition & 0 deletions gtk4-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//! The crate aims to provide useful macros to use with the GTK 4 Rust bindings.

mod attribute_parser;
mod blueprint;
mod composite_template_derive;
mod template_callbacks_attribute;
mod util;
Expand Down
57 changes: 57 additions & 0 deletions gtk4-macros/tests/templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,60 @@ glib::wrapper! {
fn template_child_without_attribute() {
let _: MyWidget3 = glib::Object::new(&[]);
}

#[cfg(target_os = "linux")]
mod imp4 {
use super::*;

#[derive(Debug, Default, CompositeTemplate)]
#[template(string = "
template MyWidget4 : Widget {
Label label {
label: 'foobar';
}
Label my_label2 {
label: 'foobaz';
}
}
")]
pub struct MyWidget4 {
#[template_child]
pub label: TemplateChild<gtk::Label>,
#[template_child(id = "my_label2")]
pub label2: gtk::TemplateChild<gtk::Label>,
}

#[glib::object_subclass]
impl ObjectSubclass for MyWidget4 {
const NAME: &'static str = "MyWidget4";
type Type = super::MyWidget4;
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 MyWidget4 {
fn dispose(&self) {
while let Some(child) = self.obj().first_child() {
child.unparent();
}
}
}
impl WidgetImpl for MyWidget4 {}
}

#[cfg(target_os = "linux")]
glib::wrapper! {
pub struct MyWidget4(ObjectSubclass<imp4::MyWidget4>) @extends gtk::Widget;
}

#[gtk::test]
#[cfg(target_os = "linux")]
fn blueprint_template() {
let _: MyWidget4 = glib::Object::new(&[]);
}

0 comments on commit 9c9a611

Please sign in to comment.