I'm trying to use GtkTemplate, but it is really annoyingly not working. I have defined .ui file resources, properly calling it & etc.
Here is my files:
meson.build:
# project name and programming language
project('myproject', 'vala', 'c', version: '1.0.0')
# add resources to the executeable
gnome = import('gnome')
gresources = gnome.compile_resources(
meson.project_name() + '.resources',
'data/gresources.xml',
c_name: 'resources'
)
executable(
meson.project_name(),
'src/OpenFileWindow.vala',
'src/Main.vala',
gresources,
dependencies: [
dependency('gtk+-3.0'),
dependency('gio-2.0'),
],
install: true
)
src/OpenFileWindow.vala:
using Gtk;
namespace MyProject {
[GtkTemplate (ui="/ui/OpenFileWindow.ui")]
public class OpenFileWindow : Window {
[GtkChild]
Button btn_browse;
public OpenFileWindow() {
}
[GtkCallback]
private void btn_browse_clicked(Button btn) {
stdout.printf("CLICKED");
}
}
}
ui/OpenFileWindow.ui:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<template class="OpenFileWindow" parent="GtkWindow">
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="btn_browse">
<property name="label">gtk-open</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="image_position">top</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="myproject_openfilewindow_btn_browse_clicked" swapped="no"/>
</object>
</child>
</template>
</interface>
data/gresources.xml:
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/">
<file preprocess="xml-stripblanks">ui/OpenFileWindow.ui</file>
</gresource>
</gresources>
And when I builded with meson & ninja, it gives this error:
valac -C --debug --debug --pkg gio-2.0 --pkg gtk+-3.0 --color=always --directory myproject@exe --basedir ../ --gresources=../data/gresources.xml ../src/OpenFileWindow.vala ../src/Main.vala
../src/OpenFileWindow.vala:6.5-6.40: error: UI resource not found: `/ui/OpenFileWindow.ui'. Please make sure to specify the proper GResources xml files with --gresources and alternative search locations with --gresourcesdir.
public class OpenFileWindow : Window {
What is the problem, I really can't see it... Thanks!
GResource is a read-only file system for files that have been embedded in to a compiled binary. In a Vala GUI project this can be used to store images, icons, etc. in the binary.
GtkBuilder UI definition files can also be embedded and Vala has additional support for this with the [GtkTemplate]
, [GtkChild]
and [GtkCallback]
attributes. Part of this support includes type checking at compile time. The check needs to get the source file and work out the filename for the GResource in-memory file system and this is where the project is failing. Anyone wanting to improve this should patch codegen/valagtkmodule.vala in the Vala compiler. For now, however, to get your project working you will need to use a flatter file structure for the resources.
Firstly move data/gresource.xml
to the ui/
directory. Then change the prefix
to /ui
. This means the in-memory file system will use a name that matches the GtkTemplate
attribute you use in the Vala code. Also remove the ui/
from the filename to give a flat directory structure:
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/ui/">
<file preprocess="xml-stripblanks">OpenFileWindow.ui</file>
</gresource>
</gresources>
You also need to modify the definition of gresources
in the meson.build
file:
gresources = gnome.compile_resources(
meson.project_name() + '.resources',
'ui/gresources.xml',
source_dir: ['ui']
)
This uses source_dir
to keep the references working in the flattened directory structure.
You should now no longer get the error message. Take a look at Geary as an example project that makes use of a large number of GtkBuilder UI files. That project has the GResource file in the same directory as the other files.
Your project will still not compile because the Vala compiler has recognised there is no signal for the [GtkCallback]
. This is a name resolution problem and you only need to change one line in the OpenFileWindow.ui
file from:
<signal name="clicked" handler="myproject_openfilewindow_btn_browse_clicked" swapped="no"/>
to
<signal name="clicked" handler="btn_browse_clicked" swapped="no"/>
For the Vala compiler to type check the GtkBuilder UI definition files the gresource.xml only needs to be in a common ancestor directory. This makes a resource directory structure like this possible:
resources/
├── components/
│ └── zoom-bar.ui
├── icons/
│ └── project.svg
├── layouts/
│ └── main-window.ui
├── themes/
│ ├── dark.css
│ └── light.css
└── filelist.gresource.xml
The filelist.gresource.xml
file needs a prefix
of /
, but the sub-directories copy across from the source files to the in-memory files:
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/">
<file preprocess="xml-stripblanks" compressed="true">layouts/main-window.ui</file>
<file preprocess="xml-stripblanks" compressed="true">components/zoom-bar.ui</file>
</gresource>
</gresources>
This can then be accessed in Vala with:
[GtkTemplate (ui="/layouts/main-window.ui")]
The source_dir
argument for gnome.compile_resources()
in meson.build
still needs to be set:
gresources = gnome.compile_resources(
'project-resources',
'resources/filelist.gresource.xml',
source_dir: ['resources']
)