GtkFontDialogButton and Gsettings
The Preference Dialog
If the user clicks on the preference menu, a preference dialog appears.
It has only one button, which is a GtkFontDialogButton widget. You can add more widgets on the dialog but this simple dialog isn’t so bad for the first example program.
If the button is clicked, a GtkFontDialog appears like this.
If the user chooses a font and clicks on the select button, the font is changed.
GtkFontDialogButton and GtkFontDialog are available since GTK version 4.10. They replace GtkFontButton and GtkFontChooserDialog, which are deprecated since 4.10.
Composite Widget
The preference dialog has GtkBox, GtkLabel and GtkFontButton
in it and is defined as a composite widget. The following is the
template UI file for TfePref.
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="TfePref" parent="GtkWindow">
<property name="title">Preferences</property>
<property name="resizable">FALSE</property>
<property name="modal">TRUE</property>
<child>
<object class="GtkBox">
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
<property name="spacing">12</property>
<property name="halign">GTK_ALIGN_CENTER</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<child>
<object class="GtkLabel">
<property name="label">Font:</property>
<property name="xalign">1</property>
</object>
</child>
<child>
<object class="GtkFontDialogButton" id="font_dialog_btn">
<property name="dialog">
<object class="GtkFontDialog"/>
</property>
</object>
</child>
</object>
</child>
</template>
</interface>- Template tag specifies a composite widget. The class
attribute specifies the class name, which is “TfePref”. The
parent attribute is
GtkWindow. Therefore,TfePrefis a child class ofGtkWindow. A parent attribute is optional but it is recommended to write it explicitly. You can make TfePref as a child ofGtkDialog, butGtkDialogis deprecated since version 4.10. - There are three properties, title, resizable and modal.
- TfePref has a child widget GtkBox which is horizontal. The box has two children GtkLabel and GtkFontDialogButton.
The Header File
The file tfepref.h defines types and declares a
public function.
#pragma once
#include <gtk/gtk.h>
#define TFE_TYPE_PREF tfe_pref_get_type ()
G_DECLARE_FINAL_TYPE (TfePref, tfe_pref, TFE, PREF, GtkWindow)
GtkWidget *
tfe_pref_new (void);- 5: Defines the type
TFE_TYPE_PREF, which is a macro replaced bytfe_pref_get_type (). - 6: The macro
G_DECLARE_FINAL_TYPEexpands to:- The function
tfe_pref_get_type ()is declared. - TfePref type is defined as a typedef of
struct _TfePref. - TfePrefClass type is defined as a typedef of
struct {GtkWindowClass *parent;}. - Two functions
TFE_PREF ()andTFE_IS_PREF ()are defined.
- The function
- 8-9:The function
tfe_pref_newis declared. It creates a new TfePref instance.
The C File for the Composite Widget
The following codes are extracted from the file
tfepref.c.
#include <gtk/gtk.h>
#include "tfepref.h"
struct _TfePref
{
GtkWindow parent;
GtkFontDialogButton *font_dialog_btn;
};
G_DEFINE_FINAL_TYPE (TfePref, tfe_pref, GTK_TYPE_WINDOW);
static void
tfe_pref_dispose (GObject *gobject) {
TfePref *pref = TFE_PREF (gobject);
gtk_widget_dispose_template (GTK_WIDGET (pref), TFE_TYPE_PREF);
G_OBJECT_CLASS (tfe_pref_parent_class)->dispose (gobject);
}
static void
tfe_pref_init (TfePref *pref) {
gtk_widget_init_template (GTK_WIDGET (pref));
}
static void
tfe_pref_class_init (TfePrefClass *class) {
G_OBJECT_CLASS (class)->dispose = tfe_pref_dispose;
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class), "/com/github/ToshioCP/tfe/tfepref.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), TfePref, font_dialog_btn);
}
GtkWidget *
tfe_pref_new (void) {
return GTK_WIDGET (g_object_new (TFE_TYPE_PREF, NULL));
}- The structure
_TfePrefhasfont_dialog_btnmember. It points to the GtkFontDialogButton object specified in the XML file “tfepref.ui”. The member namefont_dialog_btnmust be the same as the GtkFontDialogButton id attribute in the XML file. G_DEFINE_FINAL_TYPEmacro expands to:- The declaration of the functions
tfe_pref_initandtfe_pref_class_init. They are defined in the following part of the program. - The definition of the variable
tfe_pref_parent_class. - The definition of the function
tfe_pref_get_type.
- The declaration of the functions
- The function
tfe_pref_class_initinitializes the TfePref class. The functiongtk_widget_class_set_template_from_resourceinitializes the composite widget template from the XML resource. The functiongtk_widget_class_bind_template_childconnects the TfePref structure memberfont_dialog_btnand the GtkFontDialogButton in the XML. The member name and the id attribute value must be the same. - The function
tfe_pref_initinitializes a newly created instance. The functiongtk_widget_init_templatecreates and initializes child widgets. - The function
tfe_pref_disposereleases objects. The functiongtk_widget_dispose_templatereleases child widgets.
GtkFontDialogButton and Pango
If the GtkFontDialogButton button is clicked, the
GtkFontDialog dialog appears. A user can choose a font on the
dialog. If the user clicks on the “select” button, the dialog
disappears. And the font information is given to the
GtkFontDialogButton instance. The font data is retrieved with
the method gtk_font_dialog_button_get_font_desc. It
returns a pointer to the PangoFontDescription structure.
Pango is a text layout engine. The documentation is on the internet.
PangoFontDescription is a C structure and it isn’t allowed to be accessed directly. The document is here. If you want to retrieve the font information, there are several functions.
pango_font_description_to_stringreturns a string like “Jamrul Bold Italic Semi-Expanded 12”.pango_font_description_get_familyreturns a font family like “Jamrul”.pango_font_description_get_weightreturns a PangoWeight constant likePANGO_WEIGHT_BOLD.pango_font_description_get_stylereturns a PangoStyle constant likePANGO_STYLE_ITALIC.pango_font_description_get_stretchreturns a PangoStretch constant likePANGO_STRETCH_SEMI_EXPANDED.pango_font_description_get_sizereturns an integer like12. Its unit is points or pixels (device units). The functionpango_font_description_get_size_is_absolutereturns TRUE if the unit is an absolute device unit. Otherwise the unit is point.
GSettings
We want to maintain the font data after the application quits. There are some ways to implement.
- Make a configuration file. For example, a text file “~/.config/tfe/font_desc.cfg” keeps font information.
- Use GSettings object. The basic idea of GSettings are similar to configuration file. Configuration information data is put into a database file.
GSettings is simple and easy to use but a bit hard to understand the concept. This subsection describes the concept first and then how to program it.
GSettings Schema
GSettings schema describes a set of keys, value types and some other information. GSettings object uses this schema and it writes/reads the value of a key to/from the right place in the database.
- A schema has an id. The id must be unique. We often use the same string as application id, but schema id and application id are different. You can use different name from application id. Schema id is a string delimited by periods. For example, “com.github.ToshioCP.tfe” is a correct schema id.
- A schema usually has a path. The path is a location in the
database. Each key is stored under the path. For example, if a
key
font-descis defined with a path/com/github/ToshioCP/tfe/, the key’s location in the database is/com/github/ToshioCP/tfe/font-desc. A path is a string begins with and ends with a slash (/). And it is delimited by slashes. - GSettings save information as key-value style. A key is a
string that begins with a lower case character followed by lower
case letters, digits or dashes (
-) and ends with a lower case letter or digit. No consecutive dashes are allowed. Values can be any type. GSettings stores values as GVariant type, which can be, for example, integer, double, boolean, string or complex types like an array. The type of values needs to be defined in the schema. - A default value needs to be set for each key.
- A summary and description can be set for each key optionally.
Schemas are described in an XML format. For example,
<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
<schema path="/com/github/ToshioCP/tfe/" id="com.github.ToshioCP.tfe">
<key name="font-desc" type="s">
<default>'Monospace 12'</default>
<summary>Font</summary>
<description>A font to be used for textview.</description>
</key>
</schema>
</schemalist>- 4: The type attribute is “s”. It is GVariant type string.
For GVariant type string, see GLib
API Reference – GVariant Type Strings. Other common types
are:
- “b”: gboolean
- “i”: gint32.
- “d”: double.
Further information is in:
- GLib API Reference – GVariant Format Strings
- GLib API Reference – GVariant Text Format
- GLib API Reference – GVariant
- GLib API Reference – VariantType
Gsettings Command
First, let’s try gsettings application. It is a
configuration tool for GSettings.
$ gsettings help
Usage:
gsettings --version
gsettings [--schemadir SCHEMADIR] COMMAND [ARGS?]
Commands:
help Show this information
list-schemas List installed schemas
list-relocatable-schemas List relocatable schemas
list-keys List keys in a schema
list-children List children of a schema
list-recursively List keys and values, recursively
range Queries the range of a key
describe Queries the description of a key
get Get the value of a key
set Set the value of a key
reset Reset the value of a key
reset-recursively Reset all values in a given schema
writable Check if a key is writable
monitor Watch for changes
Use "gsettings help COMMAND" to get detailed help.
List schemas.
$ gsettings list-schemas
org.gnome.rhythmbox.podcast
ca.desrt.dconf-editor.Demo.Empty
org.gnome.gedit.preferences.ui
org.gnome.evolution-data-server.calendar
org.gnome.rhythmbox.plugins.generic-player
... ...
Each line is an id of a schema. Each schema has a key-value
configuration data. You can see them with list-recursively
command. Let’s look at the keys and values of
org.gnome.calculator schema.
$ gsettings list-recursively org.gnome.calculator
org.gnome.calculator accuracy 9
org.gnome.calculator angle-units 'degrees'
org.gnome.calculator base 10
org.gnome.calculator button-mode 'basic'
org.gnome.calculator number-format 'automatic'
org.gnome.calculator precision 2000
org.gnome.calculator refresh-interval 604800
org.gnome.calculator show-thousands false
org.gnome.calculator show-zeroes false
org.gnome.calculator source-currency ''
org.gnome.calculator source-units 'degree'
org.gnome.calculator target-currency ''
org.gnome.calculator target-units 'radian'
org.gnome.calculator window-position (-1, -1)
org.gnome.calculator word-size 64
This schema is used by GNOME Calculator. Run the calculator and change the mode, then check the schema again.
$ gnome-calculator
Change the mode to advanced and quit.
Run gsettings and check the value of
button-mode.
$ gsettings list-recursively org.gnome.calculator
... ...
org.gnome.calculator button-mode 'advanced'
... ...
Now we know that GNOME Calculator used gsettings and it has
set button-mode key to “advanced”. The value
remains even the calculator quits. So when the calculator runs
again, it will appear as an advanced mode.
Glib-compile-schemas Utility
GSettings schemas are specified with an XML format. The XML
schema files must have the filename extension
.gschema.xml. The following is the XML schema file
for the application tfe.
<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
<schema path="/com/github/ToshioCP/tfe/" id="com.github.ToshioCP.tfe">
<key name="font-desc" type="s">
<default>'Monospace 12'</default>
<summary>Font</summary>
<description>A font to be used for textview.</description>
</key>
</schema>
</schemalist>The filename is “com.github.ToshioCP.tfe.gschema.xml”. Schema XML filenames are usually the schema id followed by “.gschema.xml” suffix. You can use different name from schema id, but it is not recommended.
- 2: The top level element is
<schemalist>. - 3: schema tag has
pathandidattributes. A path determines where the settings are stored in the conceptual global tree of settings. An id identifies the schema. - 4: Key tag has two attributes. Name is the name of the key. Type is the type of the value of the key and it is a GVariant Format String.
- 5: default value of the key
font-descisMonospace 12. - 6: Summary and description elements describe the key. They are optional, but it is recommended to add them in the XML file.
The XML file is compiled by glib-compile-schemas. When
compiling, glib-compile-schemas compiles all the
XML files which have “.gschema.xml” file extension in the
directory given as an argument. It converts the XML file into a
binary file gschemas.compiled. Suppose the XML file
above is under tfe6 directory.
$ glib-compile-schemas tfe6
Then, gschemas.compiled is generated under
tfe6. When you test your application, set
GSETTINGS_SCHEMA_DIR environment variable so that
GSettings objet can find gschemas.compiled.
$ GSETTINGS_SCHEMA_DIR=(the directory gschemas.compiled is located):$GSETTINGS_SCHEMA_DIR (your application name)
GSettings object looks for this file by the following process.
- It searches
glib-2.0/schemassubdirectories of all the directories specified in the environment variableXDG_DATA_DIRS. Common directores are/usr/share/glib-2.0/schemasand/usr/local/share/glib-2.0/schemas. - If
$HOME/.local/share/glib-2.0/schemasexists, it is also searched. - If
GSETTINGS_SCHEMA_DIRenvironment variable is defined, it searches all the directories specified in the variable.GSETTINGS_SCHEMA_DIRcan specify multiple directories delimited by colon (:).
The directories above includes more than one
.gschema.xml file. Therefore, when you install your
application, follow the instruction below to install your
schemas.
- Make
.gschema.xmlfile. - Copy it to one of the directories above. For example,
$HOME/.local/share/glib-2.0/schemas. - Run
glib-compile-schemason the directory. It compiles all the schema files in the directory and creates or updates the database filegschemas.compiled.
GSettings Object and Binding
Now, we go on to the next topic, how to program GSettings.
You need to compile your schema file in advance.
Suppose id, key, class name and a property name are:
- GSettings id: com.github.ToshioCP.sample
- GSettings key: sample_key
- The class name: Sample
- The property to bind: sample_property
The example below uses g_settings_bind. If you
use it, GSettings key and instance property must have the same
the type. In the example, it is assumed that the type of
“sample_key” and “sample_property” are the same.
GSettings *settings;
Sample *sample_object;
settings = g_settings_new ("com.github.ToshioCP.sample");
sample_object = sample_new ();
g_settings_bind (settings, "sample_key", sample_object, "sample_property", G_SETTINGS_BIND_DEFAULT);The function g_settings_bind binds the GSettings
value and the property of the instance. If the property value is
changed, the GSettings value is also changed, and vice versa.
The two values are always the same.
The function g_settings_bind is simple and easy
but it isn’t always possible. The type of GSettings are
restricted to the type GVariant has. Some property types are out
of GVariant. For example, GtkFontDialogButton has “font-desc”
property and its type is PangoFontDescription.
PangoFontDescription is a C structure and it is wrapped in a
boxed type GValue to store in the property. GVariant doesn’t
support boxed type.
In that case, another function
g_settings_bind_with_mapping is used. It binds
GSettings GVariant value and object property via GValue with
mapping functions. See GIO
documentation for further details.
void
g_settings_bind_with_mapping (
GSettings* settings,
const gchar* key,
GObject* object,
const gchar* property,
GSettingsBindFlags flags, // G_SETTINGS_BIND_DEFAULT is commonly used
GSettingsBindGetMapping get_mapping, // GSettings => property, See the example below
GSettingsBindSetMapping set_mapping, // property => GSettings, See the example below
gpointer user_data, // NULL if unnecessary
GDestroyNotify destroy //NULL if unnecessary
)The mapping functions are defined like these:
gboolean
(* GSettingsBindGetMapping) (
GValue* value,
GVariant* variant,
gpointer user_data
)
GVariant*
(* GSettingsBindSetMapping) (
const GValue* value,
const GVariantType* expected_type,
gpointer user_data
)The following codes are extracted from
tfepref.c.
static gboolean // GSettings => property
get_mapping (GValue *value, GVariant *variant, gpointer user_data) {
const char *s = g_variant_get_string (variant, NULL);
PangoFontDescription *font_desc = pango_font_description_from_string (s);
g_value_take_boxed (value, font_desc);
return TRUE;
}
static GVariant * // Property => GSettings
set_mapping (const GValue *value, const GVariantType *expected_type, gpointer user_data) {
char *font_desc_string = pango_font_description_to_string (g_value_get_boxed (value));
return g_variant_new_take_string (font_desc_string);
}
static void
tfe_pref_init (TfePref *pref) {
gtk_widget_init_template (GTK_WIDGET (pref));
pref->settings = g_settings_new ("com.github.ToshioCP.tfe");
g_settings_bind_with_mapping (pref->settings, "font-desc", pref->font_dialog_btn, "font-desc", G_SETTINGS_BIND_DEFAULT,
get_mapping, set_mapping, NULL, NULL);
}- 15-21: This function
tfe_pref_initinitializes the new TfePref instance. - 18: Creates a new GSettings instance. The id is “com.github.ToshioCP.tfe”.
- 19-20: Binds the GSettings “font-desc” and the
GtkFontDialogButton property “font-desc”. The mapping functions
are
get_mappingandset_mapping. - 1-7: The mapping function from GSettings to the property.
The first argument
valueis a GValue to be stored in the property. The second argumentvariantis a GVariant structure that comes from the GSettings value. - 3: Retrieves a string from the GVariant structure.
- 4: Build a PangoFontDescription structure from the string
and assigns its address to
font_desc. - 5: Puts
font_descinto the GValuevalue. The ownership offont_descmoves tovalue. - 6: Returns TRUE that means the mapping succeeds.
- 9-13: The mapping function from the property to GSettings.
The first argument
valueholds the property data. The second argumentexpected_typeis the type of GVariant that the GSettings value has. It isn’t used in this function. - 11: Gets the PangoFontDescription structure from
valueand converts it to string. - 12: The string is inserted to a GVariant structure. The
ownership of the string
font_desc_stringmoves to the returned value.
C File
The following is the full codes of tfepref.c
#include <gtk/gtk.h>
#include "tfepref.h"
struct _TfePref
{
GtkWindow parent;
GSettings *settings;
GtkFontDialogButton *font_dialog_btn;
};
G_DEFINE_FINAL_TYPE (TfePref, tfe_pref, GTK_TYPE_WINDOW);
static void
tfe_pref_dispose (GObject *gobject) {
TfePref *pref = TFE_PREF (gobject);
/* GSetting bindings are automatically removed when the object is finalized, so it isn't necessary to unbind them explicitly.*/
g_clear_object (&pref->settings);
gtk_widget_dispose_template (GTK_WIDGET (pref), TFE_TYPE_PREF);
G_OBJECT_CLASS (tfe_pref_parent_class)->dispose (gobject);
}
/* ---------- get_mapping/set_mapping ---------- */
static gboolean // GSettings => property
get_mapping (GValue *value, GVariant *variant, gpointer user_data) {
const char *s = g_variant_get_string (variant, NULL);
PangoFontDescription *font_desc = pango_font_description_from_string (s);
g_value_take_boxed (value, font_desc);
return TRUE;
}
static GVariant * // Property => GSettings
set_mapping (const GValue *value, const GVariantType *expected_type, gpointer user_data) {
char *font_desc_string = pango_font_description_to_string (g_value_get_boxed (value));
return g_variant_new_take_string (font_desc_string);
}
static void
tfe_pref_init (TfePref *pref) {
gtk_widget_init_template (GTK_WIDGET (pref));
pref->settings = g_settings_new ("com.github.ToshioCP.tfe");
g_settings_bind_with_mapping (pref->settings, "font-desc", pref->font_dialog_btn, "font-desc", G_SETTINGS_BIND_DEFAULT,
get_mapping, set_mapping, NULL, NULL);
}
static void
tfe_pref_class_init (TfePrefClass *class) {
G_OBJECT_CLASS (class)->dispose = tfe_pref_dispose;
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class), "/com/github/ToshioCP/tfe/tfepref.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), TfePref, font_dialog_btn);
}
GtkWidget *
tfe_pref_new (void) {
return GTK_WIDGET (g_object_new (TFE_TYPE_PREF, NULL));
}Test Program
There’s a test program located at src/tfe6/test
directory.
#include <gtk/gtk.h>
#include "../tfepref.h"
GSettings *settings;
// "changed::font-desc" signal handler
static void
changed_font_desc_cb (GSettings *settings, char *key, gpointer user_data) {
char *s;
s = g_settings_get_string (settings, key);
g_print ("%s\n", s);
g_free (s);
}
static void
app_shutdown (GApplication *application) {
g_object_unref (settings);
}
static void
app_activate (GApplication *application) {
GtkWidget *pref = tfe_pref_new ();
gtk_window_set_application (GTK_WINDOW (pref), GTK_APPLICATION (application));
gtk_window_present (GTK_WINDOW (pref));
}
static void
app_startup (GApplication *application) {
settings = g_settings_new ("com.github.ToshioCP.tfe");
g_signal_connect (settings, "changed::font-desc", G_CALLBACK (changed_font_desc_cb), NULL);
g_print ("%s\n", "Change the font with the font button. Then the new font will be printed out.\n");
}
#define APPLICATION_ID "com.github.ToshioCP.test_tfe_pref"
int
main (int argc, char **argv) {
GtkApplication *app;
int stat;
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
g_signal_connect (app, "shutdown", G_CALLBACK (app_shutdown), NULL);
stat = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return stat;
}This program sets its active window to TfePref instance, which is a child object of GtkWindow.
It sets the “changed::font-desc” signal handler in the startup function. The process from the user’s font selection to the handler is:
- The user clicked on the GtkFontDialogButton and GtkFontDialog appears.
- He/she selects a new font.
- The “font-desc” property of the GtkFontDialogButton instance is changed.
- The value of “font-desc” key on the GSettings database is changed since it is bound to the property.
- The “changed::font-desc” signal on the GSettings instance is emitted.
- The handler is called.
The program building is divided into four steps.
- Compile the schema file
- Compile the XML file to a resource (C source file)
- Compile the C files
- Run the executable file
Commands are shown in the next four sub-subsections. You don’t need to try them. The final sub-subsection shows the meson-ninja way, which is the easiest.
Compile the Schema File
$ cd src/tef6/test
$ cp ../com.github.ToshioCP.tfe.gschema.xml com.github.ToshioCP.tfe.gschema.xml
$ glib-compile-schemas .
Be careful. The commands glib-compile-schemas
has an argument “.”, which means the current directory. This
results in creating gschemas.compiled file.
Compile the XML File
$ glib-compile-resources --sourcedir=.. --generate-source --target=resource.c ../tfe.gresource.xml
Compile the C File
$ gcc `pkg-config --cflags gtk4` test_pref.c ../tfepref.c resource.c `pkg-config --libs gtk4`
Run the Executable File
$ GSETTINGS_SCHEMA_DIR=. ./a.out
Jamrul Italic Semi-Expanded 12 # <= select Jamrul Italic 12
Monospace 12 #<= select Monospace Regular 12
Meson-Ninja Way
Meson wraps up the commands above. Create the following text
and save it to meson.build.
Note: Gtk4-tutorial repository has meson.build file that defines several tests. So you can try it instead of the following text.
project('tfe_pref_test', 'c')
gtkdep = dependency('gtk4')
gnome=import('gnome')
resources = gnome.compile_resources('resources','../tfe.gresource.xml', source_dir: '..')
gnome.compile_schemas(build_by_default: true, depend_files: 'com.github.ToshioCP.tfe.gschema.xml')
executable('test_pref', ['test_pref.c', '../tfepref.c'], resources, dependencies: gtkdep, export_dynamic: true, install: false)
- Project name is ‘tfe_pref_test’ and it is written in C language.
- It depends on GTK4 library.
- It uses GNOME module. Modules are prepared by Meson.
- GNOME module has
compile_resourcesmethod. When you call this method, you need the prefix “gnome.”.- The target filename is resources.
- The definition XML file is ‘../tfe.gresource.xml’.
- The source dir is ‘..’. All the UI files are located there.
- GNOME module has
compile_schemasmethod. It compiles the schema file ‘com.github.ToshioCP.tfe.gschema.xml’. You need to copy ‘../com.github.ToshioCP.tfe.gschema.xml’ to the current directory in advance. - It creates an executable file ‘test_pref’. The source files
are ‘test_pref.c’, ‘../tfepref.c’ and
resources, which is made bygnome.compile_resources. It depends ongtkdep, which is GTK4 library. The symbols are exported and no installation support.
Type like this to build and test the program.
$ cd src/tef6/test
$ cp ../com.github.ToshioCP.tfe.gschema.xml com.github.ToshioCP.tfe.gschema.xml
$ meson setup _build
$ ninja -C _build
$ GSETTINGS_SCHEMA_DIR=_build _build/test_pref
A window appears and you can choose a font via GtkFontDialog. If you select a new font, the font string is output through the standard output.