Gtk4-tutorial/docs/sec21.html

864 lines
68 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
<title>GTK 4 tutorial</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre{overflow: visible;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::after
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
div.sourceCode { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
pre:not(.sourceCode) { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
table {margin-left: auto; margin-right: auto; border-collapse: collapse; border: 1px solid;}
th {padding: 2px 6px; border: 1px solid; background-color: ghostwhite;}
td {padding: 2px 6px; border: 1px solid;}
img {display: block; margin-left: auto; margin-right: auto;}
figcaption {text-align: center;}
</style>
</head>
<body style="padding-top: 70px;">
<div class="container">
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
<div class="container-fluid">
<span class="navbar-brand">Gtk4 tutorial</span>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="sec20.html">Prev: section20</a>
</li>
<li class="nav-item">
<a class="nav-link" href="sec22.html">Next: section22</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="row justify-content-center">
<div class="col-xl-10 col-xxl-9">
<h1 id="gtkfontdialogbutton-and-gsettings">GtkFontDialogButton and
Gsettings</h1>
<h2 id="the-preference-dialog">The preference dialog</h2>
<p>If the user clicks on the preference menu, a preference dialog
appears.</p>
<figure>
<img src="image/pref_dialog.png" alt="Preference dialog" />
<figcaption aria-hidden="true">Preference dialog</figcaption>
</figure>
<p>It has only one button, which is a GtkFontDialogButton widget. You
can add more widgets on the dialog but this simple dialog isnt so bad
for the first example program.</p>
<p>If the button is clicked, a FontDialog appears like this.</p>
<figure>
<img src="image/fontdialog.png" alt="Font dialog" />
<figcaption aria-hidden="true">Font dialog</figcaption>
</figure>
<p>If the user chooses a font and clicks on the select button, the font
is changed.</p>
<p>GtkFontDialogButton and GtkFontDialog are available since GTK version
4.10. They replace GtkFontButton and GtkFontChooserDialog, which are
deprecated since 4.10.</p>
<h2 id="a-composite-widget">A composite widget</h2>
<p>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.</p>
2023-01-03 07:30:06 +01:00
<div class="sourceCode" id="cb1"><pre
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb1-1"><a href="#cb1-1"></a><span class="fu">&lt;?xml</span><span class="ot"> version=</span><span class="st">&quot;1.0&quot;</span><span class="ot"> encoding=</span><span class="st">&quot;UTF-8&quot;</span><span class="fu">?&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2"></a>&lt;<span class="kw">interface</span>&gt;</span>
<span id="cb1-3"><a href="#cb1-3"></a> &lt;<span class="kw">template</span><span class="ot"> class=</span><span class="st">&quot;TfePref&quot;</span><span class="ot"> parent=</span><span class="st">&quot;GtkWindow&quot;</span>&gt;</span>
2023-01-03 07:30:06 +01:00
<span id="cb1-4"><a href="#cb1-4"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;title&quot;</span>&gt;Preferences&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-5"><a href="#cb1-5"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;resizable&quot;</span>&gt;FALSE&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-6"><a href="#cb1-6"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;modal&quot;</span>&gt;TRUE&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-7"><a href="#cb1-7"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb1-8"><a href="#cb1-8"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkBox&quot;</span>&gt;</span>
<span id="cb1-9"><a href="#cb1-9"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;orientation&quot;</span>&gt;GTK_ORIENTATION_HORIZONTAL&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-10"><a href="#cb1-10"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;spacing&quot;</span>&gt;12&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-11"><a href="#cb1-11"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;halign&quot;</span>&gt;GTK_ALIGN_CENTER&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-12"><a href="#cb1-12"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;margin-start&quot;</span>&gt;12&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-13"><a href="#cb1-13"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;margin-end&quot;</span>&gt;12&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-14"><a href="#cb1-14"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;margin-top&quot;</span>&gt;12&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-15"><a href="#cb1-15"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;margin-bottom&quot;</span>&gt;12&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-16"><a href="#cb1-16"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb1-17"><a href="#cb1-17"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span>&gt;</span>
<span id="cb1-18"><a href="#cb1-18"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;Font:&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-19"><a href="#cb1-19"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;xalign&quot;</span>&gt;1&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-20"><a href="#cb1-20"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-21"><a href="#cb1-21"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb1-22"><a href="#cb1-22"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb1-23"><a href="#cb1-23"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkFontDialogButton&quot;</span><span class="ot"> id=</span><span class="st">&quot;font_dialog_btn&quot;</span>&gt;</span>
<span id="cb1-24"><a href="#cb1-24"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;dialog&quot;</span>&gt;</span>
<span id="cb1-25"><a href="#cb1-25"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkFontDialog&quot;</span>/&gt;</span>
<span id="cb1-26"><a href="#cb1-26"></a> &lt;/<span class="kw">property</span>&gt;</span>
2023-01-03 07:30:06 +01:00
<span id="cb1-27"><a href="#cb1-27"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-28"><a href="#cb1-28"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb1-29"><a href="#cb1-29"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-30"><a href="#cb1-30"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb1-31"><a href="#cb1-31"></a> &lt;/<span class="kw">template</span>&gt;</span>
<span id="cb1-32"><a href="#cb1-32"></a>&lt;/<span class="kw">interface</span>&gt;</span></code></pre></div>
<ul>
<li>Template tag specifies a composite widget. The class attribute
specifies the class name, which is “TfePref”. The parent attribute is
<code>GtkWindow</code>. Therefore. <code>TfePref</code> is a child class
of <code>GtkWindow</code>. A parent attribute is optional but it is
recommended to write it explicitly. You can make TfePref as a child of
<code>GtkDialog</code>, but <code>GtkDialog</code> is deprecated since
version 4.10.</li>
<li>There are three properties, title, resizable and modal.</li>
<li>TfePref has a child widget GtkBox which is horizontal. The box has
two children GtkLabel and GtkFontDialogButton.</li>
</ul>
<h2 id="the-header-file">The header file</h2>
<p>The file <code>tfepref.h</code> defines types and declares a public
function.</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1"></a><span class="pp">#pragma once</span></span>
<span id="cb2-2"><a href="#cb2-2"></a></span>
<span id="cb2-3"><a href="#cb2-3"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb2-4"><a href="#cb2-4"></a></span>
<span id="cb2-5"><a href="#cb2-5"></a><span class="pp">#define TFE_TYPE_PREF tfe_pref_get_type ()</span></span>
<span id="cb2-6"><a href="#cb2-6"></a>G_DECLARE_FINAL_TYPE <span class="op">(</span>TfePref<span class="op">,</span> tfe_pref<span class="op">,</span> TFE<span class="op">,</span> PREF<span class="op">,</span> GtkWindow<span class="op">)</span></span>
<span id="cb2-7"><a href="#cb2-7"></a></span>
<span id="cb2-8"><a href="#cb2-8"></a>GtkWidget <span class="op">*</span></span>
<span id="cb2-9"><a href="#cb2-9"></a>tfe_pref_new <span class="op">(</span><span class="dt">void</span><span class="op">);</span></span></code></pre></div>
2023-01-03 07:30:06 +01:00
<ul>
<li>5: Defines the type <code>TFE_TYPE_PREF</code>, which is a macro
2023-01-03 07:30:06 +01:00
replaced by <code>tfe_pref_get_type ()</code>.</li>
<li>6: The macro <code>G_DECLAER_FINAL_TYPE</code> expands to:
2023-01-03 07:30:06 +01:00
<ul>
<li>The function <code>tfe_pref_get_type ()</code> is declared.</li>
<li>TfePrep type is defined as a typedef of
<code>struct _TfePrep</code>.</li>
<li>TfePrepClass type is defined as a typedef of
<code>struct {GtkWindowClass *parent;}</code>.</li>
2023-01-03 07:30:06 +01:00
<li>Two functions <code>TFE_PREF ()</code> and
<code>TFE_IS_PREF ()</code> is defined.</li>
</ul></li>
<li>8-9:The function <code>tfe_pref_new</code> is declared. It creates a
new TfePref instance.</li>
2023-01-03 07:30:06 +01:00
</ul>
<h2 id="the-c-file-for-composite-widget">The C file for composite
widget</h2>
<p>The following codes are extracted from the file
<code>tfepref.c</code>.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&quot;tfepref.h&quot;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> _TfePref</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a> GtkWindow parent<span class="op">;</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> GtkFontDialogButton <span class="op">*</span>font_dialog_btn<span class="op">;</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>G_DEFINE_FINAL_TYPE <span class="op">(</span>TfePref<span class="op">,</span> tfe_pref<span class="op">,</span> GTK_TYPE_WINDOW<span class="op">);</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>tfe_pref_dispose <span class="op">(</span>GObject <span class="op">*</span>gobject<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a> TfePref <span class="op">*</span>pref <span class="op">=</span> TFE_PREF <span class="op">(</span>gobject<span class="op">);</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a> gtk_widget_dispose_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>pref<span class="op">),</span> TFE_TYPE_PREF<span class="op">);</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a> G_OBJECT_CLASS <span class="op">(</span>tfe_pref_parent_class<span class="op">)-&gt;</span>dispose <span class="op">(</span>gobject<span class="op">);</span></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a>tfe_pref_init <span class="op">(</span>TfePref <span class="op">*</span>pref<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a> gtk_widget_init_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>pref<span class="op">));</span></span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a>tfe_pref_class_init <span class="op">(</span>TfePrefClass <span class="op">*</span>class<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a> G_OBJECT_CLASS <span class="op">(</span>class<span class="op">)-&gt;</span>dispose <span class="op">=</span> tfe_pref_dispose<span class="op">;</span></span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a> gtk_widget_class_set_template_from_resource <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> <span class="st">&quot;/com/github/ToshioCP/tfe/tfepref.ui&quot;</span><span class="op">);</span></span>
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true" tabindex="-1"></a> gtk_widget_class_bind_template_child <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> TfePref<span class="op">,</span> font_dialog_btn<span class="op">);</span></span>
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb3-30"><a href="#cb3-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-31"><a href="#cb3-31" aria-hidden="true" tabindex="-1"></a>GtkWidget <span class="op">*</span></span>
<span id="cb3-32"><a href="#cb3-32" aria-hidden="true" tabindex="-1"></a>tfe_pref_new <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-33"><a href="#cb3-33" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> GTK_WIDGET <span class="op">(</span>g_object_new <span class="op">(</span>TFE_TYPE_PREF<span class="op">,</span> NULL<span class="op">));</span></span>
<span id="cb3-34"><a href="#cb3-34" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<ul>
<li>The structure <code>_TfePref</code> has <code>font_dialog_btn</code>
member. It points the GtkFontDialogButton object specified in the XML
file “tfepref.ui”. The member name <code>font_dialog_btn</code> must be
the same as the GtkFontDialogButton id attribute in the XML file.</li>
<li><code>G_DEFINE_FINAL_TYPE</code> macro expands to:
<ul>
<li>The declaration of the functions <code>tfe_pref_init</code> and
<code>tfe_pref_class_init</code>. They are defined in the following part
of the program.</li>
<li>The definition of the variable
<code>tfe_pref_parent_class</code>.</li>
<li>The definition of the function <code>tfe_pref_get_type</code>.</li>
</ul></li>
<li>The function <code>tfe_pref_class_init</code> initializes the
TfePref class. The function
<code>gtk_widget_class_set_template_from_resource</code> initializes the
composite widget template from the XML resource. The function
<code>gtk_widget_class_bind_template_child</code> connects the TfePref
structure member <code>font_dialog_btn</code> and the
GtkFontDialogButton in the XML. The member name and the id attribute
value must be the same.</li>
<li>The function <code>tfe_pref_init</code> initializes a newly created
instance. The function <code>gtk_widget_init_template</code> creates and
initializes child widgets.</li>
<li>The function <code>tfe_pref_dispose</code> releases objects. The
function <code>gtk_widget_dispose_template</code> releases child
widgets.</li>
</ul>
<h2 id="gtkfontdialogbutton-and-pango">GtkFontDialogButton and
Pango</h2>
<p>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 taken with the method
<code>gtk_font_dialog_button_get_font_desc</code>. It returns a pointer
to the PangoFontDescription structure.</p>
<p>Pango is a text layout engine. The <a
href="https://docs.gtk.org/Pango/index.html">documentation</a> is on the
internet.</p>
<p>PangoFontDescription is a C structure and it isnt allowed to access
directly. The document is <a
href="https://docs.gtk.org/Pango/struct.FontDescription.html">here</a>.
If you want to retrieve the font information, there are several
functions.</p>
<ul>
<li><code>pango_font_description_to_string</code> returns a string like
“Jamrul Bold Italic Semi-Expanded 12”.</li>
<li><code>pango_font_description_get_family</code> returns a font family
like “Jamrul”.</li>
<li><code>pango_font_description_get_weight</code> returns a PangoWeight
constant like <code>PANGO_WEIGHT_BOLD</code>.</li>
<li><code>pango_font_description_get_style</code> returns a PangoStyle
constant like <code>PANGO_STYLE_ITALIC</code>.</li>
<li><code>pango_font_description_get_stretch</code> returns a
PangoStretch constant like
<code>PANGO_STRETCH_SEMI_EXPANDED</code>.</li>
<li><code>pango_font_description_get_size</code> returns an integer like
<code>12</code>. Its unit is point or pixel (device unit). The function
<code>pango_font_description_get_size_is_absolute</code> returns TRUE if
the unit is absolute that means device unit. Otherwise the unit is
point.</li>
</ul>
<h2 id="gsettings">GSettings</h2>
<p>We want to maintain the font data after the application quits. There
are some ways to implement.</p>
<ul>
<li>Make a configuration file. For example, a text file
“~/.config/tfe/font_desc.cfg” keeps font information.</li>
<li>Use GSettings object. The basic idea of GSettings are similar to
configuration file. Configuration information data is put into a
database file.</li>
</ul>
<p>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.</p>
<h3 id="gsettings-schema">GSettings schema</h3>
<p>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.</p>
2023-01-03 07:30:06 +01:00
<ul>
<li>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.</li>
<li>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
<code>font-desc</code> is defined with a path
<code>/com/github/ToshioCP/tfe/</code>, the keys location in the
database is <code>/com/github/ToshioCP/tfe/font-desc</code>. Path is a
string begins with and ends with a slash (<code>/</code>). And it is
delimited by slashes.</li>
<li>GSettings save information as key-value style. Key is a string
begins with a lower case character followed by lower case, digit or dash
(<code>-</code>) and ends with lower case 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.</li>
<li>A default value needs to be set for each key.</li>
<li>A summery and description can be set for each key optionally.</li>
</ul>
<p>Schemas are described in an XML format. For example,</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb4-1"><a href="#cb4-1"></a><span class="fu">&lt;?xml</span><span class="ot"> version=</span><span class="st">&quot;1.0&quot;</span><span class="ot"> encoding=</span><span class="st">&quot;UTF-8&quot;</span><span class="fu">?&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2"></a>&lt;<span class="kw">schemalist</span>&gt;</span>
<span id="cb4-3"><a href="#cb4-3"></a> &lt;<span class="kw">schema</span><span class="ot"> path=</span><span class="st">&quot;/com/github/ToshioCP/tfe/&quot;</span><span class="ot"> id=</span><span class="st">&quot;com.github.ToshioCP.tfe&quot;</span>&gt;</span>
<span id="cb4-4"><a href="#cb4-4"></a> &lt;<span class="kw">key</span><span class="ot"> name=</span><span class="st">&quot;font-desc&quot;</span><span class="ot"> type=</span><span class="st">&quot;s&quot;</span>&gt;</span>
<span id="cb4-5"><a href="#cb4-5"></a> &lt;<span class="kw">default</span>&gt;&#39;Monospace 12&#39;&lt;/<span class="kw">default</span>&gt;</span>
<span id="cb4-6"><a href="#cb4-6"></a> &lt;<span class="kw">summary</span>&gt;Font&lt;/<span class="kw">summary</span>&gt;</span>
<span id="cb4-7"><a href="#cb4-7"></a> &lt;<span class="kw">description</span>&gt;A font to be used for textview.&lt;/<span class="kw">description</span>&gt;</span>
<span id="cb4-8"><a href="#cb4-8"></a> &lt;/<span class="kw">key</span>&gt;</span>
<span id="cb4-9"><a href="#cb4-9"></a> &lt;/<span class="kw">schema</span>&gt;</span>
<span id="cb4-10"><a href="#cb4-10"></a>&lt;/<span class="kw">schemalist</span>&gt;</span></code></pre></div>
<ul>
<li>4: The type attribute is “s”. It is GVariant type string. For
GVariant type string, see <a
href="https://docs.gtk.org/glib/struct.VariantType.html#gvariant-type-strings">GLib
API Reference GVariant Type Strings</a>. Other common types are:
2023-01-03 07:30:06 +01:00
<ul>
<li>“b”: gboolean</li>
<li>“i”: gint32.</li>
<li>“d”: double.</li>
2023-01-03 07:30:06 +01:00
</ul></li>
</ul>
<p>Further information is in:</p>
<ul>
<li><a
href="https://docs.gtk.org/glib/gvariant-format-strings.html">GLib API
Reference GVariant Format Strings</a></li>
<li><a href="https://docs.gtk.org/glib/gvariant-text.html">GLib API
Reference GVariant Text Format</a></li>
<li><a href="https://docs.gtk.org/glib/struct.Variant.html">GLib API
Reference GVariant</a></li>
<li><a href="https://docs.gtk.org/glib/struct.VariantType.html">GLib API
Reference VariantType</a></li>
</ul>
<h3 id="gsettings-command">Gsettings command</h3>
<p>First, lets try <code>gsettings</code> application. It is a
configuration tool for GSettings.</p>
<pre><code>$ 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 &quot;gsettings help COMMAND&quot; to get detailed help.</code></pre>
<p>List schemas.</p>
<pre><code>$ 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
... ...
</code></pre>
<p>Each line is an id of a schema. Each schema has a key-value
configuration data. You can see them with list-recursively command.
Lets look at the keys and values of <code>org.gnome.calculator</code>
schema.</p>
<pre><code>$ gsettings list-recursively org.gnome.calculator
org.gnome.calculator accuracy 9
org.gnome.calculator angle-units &#39;degrees&#39;
org.gnome.calculator base 10
org.gnome.calculator button-mode &#39;basic&#39;
org.gnome.calculator number-format &#39;automatic&#39;
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 &#39;&#39;
org.gnome.calculator source-units &#39;degree&#39;
org.gnome.calculator target-currency &#39;&#39;
org.gnome.calculator target-units &#39;radian&#39;
org.gnome.calculator window-position (-1, -1)
org.gnome.calculator word-size 64</code></pre>
<p>This schema is used by GNOME Calculator. Run the calculator and
change the mode, then check the schema again.</p>
<pre><code>$ gnome-calculator</code></pre>
2023-01-03 07:30:06 +01:00
<figure>
<img src="image/gnome_calculator_basic.png"
alt="gnome-calculator basic mode" />
<figcaption aria-hidden="true">gnome-calculator basic mode</figcaption>
2023-01-03 07:30:06 +01:00
</figure>
<p>Change the mode to advanced and quit.</p>
2023-01-03 07:30:06 +01:00
<figure>
<img src="image/gnome_calculator_advanced.png"
alt="gnome-calculator advanced mode" />
<figcaption aria-hidden="true">gnome-calculator advanced
mode</figcaption>
2023-01-03 07:30:06 +01:00
</figure>
<p>Run gsettings and check the value of <code>button-mode</code>.</p>
<pre><code>$ gsettings list-recursively org.gnome.calculator
... ...
org.gnome.calculator button-mode &#39;advanced&#39;
... ...
</code></pre>
<p>Now we know that GNOME Calculator used gsettings and it has set
<code>button-mode</code> key to “advanced”. The value remains even the
calculator quits. So when the calculator runs again, it will appear as
an advanced mode.</p>
<h3 id="glib-compile-schemas-utility">Glib-compile-schemas utility</h3>
<p>GSettings schemas are specified with an XML format. The XML schema
files must have the filename extension <code>.gschema.xml</code>. The
following is the XML schema file for the application
<code>tfe</code>.</p>
2023-01-03 07:30:06 +01:00
<div class="sourceCode" id="cb10"><pre
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb10-1"><a href="#cb10-1"></a><span class="fu">&lt;?xml</span><span class="ot"> version=</span><span class="st">&quot;1.0&quot;</span><span class="ot"> encoding=</span><span class="st">&quot;UTF-8&quot;</span><span class="fu">?&gt;</span></span>
<span id="cb10-2"><a href="#cb10-2"></a>&lt;<span class="kw">schemalist</span>&gt;</span>
<span id="cb10-3"><a href="#cb10-3"></a> &lt;<span class="kw">schema</span><span class="ot"> path=</span><span class="st">&quot;/com/github/ToshioCP/tfe/&quot;</span><span class="ot"> id=</span><span class="st">&quot;com.github.ToshioCP.tfe&quot;</span>&gt;</span>
<span id="cb10-4"><a href="#cb10-4"></a> &lt;<span class="kw">key</span><span class="ot"> name=</span><span class="st">&quot;font-desc&quot;</span><span class="ot"> type=</span><span class="st">&quot;s&quot;</span>&gt;</span>
<span id="cb10-5"><a href="#cb10-5"></a> &lt;<span class="kw">default</span>&gt;&#39;Monospace 12&#39;&lt;/<span class="kw">default</span>&gt;</span>
<span id="cb10-6"><a href="#cb10-6"></a> &lt;<span class="kw">summary</span>&gt;Font&lt;/<span class="kw">summary</span>&gt;</span>
<span id="cb10-7"><a href="#cb10-7"></a> &lt;<span class="kw">description</span>&gt;A font to be used for textview.&lt;/<span class="kw">description</span>&gt;</span>
<span id="cb10-8"><a href="#cb10-8"></a> &lt;/<span class="kw">key</span>&gt;</span>
<span id="cb10-9"><a href="#cb10-9"></a> &lt;/<span class="kw">schema</span>&gt;</span>
<span id="cb10-10"><a href="#cb10-10"></a>&lt;/<span class="kw">schemalist</span>&gt;</span></code></pre></div>
<p>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.</p>
<ul>
<li>2: The top level element is <code>&lt;schemalist&gt;</code>.</li>
<li>3: schema tag has <code>path</code> and <code>id</code> attributes.
A path determines where the settings are stored in the conceptual global
tree of settings. An id identifies the schema.</li>
<li>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.</li>
<li>5: default value of the key <code>font-desc</code> is
<code>Monospace 12</code>.</li>
<li>6: Summery and description elements describes the key. They are
optional, but it is recommended to add them in the XML file.</li>
</ul>
<p>The XML file is compiled by glib-compile-schemas. When compiling,
<code>glib-compile-schemas</code> 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 <code>gschemas.compiled</code>.
Suppose the XML file above is under <code>tfe6</code> directory.</p>
<pre><code>$ glib-compile-schemas tfe6</code></pre>
<p>Then, <code>gschemas.compiled</code> is generated under
<code>tfe6</code>. When you test your application, set
<code>GSETTINGS_SCHEMA_DIR</code> environment variable so that GSettings
objet can find <code>gschemas.compiled</code>.</p>
<pre><code>$ GSETTINGS_SCHEMA_DIR=(the directory gschemas.compiled is located):$GSETTINGS_SCHEMA_DIR (your application name)</code></pre>
<p>GSettings object looks for this file by the following process.</p>
2023-01-03 07:30:06 +01:00
<ul>
<li>It searches <code>glib-2.0/schemas</code> subdirectories of all the
directories specified in the environment variable
<code>XDG_DATA_DIRS</code>. Common directores are
<code>/usr/share/glib-2.0/schemas</code> and
<code>/usr/local/share/glib-2.0/schemas</code>.</li>
<li>If <code>$HOME/.local/share/glib-2.0/schemas</code> exists, it is
also searched.</li>
<li>If <code>GSETTINGS_SCHEMA_DIR</code> environment variable is
defined, it searches all the directories specified in the variable.
<code>GSETTINGS_SCHEMA_DIR</code> can specify multiple directories
delimited by colon (:).</li>
2023-01-03 07:30:06 +01:00
</ul>
<p>The directories above includes more than one
<code>.gschema.xml</code> file. Therefore, when you install your
application, follow the instruction below to install your schemas.</p>
<ol type="1">
<li>Make <code>.gschema.xml</code> file.</li>
<li>Copy it to one of the directories above. For example,
<code>$HOME/.local/share/glib-2.0/schemas</code>.</li>
<li>Run <code>glib-compile-schemas</code> on the directory. It compiles
all the schema files in the directory and creates or updates the
database file <code>gschemas.compiled</code>.</li>
</ol>
<h3 id="gsettings-object-and-binding">GSettings object and binding</h3>
<p>Now, we go on to the next topic, how to program GSettings.</p>
<p>You need to compile your schema file in advance.</p>
<p>Suppose id, key, class name and a property name are:</p>
2023-01-03 07:30:06 +01:00
<ul>
<li>GSettings id: com.github.ToshioCP.sample</li>
<li>GSettings key: sample_key</li>
<li>The class name: Sample</li>
<li>The property to bind: sample_property</li>
2023-01-03 07:30:06 +01:00
</ul>
<p>The example below uses <code>g_settings_bind</code>. 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.</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>GSettings <span class="op">*</span>settings<span class="op">;</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>Sample <span class="op">*</span>sample_object<span class="op">;</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>settings <span class="op">=</span> g_settings_new <span class="op">(</span><span class="st">&quot;com.github.ToshioCP.sample&quot;</span><span class="op">);</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>sample_object <span class="op">=</span> sample_new <span class="op">();</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>g_settings_bind <span class="op">(</span>settings<span class="op">,</span> <span class="st">&quot;sample_key&quot;</span><span class="op">,</span> sample_object<span class="op">,</span> <span class="st">&quot;sample_property&quot;</span><span class="op">,</span> G_SETTINGS_BIND_DEFAULT<span class="op">);</span></span></code></pre></div>
<p>The function <code>g_settings_bind</code> 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.</p>
<p>The function <code>g_settings_bind</code> is simple and easy but it
isnt 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
doesnt support boxed type.</p>
<p>In that case, another function
<code>g_settings_bind_with_mapping</code> is used. It binds GSettings
GVariant value and object property via GValue with mapping
functions.</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>g_settings_bind_with_mapping <span class="op">(</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> GSettings<span class="op">*</span> settings<span class="op">,</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">const</span> gchar<span class="op">*</span> key<span class="op">,</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> object<span class="op">,</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">const</span> gchar<span class="op">*</span> property<span class="op">,</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a> GSettingsBindFlags flags<span class="op">,</span> <span class="co">// G_SETTINGS_BIND_DEFAULT is commonly used</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a> GSettingsBindGetMapping get_mapping<span class="op">,</span> <span class="co">// GSettings =&gt; property, See the example below</span></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a> GSettingsBindSetMapping set_mapping<span class="op">,</span> <span class="co">// property =&gt; GSettings, See the example below</span></span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a> gpointer user_data<span class="op">,</span> <span class="co">// NULL if unnecessary</span></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a> GDestroyNotify destroy <span class="co">//NULL if unnecessary</span></span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div>
<p>The mapping functions are defined like these:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>gboolean</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="op">(*</span> GSettingsBindGetMapping<span class="op">)</span> <span class="op">(</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a> GValue<span class="op">*</span> value<span class="op">,</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a> GVariant<span class="op">*</span> variant<span class="op">,</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a> gpointer user_data</span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>GVariant<span class="op">*</span></span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a><span class="op">(*</span> GSettingsBindSetMapping<span class="op">)</span> <span class="op">(</span></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">const</span> GValue<span class="op">*</span> value<span class="op">,</span></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">const</span> GVariantType<span class="op">*</span> expected_type<span class="op">,</span></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a> gpointer user_data</span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div>
<p>The following codes are extracted from <code>tfepref.c</code>.</p>
<div class="sourceCode" id="cb16"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb16-1"><a href="#cb16-1"></a><span class="dt">static</span> gboolean <span class="co">// GSettings =&gt; property</span></span>
<span id="cb16-2"><a href="#cb16-2"></a>get_mapping <span class="op">(</span>GValue<span class="op">*</span> value<span class="op">,</span> GVariant<span class="op">*</span> variant<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-3"><a href="#cb16-3"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>s <span class="op">=</span> g_variant_get_string <span class="op">(</span>variant<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb16-4"><a href="#cb16-4"></a> PangoFontDescription <span class="op">*</span>font_desc <span class="op">=</span> pango_font_description_from_string <span class="op">(</span>s<span class="op">);</span></span>
<span id="cb16-5"><a href="#cb16-5"></a> g_value_take_boxed <span class="op">(</span>value<span class="op">,</span> font_desc<span class="op">);</span></span>
<span id="cb16-6"><a href="#cb16-6"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span>
<span id="cb16-7"><a href="#cb16-7"></a><span class="op">}</span></span>
<span id="cb16-8"><a href="#cb16-8"></a></span>
<span id="cb16-9"><a href="#cb16-9"></a><span class="dt">static</span> GVariant<span class="op">*</span> <span class="co">// Property =&gt; GSettings</span></span>
<span id="cb16-10"><a href="#cb16-10"></a>set_mapping <span class="op">(</span><span class="dt">const</span> GValue<span class="op">*</span> value<span class="op">,</span> <span class="dt">const</span> GVariantType<span class="op">*</span> expected_type<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-11"><a href="#cb16-11"></a> <span class="dt">char</span><span class="op">*</span>font_desc_string <span class="op">=</span> pango_font_description_to_string <span class="op">(</span>g_value_get_boxed <span class="op">(</span>value<span class="op">));</span></span>
<span id="cb16-12"><a href="#cb16-12"></a> <span class="cf">return</span> g_variant_new_take_string <span class="op">(</span>font_desc_string<span class="op">);</span></span>
<span id="cb16-13"><a href="#cb16-13"></a><span class="op">}</span></span>
<span id="cb16-14"><a href="#cb16-14"></a></span>
<span id="cb16-15"><a href="#cb16-15"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb16-16"><a href="#cb16-16"></a>tfe_pref_init <span class="op">(</span>TfePref <span class="op">*</span>pref<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-17"><a href="#cb16-17"></a> gtk_widget_init_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>pref<span class="op">));</span></span>
<span id="cb16-18"><a href="#cb16-18"></a> pref<span class="op">-&gt;</span>settings <span class="op">=</span> g_settings_new <span class="op">(</span><span class="st">&quot;com.github.ToshioCP.tfe&quot;</span><span class="op">);</span></span>
<span id="cb16-19"><a href="#cb16-19"></a> g_settings_bind_with_mapping <span class="op">(</span>pref<span class="op">-&gt;</span>settings<span class="op">,</span> <span class="st">&quot;font-desc&quot;</span><span class="op">,</span> pref<span class="op">-&gt;</span>font_dialog_btn<span class="op">,</span> <span class="st">&quot;font-desc&quot;</span><span class="op">,</span> G_SETTINGS_BIND_DEFAULT<span class="op">,</span></span>
<span id="cb16-20"><a href="#cb16-20"></a> get_mapping<span class="op">,</span> set_mapping<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb16-21"><a href="#cb16-21"></a><span class="op">}</span></span></code></pre></div>
<ul>
<li>15-21: This function <code>tfe_pref_init</code> initializes the new
TfePref instance.</li>
<li>18: Creates a new GSettings instance. The id is
“com.github.ToshioCP.tfe”.</li>
<li>19-20: Binds the GSettings “font-desc” and the GtkFontDialogButton
property “font-desc”. The mapping functions are <code>get_mapping</code>
and <code>set_mapping</code>.</li>
<li>1-7: The mapping function from GSettings to the property. The first
argument <code>value</code> is a GValue to be stored in the property.
The second argument <code>variant</code> is a GVarinat structure that
comes from the GSettings value.</li>
<li>3: Retrieves a string from the GVariant structure.</li>
<li>4: Build a PangoFontDescription structure from the string and
assigns its address to <code>font_desc</code>.</li>
<li>5: Puts <code>font_desc</code> into the GValue <code>value</code>.
The ownership of <code>font_desc</code> moves to
<code>value</code>.</li>
<li>6: Returns TRUE that means the mapping succeeds.</li>
<li>9-13: The mapping function from the property to GSettings. The first
argument <code>value</code> holds the property data. The second argument
<code>expected_type</code> is the type of GVariant that the GSettings
value has. It isnt used in this function.</li>
<li>11: Gets the PangoFontDescription structure from <code>value</code>
and converts it to string.</li>
<li>12: The string is inserted to a GVariant structure. The ownership of
the string <code>font_desc_string</code> moves to the returned
value.</li>
</ul>
<h2 id="c-file">C file</h2>
<p>The following is the full codes of <code>tfepref.c</code></p>
2023-01-03 07:30:06 +01:00
<div class="sourceCode" id="cb17"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb17-1"><a href="#cb17-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb17-2"><a href="#cb17-2"></a><span class="pp">#include </span><span class="im">&quot;tfepref.h&quot;</span></span>
<span id="cb17-3"><a href="#cb17-3"></a></span>
<span id="cb17-4"><a href="#cb17-4"></a><span class="kw">struct</span> _TfePref</span>
<span id="cb17-5"><a href="#cb17-5"></a><span class="op">{</span></span>
<span id="cb17-6"><a href="#cb17-6"></a> GtkWindow parent<span class="op">;</span></span>
<span id="cb17-7"><a href="#cb17-7"></a> GSettings <span class="op">*</span>settings<span class="op">;</span></span>
<span id="cb17-8"><a href="#cb17-8"></a> GtkFontDialogButton <span class="op">*</span>font_dialog_btn<span class="op">;</span></span>
<span id="cb17-9"><a href="#cb17-9"></a><span class="op">};</span></span>
2023-01-03 07:30:06 +01:00
<span id="cb17-10"><a href="#cb17-10"></a></span>
<span id="cb17-11"><a href="#cb17-11"></a>G_DEFINE_FINAL_TYPE <span class="op">(</span>TfePref<span class="op">,</span> tfe_pref<span class="op">,</span> GTK_TYPE_WINDOW<span class="op">);</span></span>
2023-01-03 07:30:06 +01:00
<span id="cb17-12"><a href="#cb17-12"></a></span>
<span id="cb17-13"><a href="#cb17-13"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb17-14"><a href="#cb17-14"></a>tfe_pref_dispose <span class="op">(</span>GObject <span class="op">*</span>gobject<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-15"><a href="#cb17-15"></a> TfePref <span class="op">*</span>pref <span class="op">=</span> TFE_PREF <span class="op">(</span>gobject<span class="op">);</span></span>
<span id="cb17-16"><a href="#cb17-16"></a></span>
<span id="cb17-17"><a href="#cb17-17"></a> <span class="co">/* GSetting bindings are automatically removed when the object is finalized, so it isn&#39;t necessary to unbind them explicitly.*/</span></span>
<span id="cb17-18"><a href="#cb17-18"></a> g_clear_object <span class="op">(&amp;</span>pref<span class="op">-&gt;</span>settings<span class="op">);</span></span>
<span id="cb17-19"><a href="#cb17-19"></a> gtk_widget_dispose_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>pref<span class="op">),</span> TFE_TYPE_PREF<span class="op">);</span></span>
<span id="cb17-20"><a href="#cb17-20"></a> G_OBJECT_CLASS <span class="op">(</span>tfe_pref_parent_class<span class="op">)-&gt;</span>dispose <span class="op">(</span>gobject<span class="op">);</span></span>
<span id="cb17-21"><a href="#cb17-21"></a><span class="op">}</span></span>
<span id="cb17-22"><a href="#cb17-22"></a></span>
<span id="cb17-23"><a href="#cb17-23"></a><span class="co">/* ---------- get_mapping/set_mapping ---------- */</span></span>
<span id="cb17-24"><a href="#cb17-24"></a><span class="dt">static</span> gboolean <span class="co">// GSettings =&gt; property</span></span>
<span id="cb17-25"><a href="#cb17-25"></a>get_mapping <span class="op">(</span>GValue<span class="op">*</span> value<span class="op">,</span> GVariant<span class="op">*</span> variant<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-26"><a href="#cb17-26"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>s <span class="op">=</span> g_variant_get_string <span class="op">(</span>variant<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb17-27"><a href="#cb17-27"></a> PangoFontDescription <span class="op">*</span>font_desc <span class="op">=</span> pango_font_description_from_string <span class="op">(</span>s<span class="op">);</span></span>
<span id="cb17-28"><a href="#cb17-28"></a> g_value_take_boxed <span class="op">(</span>value<span class="op">,</span> font_desc<span class="op">);</span></span>
<span id="cb17-29"><a href="#cb17-29"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span>
<span id="cb17-30"><a href="#cb17-30"></a><span class="op">}</span></span>
<span id="cb17-31"><a href="#cb17-31"></a></span>
<span id="cb17-32"><a href="#cb17-32"></a><span class="dt">static</span> GVariant<span class="op">*</span> <span class="co">// Property =&gt; GSettings</span></span>
<span id="cb17-33"><a href="#cb17-33"></a>set_mapping <span class="op">(</span><span class="dt">const</span> GValue<span class="op">*</span> value<span class="op">,</span> <span class="dt">const</span> GVariantType<span class="op">*</span> expected_type<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-34"><a href="#cb17-34"></a> <span class="dt">char</span><span class="op">*</span>font_desc_string <span class="op">=</span> pango_font_description_to_string <span class="op">(</span>g_value_get_boxed <span class="op">(</span>value<span class="op">));</span></span>
<span id="cb17-35"><a href="#cb17-35"></a> <span class="cf">return</span> g_variant_new_take_string <span class="op">(</span>font_desc_string<span class="op">);</span></span>
<span id="cb17-36"><a href="#cb17-36"></a><span class="op">}</span></span>
<span id="cb17-37"><a href="#cb17-37"></a></span>
<span id="cb17-38"><a href="#cb17-38"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb17-39"><a href="#cb17-39"></a>tfe_pref_init <span class="op">(</span>TfePref <span class="op">*</span>pref<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-40"><a href="#cb17-40"></a> gtk_widget_init_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>pref<span class="op">));</span></span>
<span id="cb17-41"><a href="#cb17-41"></a> pref<span class="op">-&gt;</span>settings <span class="op">=</span> g_settings_new <span class="op">(</span><span class="st">&quot;com.github.ToshioCP.tfe&quot;</span><span class="op">);</span></span>
<span id="cb17-42"><a href="#cb17-42"></a> g_settings_bind_with_mapping <span class="op">(</span>pref<span class="op">-&gt;</span>settings<span class="op">,</span> <span class="st">&quot;font-desc&quot;</span><span class="op">,</span> pref<span class="op">-&gt;</span>font_dialog_btn<span class="op">,</span> <span class="st">&quot;font-desc&quot;</span><span class="op">,</span> G_SETTINGS_BIND_DEFAULT<span class="op">,</span></span>
<span id="cb17-43"><a href="#cb17-43"></a> get_mapping<span class="op">,</span> set_mapping<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb17-44"><a href="#cb17-44"></a><span class="op">}</span></span>
<span id="cb17-45"><a href="#cb17-45"></a></span>
<span id="cb17-46"><a href="#cb17-46"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb17-47"><a href="#cb17-47"></a>tfe_pref_class_init <span class="op">(</span>TfePrefClass <span class="op">*</span>class<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-48"><a href="#cb17-48"></a> G_OBJECT_CLASS <span class="op">(</span>class<span class="op">)-&gt;</span>dispose <span class="op">=</span> tfe_pref_dispose<span class="op">;</span></span>
<span id="cb17-49"><a href="#cb17-49"></a> gtk_widget_class_set_template_from_resource <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> <span class="st">&quot;/com/github/ToshioCP/tfe/tfepref.ui&quot;</span><span class="op">);</span></span>
<span id="cb17-50"><a href="#cb17-50"></a> gtk_widget_class_bind_template_child <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> TfePref<span class="op">,</span> font_dialog_btn<span class="op">);</span></span>
<span id="cb17-51"><a href="#cb17-51"></a><span class="op">}</span></span>
<span id="cb17-52"><a href="#cb17-52"></a></span>
<span id="cb17-53"><a href="#cb17-53"></a>GtkWidget <span class="op">*</span></span>
<span id="cb17-54"><a href="#cb17-54"></a>tfe_pref_new <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-55"><a href="#cb17-55"></a> <span class="cf">return</span> GTK_WIDGET <span class="op">(</span>g_object_new <span class="op">(</span>TFE_TYPE_PREF<span class="op">,</span> NULL<span class="op">));</span></span>
<span id="cb17-56"><a href="#cb17-56"></a><span class="op">}</span></span></code></pre></div>
<h2 id="test-program">Test program</h2>
<p>Theres a test program located at <code>src/tfe6/test</code>
2023-01-03 07:30:06 +01:00
directory.</p>
<div class="sourceCode" id="cb18"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb18-1"><a href="#cb18-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb18-2"><a href="#cb18-2"></a><span class="pp">#include </span><span class="im">&quot;../tfepref.h&quot;</span></span>
<span id="cb18-3"><a href="#cb18-3"></a></span>
<span id="cb18-4"><a href="#cb18-4"></a>GSettings <span class="op">*</span>settings<span class="op">;</span></span>
<span id="cb18-5"><a href="#cb18-5"></a></span>
<span id="cb18-6"><a href="#cb18-6"></a><span class="co">// &quot;changed::font-desc&quot; signal handler</span></span>
<span id="cb18-7"><a href="#cb18-7"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb18-8"><a href="#cb18-8"></a>changed_font_desc_cb <span class="op">(</span>GSettings <span class="op">*</span>settings<span class="op">,</span> <span class="dt">char</span> <span class="op">*</span>key<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb18-9"><a href="#cb18-9"></a> <span class="dt">char</span> <span class="op">*</span>s<span class="op">;</span></span>
<span id="cb18-10"><a href="#cb18-10"></a> s <span class="op">=</span> g_settings_get_string <span class="op">(</span>settings<span class="op">,</span> key<span class="op">);</span></span>
<span id="cb18-11"><a href="#cb18-11"></a> g_print <span class="op">(</span><span class="st">&quot;%s</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">,</span> s<span class="op">);</span></span>
<span id="cb18-12"><a href="#cb18-12"></a> g_free <span class="op">(</span>s<span class="op">);</span></span>
<span id="cb18-13"><a href="#cb18-13"></a><span class="op">}</span></span>
<span id="cb18-14"><a href="#cb18-14"></a></span>
<span id="cb18-15"><a href="#cb18-15"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb18-16"><a href="#cb18-16"></a>app_shutdown <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb18-17"><a href="#cb18-17"></a> g_object_unref <span class="op">(</span>settings<span class="op">);</span></span>
<span id="cb18-18"><a href="#cb18-18"></a><span class="op">}</span></span>
<span id="cb18-19"><a href="#cb18-19"></a></span>
<span id="cb18-20"><a href="#cb18-20"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb18-21"><a href="#cb18-21"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb18-22"><a href="#cb18-22"></a> GtkWidget <span class="op">*</span>pref <span class="op">=</span> tfe_pref_new <span class="op">();</span></span>
<span id="cb18-23"><a href="#cb18-23"></a></span>
<span id="cb18-24"><a href="#cb18-24"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>pref<span class="op">),</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">));</span></span>
<span id="cb18-25"><a href="#cb18-25"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>pref<span class="op">));</span></span>
<span id="cb18-26"><a href="#cb18-26"></a><span class="op">}</span></span>
<span id="cb18-27"><a href="#cb18-27"></a></span>
<span id="cb18-28"><a href="#cb18-28"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb18-29"><a href="#cb18-29"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb18-30"><a href="#cb18-30"></a> settings <span class="op">=</span> g_settings_new <span class="op">(</span><span class="st">&quot;com.github.ToshioCP.tfe&quot;</span><span class="op">);</span></span>
<span id="cb18-31"><a href="#cb18-31"></a> g_signal_connect <span class="op">(</span>settings<span class="op">,</span> <span class="st">&quot;changed::font-desc&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>changed_font_desc_cb<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb18-32"><a href="#cb18-32"></a> g_print <span class="op">(</span><span class="st">&quot;%s</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">,</span> <span class="st">&quot;Change the font with the font button. Then the new font will be printed out.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span>
<span id="cb18-33"><a href="#cb18-33"></a><span class="op">}</span></span>
<span id="cb18-34"><a href="#cb18-34"></a></span>
<span id="cb18-35"><a href="#cb18-35"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.test_tfe_pref&quot;</span></span>
<span id="cb18-36"><a href="#cb18-36"></a></span>
<span id="cb18-37"><a href="#cb18-37"></a><span class="dt">int</span></span>
<span id="cb18-38"><a href="#cb18-38"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span>
<span id="cb18-39"><a href="#cb18-39"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb18-40"><a href="#cb18-40"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb18-41"><a href="#cb18-41"></a></span>
<span id="cb18-42"><a href="#cb18-42"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_DEFAULT_FLAGS<span class="op">);</span></span>
<span id="cb18-43"><a href="#cb18-43"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;startup&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb18-44"><a href="#cb18-44"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb18-45"><a href="#cb18-45"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;shutdown&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_shutdown<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb18-46"><a href="#cb18-46"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span>
<span id="cb18-47"><a href="#cb18-47"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb18-48"><a href="#cb18-48"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb18-49"><a href="#cb18-49"></a><span class="op">}</span></span></code></pre></div>
<p>This program sets its active window to TfePref instance, which is a
child object of GtkWindow.</p>
<p>It sets the “changed::font-desc” signal handler in the startup
function. The process from the users font selection to the handler
is:</p>
<ul>
<li>The user clicked on the GtkFontDialogButton and GtkFontDialog
appears.</li>
<li>He/she selects a new font.</li>
<li>The “font-desc” property of the GtkFontDialogButton instance is
changed.</li>
<li>The value of “font-desc” key on the GSettings database is changed
since it is bound to the property.</li>
<li>The “changed::font-desc” signal on the GSettings instance is
emitted.</li>
<li>The handler is called.</li>
</ul>
<p>The program building is divided into four steps.</p>
2023-01-03 07:30:06 +01:00
<ul>
<li>Compile the schema file</li>
<li>Compile the XML file to a resource (C source file)</li>
<li>Compile the C files</li>
<li>Run the executable file</li>
2023-01-03 07:30:06 +01:00
</ul>
<p>Commands are shown in the next four sub-subsections. You dont need
to try them. The final sub-subsection shows the meson-ninja way, which
is the easiest.</p>
<h3 id="compile-the-schema-file">Compile the schema file</h3>
<pre><code>$ cd src/tef6/test
$ cp ../com.github.ToshioCP.tfe.gschema.xml com.github.ToshioCP.tfe.gschema.xml
$ glib-compile-schemas .</code></pre>
<p>Be careful. The commands <code>glib-compile-schemas</code> has an
argument “.”, which means the current directory. This results in
creating <code>gschemas.compiled</code> file.</p>
<h3 id="compile-the-xml-file">Compile the XML file</h3>
<pre><code>$ glib-compile-resources --sourcedir=.. --generate-source --target=resource.c ../tfe.gresource.xml</code></pre>
<h3 id="compile-the-c-file">Compile the C file</h3>
<pre><code>$ gcc `pkg-config --cflags gtk4` test_pref.c ../tfepref.c resource.c `pkg-config --libs gtk4`</code></pre>
<h3 id="run-the-executable-file">Run the executable file</h3>
<pre><code>$ GSETTINGS_SCHEMA_DIR=. ./a.out
Jamrul Italic Semi-Expanded 12 # &lt;= select Jamrul Italic 12
Monospace 12 #&lt;= select Monospace Regular 12</code></pre>
<h3 id="meson-ninja-way">Meson-ninja way</h3>
<p>Meson wraps up the commands above. Create the following text and save
it to <code>meson.build</code>.</p>
<p>Note: Gtk4-tutorial repository has meson.build file that defines
several tests. So you can try it instead of the following text.</p>
<pre><code>project(&#39;tfe_pref_test&#39;, &#39;c&#39;)
gtkdep = dependency(&#39;gtk4&#39;)
gnome=import(&#39;gnome&#39;)
resources = gnome.compile_resources(&#39;resources&#39;,&#39;../tfe.gresource.xml&#39;, source_dir: &#39;..&#39;)
gnome.compile_schemas(build_by_default: true, depend_files: &#39;com.github.ToshioCP.tfe.gschema.xml&#39;)
executable(&#39;test_pref&#39;, [&#39;test_pref.c&#39;, &#39;../tfepref.c&#39;], resources, dependencies: gtkdep, export_dynamic: true, install: false)</code></pre>
<ul>
<li>Project name is tfe_pref_test and it is written in C
language.</li>
<li>It depends on GTK4 library.</li>
<li>It uses GNOME module. Modules are prepared by Meson.</li>
<li>GNOME module has <code>compile_resources</code> method. When you
call this method, you need the prefix “gnome.”.
<ul>
<li>The target filename is resources.</li>
<li>The definition XML file is ../tfe.gresource.xml.</li>
<li>The source dir is ... All the ui files are located there.</li>
</ul></li>
<li>GNOME module has <code>compile_schemas</code> method. 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.</li>
<li>It creates an executable file test_pref. The source files are
test_pref.c, ../tfepref.c and <code>resources</code>, which is made
by <code>gnome.compile_resources</code>. It depends on
<code>gtkdep</code>, which is GTK4 library. The symbols are exported and
no installation support.</li>
</ul>
<p>Type like this to build and test the program.</p>
<pre><code>$ 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</code></pre>
<p>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.</p>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</body>
</html>