Gtk4-tutorial/docs/sec31.html

919 lines
82 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.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" 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="sec30.html">Prev: section30</a>
</li>
<li class="nav-item">
<a class="nav-link" href="sec32.html">Next: section32</a>
</li>
</ul>
</div>
</div>
</nav>
2023-07-29 14:41:57 +02:00
<h1 id="gtkexpression">GtkExpression</h1>
<p>GtkExpression is a fundamental type. It is not a descendant of
GObject. GtkExpression provides a way to describe references to values.
GtkExpression needs to be evaluated to obtain a value.</p>
<p>It is similar to arithmetic calculation.</p>
<pre><code>1 + 2 = 3</code></pre>
<p><code>1+2</code> is an expression. It shows the way how to calculate.
<code>3</code> is the value comes from the expression. Evaluation is to
calculate the expression and get the value.</p>
<p>GtkExpression is a way to get a value. Evaluation is like a
calculation. A value is got by evaluating the expression.</p>
<h2 id="constant-expression">Constant expression</h2>
<p>A constant expression (GtkConstantExpression) provides constant value
or instance when it is evaluated.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a> GValue value <span class="op">=</span> G_VALUE_INIT<span class="op">;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> expression <span class="op">=</span> gtk_constant_expression_new <span class="op">(</span>G_TYPE_INT<span class="op">,</span><span class="dv">100</span><span class="op">);</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> gtk_expression_evaluate <span class="op">(</span>expression<span class="op">,</span> NULL<span class="op">,</span> <span class="op">&amp;</span>value<span class="op">);</span></span></code></pre></div>
<ul>
<li>GtkExpression uses GValue to hold a value. GValue is a structure and
container to hold a type and value. It must be initialized with
<code>G_VALUE_INIT</code>, first. Be careful that <code>value</code> is
a structure, not a pointer to a structure.</li>
<li>Constant expression is created with
<code>gtk_constant_expression_new</code> function. The parameter of the
function is a type (GType) and a value (or instance). This expression
holds a constant value. <code>G_TYPE_INT</code> is a type that is
registered to the type system. It is integer type. Some types are shown
in the following table.</li>
<li><code>gtk_expression_evaluate</code> evaluates the expression. It
has three parameters, the expression to evaluate, <code>this</code>
instance and a pointer to a GValue for being set with the value.
<code>this</code> instance isnt necessary for constant expressions.
Therefore, the second argument is NULL.
<code>gtk_expression_evaluate</code> returns TRUE if it successfully
evaluates the expression. Otherwise it returns FALSE.</li>
<li>If it returns TRUE, the GValue <code>value</code> is set with the
value of the expression. The type of the value is int.</li>
</ul>
<table>
<thead>
<tr class="header">
<th style="text-align: left;">GType</th>
<th style="text-align: left;">C type</th>
<th style="text-align: left;">type name</th>
<th style="text-align: left;">notes</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">G_TYPE_CHAR</td>
<td style="text-align: left;">char</td>
<td style="text-align: left;">gchar</td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td style="text-align: left;">G_TYPE_BOOLEAN</td>
<td style="text-align: left;">int</td>
<td style="text-align: left;">gboolean</td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">G_TYPE_INT</td>
<td style="text-align: left;">int</td>
<td style="text-align: left;">gint</td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td style="text-align: left;">G_TYPE_FLOAT</td>
<td style="text-align: left;">float</td>
<td style="text-align: left;">gfloat</td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">G_TYPE_DOUBLE</td>
<td style="text-align: left;">double</td>
<td style="text-align: left;">gdouble</td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td style="text-align: left;">G_TYPE_POINTER</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">gpointer</td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">G_TYPE_STRING</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">gchararray</td>
<td style="text-align: left;">null-terminated Cstring</td>
</tr>
<tr class="even">
<td style="text-align: left;">G_TYPE_OBJECT</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">GObject</td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">GTK_TYPE_WINDOW</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">GtkWindow</td>
<td style="text-align: left;"></td>
</tr>
</tbody>
</table>
<p>A sample program <code>exp_constant_simple.c</code> is in
<code>src/expression</code> directory.</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-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"></a></span>
<span id="cb3-3"><a href="#cb3-3"></a><span class="dt">int</span></span>
<span id="cb3-4"><a href="#cb3-4"></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="cb3-5"><a href="#cb3-5"></a> GtkExpression <span class="op">*</span>expression<span class="op">;</span></span>
<span id="cb3-6"><a href="#cb3-6"></a> GValue value <span class="op">=</span> G_VALUE_INIT<span class="op">;</span></span>
<span id="cb3-7"><a href="#cb3-7"></a></span>
<span id="cb3-8"><a href="#cb3-8"></a> <span class="co">/* Create an expression */</span></span>
<span id="cb3-9"><a href="#cb3-9"></a> expression <span class="op">=</span> gtk_constant_expression_new <span class="op">(</span>G_TYPE_INT<span class="op">,</span><span class="dv">100</span><span class="op">);</span></span>
<span id="cb3-10"><a href="#cb3-10"></a> <span class="co">/* Evaluate the expression */</span></span>
<span id="cb3-11"><a href="#cb3-11"></a> <span class="cf">if</span> <span class="op">(</span>gtk_expression_evaluate <span class="op">(</span>expression<span class="op">,</span> NULL<span class="op">,</span> <span class="op">&amp;</span>value<span class="op">))</span></span>
<span id="cb3-12"><a href="#cb3-12"></a> g_print <span class="op">(</span><span class="st">&quot;The value is %d.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">,</span> g_value_get_int <span class="op">(&amp;</span>value<span class="op">));</span></span>
<span id="cb3-13"><a href="#cb3-13"></a> <span class="cf">else</span></span>
<span id="cb3-14"><a href="#cb3-14"></a> g_print <span class="op">(</span><span class="st">&quot;The constant expression wasn&#39;t evaluated correctly.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span>
<span id="cb3-15"><a href="#cb3-15"></a> gtk_expression_unref <span class="op">(</span>expression<span class="op">);</span></span>
<span id="cb3-16"><a href="#cb3-16"></a> g_value_unset <span class="op">(&amp;</span>value<span class="op">);</span></span>
<span id="cb3-17"><a href="#cb3-17"></a></span>
<span id="cb3-18"><a href="#cb3-18"></a> <span class="cf">return</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb3-19"><a href="#cb3-19"></a><span class="op">}</span></span></code></pre></div>
<ul>
<li>9: A constant expression is created. It holds an int value 100. The
variable <code>expression</code> points the expression.</li>
<li>11-14: Evaluates the expression. If it successes, show the value to
the stdout. Otherwise show an error message.</li>
<li>15-16: Releases the expression and unsets the GValue.</li>
</ul>
<p>Constant expression is usually used to give a constant value or
instance to another expression.</p>
<h2 id="property-expression">Property expression</h2>
<p>A property expression (GtkPropertyExpression) looks up a property in
a GObject instance. For example, a property expression that refers
“label” property in a GtkLabel object is created like this.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>expression <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_LABEL<span class="op">,</span> another_expression<span class="op">,</span> <span class="st">&quot;label&quot;</span><span class="op">);</span></span></code></pre></div>
<p>The second parameter <code>another_expression</code> is one of:</p>
<ul>
<li>An expression that gives a GtkLabel instance when it is
evaluated.</li>
<li>NULL. When NULL is given, a GtkLabel instance will be given when it
is evaluated. The instance is called <code>this</code> object.</li>
</ul>
<p>For example,</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>label <span class="op">=</span> gtk_label_new <span class="op">(</span><span class="st">&quot;Hello&quot;</span><span class="op">);</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>another_expression <span class="op">=</span> gtk_constant_expression_new <span class="op">(</span>GTK_TYPE_LABEL<span class="op">,</span> label<span class="op">);</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>expression <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_LABEL<span class="op">,</span> another_expression<span class="op">,</span> <span class="st">&quot;label&quot;</span><span class="op">);</span></span></code></pre></div>
<p>If <code>expression</code> is evaluated, the second parameter
<code>another_expression</code> is evaluated in advance. The value of
<code>another_expression</code> is the <code>label</code> (GtkLabel
instance). Then, <code>expression</code> looks up “label” property of
the label and the evaluation results “Hello”.</p>
<p>In the example above, the second argument of
<code>gtk_property_expression_new</code> is another expression. But the
second argument can be NULL. If it is NULL, <code>this</code> instance
is used instead. <code>this</code> is given by
<code>gtk_expression_evaluate</code> function.</p>
<p>Theres a simple program <code>exp_property_simple.c</code> in
<code>src/expression</code> directory.</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2"></a></span>
<span id="cb6-3"><a href="#cb6-3"></a><span class="dt">int</span></span>
<span id="cb6-4"><a href="#cb6-4"></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="cb6-5"><a href="#cb6-5"></a> GtkWidget <span class="op">*</span>label<span class="op">;</span></span>
<span id="cb6-6"><a href="#cb6-6"></a> GtkExpression <span class="op">*</span>expression<span class="op">;</span></span>
<span id="cb6-7"><a href="#cb6-7"></a> GValue value <span class="op">=</span> G_VALUE_INIT<span class="op">;</span></span>
<span id="cb6-8"><a href="#cb6-8"></a></span>
<span id="cb6-9"><a href="#cb6-9"></a> gtk_init <span class="op">();</span></span>
<span id="cb6-10"><a href="#cb6-10"></a> label <span class="op">=</span> gtk_label_new <span class="op">(</span><span class="st">&quot;Hello world.&quot;</span><span class="op">);</span></span>
<span id="cb6-11"><a href="#cb6-11"></a> <span class="co">/* Create an expression */</span></span>
<span id="cb6-12"><a href="#cb6-12"></a> expression <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_LABEL<span class="op">,</span> NULL<span class="op">,</span> <span class="st">&quot;label&quot;</span><span class="op">);</span></span>
<span id="cb6-13"><a href="#cb6-13"></a> <span class="co">/* Evaluate the expression */</span></span>
<span id="cb6-14"><a href="#cb6-14"></a> <span class="cf">if</span> <span class="op">(</span>gtk_expression_evaluate <span class="op">(</span>expression<span class="op">,</span> label<span class="op">,</span> <span class="op">&amp;</span>value<span class="op">))</span></span>
<span id="cb6-15"><a href="#cb6-15"></a> g_print <span class="op">(</span><span class="st">&quot;The value is %s.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">,</span> g_value_get_string <span class="op">(&amp;</span>value<span class="op">));</span></span>
<span id="cb6-16"><a href="#cb6-16"></a> <span class="cf">else</span></span>
<span id="cb6-17"><a href="#cb6-17"></a> g_print <span class="op">(</span><span class="st">&quot;The constant expression wasn&#39;t evaluated correctly.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span>
<span id="cb6-18"><a href="#cb6-18"></a> gtk_expression_unref <span class="op">(</span>expression<span class="op">);</span></span>
<span id="cb6-19"><a href="#cb6-19"></a> g_value_unset <span class="op">(&amp;</span>value<span class="op">);</span></span>
<span id="cb6-20"><a href="#cb6-20"></a></span>
<span id="cb6-21"><a href="#cb6-21"></a> <span class="cf">return</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb6-22"><a href="#cb6-22"></a><span class="op">}</span></span></code></pre></div>
<ul>
<li>9-10: <code>gtk_init</code> initializes GTK GUI toolkit. It isnt
usually necessary because the GtkApplication default startup handler
does the initialization. A GtkLabel instance is created with the text
“Hello world.”.</li>
<li>12: A property expression is created. It looks a “label” property of
a GtkLabel instance. But at the creation, no instance is given because
the second argument is NULL. The expression just knows how to take the
property from a future-given GtkLabel instance.</li>
<li>14-17: The function <code>gtk_expression_evaluate</code> evaluates
the expression with a this instance <code>label</code>. The result is
stored in the GValue <code>value</code>. The function
<code>g_value_get_string</code> gets a string from the GValue. But the
string is owned by the GValue so you must not free the string.</li>
<li>18-19: Release the expression and unset the GValue. At the same time
the string in the GValue is freed.</li>
</ul>
<p>If the second argument of <code>gtk_property_expression_new</code>
isnt NULL, it is another expression. The expression is owned by a newly
created property expression. So, when the expressions are useless, you
just release the last expression. Then it releases another expression it
has.</p>
<h2 id="closure-expression">Closure expression</h2>
<p>A closure expression calls closure when it is evaluated. A closure is
a generic representation of a callback (a pointer to a function). For
information about closure, see <a
href="https://docs.gtk.org/gobject/concepts.html#the-gobject-messaging-system">GObject
API Reference The GObject messaging system</a>. There are simple
closure example files <code>closure.c</code> and
<code>closure_each.c</code> in the <code>src/expression</code>
directory.</p>
<p>There are two types of closure expressions, GtkCClosureExpression and
GtkClosureExpression. They corresponds to GCClosure and GClosure
respectively. When you program in C language, GtkCClosureExpression and
GCClosure are appropriate.</p>
<p>A closure expression is created with
<code>gtk_cclosure_expression_new</code> function.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>GtkExpression <span class="op">*</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>gtk_cclosure_expression_new <span class="op">(</span>GType value_type<span class="op">,</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> GClosureMarshal marshal<span class="op">,</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> guint n_params<span class="op">,</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> GtkExpression <span class="op">**</span>params<span class="op">,</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> GCallback callback_func<span class="op">,</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> gpointer user_data<span class="op">,</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> GClosureNotify user_destroy<span class="op">);</span></span></code></pre></div>
<ul>
<li><code>value_type</code> is the type of the value when it is
evaluated.</li>
<li><code>marshal</code> is a marshaller. You can assign NULL. If it is
NULL, then <code>g_cclosure_marshal_generic ()</code> is used as a
marshaller. It is a generic marshaller function implemented via
libffi.</li>
<li><code>n_params</code> is the number of parameters.</li>
<li><code>params</code> points expressions for each parameter of the
call back function.</li>
<li><code>callback_func</code> is a callback function. It is given
arguments <code>this</code> and parameters above. So, if
<code>n_params</code> is 3, the number of arguments of the function is
4. (<code>this</code> and <code>params</code>. See below.)</li>
<li><code>user_data</code> is user data. You can add it for the closure.
It is like <code>user_data</code> in <code>g_signal_connect</code>. If
it is not necessary, assign NULL.</li>
<li><code>user_destroy</code> is a destroy notify for
<code>user_data</code>. It is called to destroy <code>user_data</code>
when it is no longer needed. If NULL is assigned to
<code>user_data</code>, assign NULL to <code>user_destroy</code>,
too.</li>
</ul>
<p>Call back functions have the following format.</p>
<pre><code>C-type
callback (this, param1, param2, ...)</code></pre>
<p>For example,</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>callback <span class="op">(</span>GObject <span class="op">*</span>object<span class="op">,</span> <span class="dt">int</span> x<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>s<span class="op">)</span></span></code></pre></div>
<p>The following is <code>exp_closure_simple.c</code> in
<code>src/expression</code>.</p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb10-2"><a href="#cb10-2"></a></span>
<span id="cb10-3"><a href="#cb10-3"></a><span class="dt">static</span> <span class="dt">int</span></span>
<span id="cb10-4"><a href="#cb10-4"></a>calc <span class="op">(</span>GtkLabel <span class="op">*</span>label<span class="op">)</span> <span class="op">{</span> <span class="co">/* this object */</span></span>
<span id="cb10-5"><a href="#cb10-5"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span> s<span class="op">;</span></span>
<span id="cb10-6"><a href="#cb10-6"></a> <span class="dt">int</span> i<span class="op">,</span> j<span class="op">;</span></span>
<span id="cb10-7"><a href="#cb10-7"></a></span>
<span id="cb10-8"><a href="#cb10-8"></a> s <span class="op">=</span> gtk_label_get_text <span class="op">(</span>label<span class="op">);</span> <span class="co">/* s is owned by the label. */</span></span>
<span id="cb10-9"><a href="#cb10-9"></a> sscanf <span class="op">(</span>s<span class="op">,</span> <span class="st">&quot;%d+%d&quot;</span><span class="op">,</span> <span class="op">&amp;</span>i<span class="op">,</span> <span class="op">&amp;</span>j<span class="op">);</span></span>
<span id="cb10-10"><a href="#cb10-10"></a> <span class="cf">return</span> i<span class="op">+</span>j<span class="op">;</span></span>
<span id="cb10-11"><a href="#cb10-11"></a><span class="op">}</span></span>
<span id="cb10-12"><a href="#cb10-12"></a></span>
<span id="cb10-13"><a href="#cb10-13"></a><span class="dt">int</span></span>
<span id="cb10-14"><a href="#cb10-14"></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="cb10-15"><a href="#cb10-15"></a> GtkExpression <span class="op">*</span>expression<span class="op">;</span></span>
<span id="cb10-16"><a href="#cb10-16"></a> GValue value <span class="op">=</span> G_VALUE_INIT<span class="op">;</span></span>
<span id="cb10-17"><a href="#cb10-17"></a> GtkLabel <span class="op">*</span>label<span class="op">;</span></span>
<span id="cb10-18"><a href="#cb10-18"></a></span>
<span id="cb10-19"><a href="#cb10-19"></a> gtk_init <span class="op">();</span></span>
<span id="cb10-20"><a href="#cb10-20"></a> label <span class="op">=</span> GTK_LABEL <span class="op">(</span>gtk_label_new <span class="op">(</span><span class="st">&quot;123+456&quot;</span><span class="op">));</span></span>
<span id="cb10-21"><a href="#cb10-21"></a> g_object_ref_sink <span class="op">(</span>label<span class="op">);</span></span>
<span id="cb10-22"><a href="#cb10-22"></a> expression <span class="op">=</span> gtk_cclosure_expression_new <span class="op">(</span>G_TYPE_INT<span class="op">,</span> NULL<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> NULL<span class="op">,</span></span>
<span id="cb10-23"><a href="#cb10-23"></a> G_CALLBACK <span class="op">(</span>calc<span class="op">),</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb10-24"><a href="#cb10-24"></a> <span class="cf">if</span> <span class="op">(</span>gtk_expression_evaluate <span class="op">(</span>expression<span class="op">,</span> label<span class="op">,</span> <span class="op">&amp;</span>value<span class="op">))</span> <span class="co">/* &#39;this&#39; object is the label. */</span></span>
<span id="cb10-25"><a href="#cb10-25"></a> g_print <span class="op">(</span><span class="st">&quot;%d</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">,</span> g_value_get_int <span class="op">(&amp;</span>value<span class="op">));</span></span>
<span id="cb10-26"><a href="#cb10-26"></a> <span class="cf">else</span></span>
<span id="cb10-27"><a href="#cb10-27"></a> g_print <span class="op">(</span><span class="st">&quot;The closure expression wasn&#39;t evaluated correctly.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span>
<span id="cb10-28"><a href="#cb10-28"></a> gtk_expression_unref <span class="op">(</span>expression<span class="op">);</span></span>
<span id="cb10-29"><a href="#cb10-29"></a> g_value_unset <span class="op">(&amp;</span>value<span class="op">);</span></span>
<span id="cb10-30"><a href="#cb10-30"></a> g_object_unref <span class="op">(</span>label<span class="op">);</span></span>
<span id="cb10-31"><a href="#cb10-31"></a> </span>
<span id="cb10-32"><a href="#cb10-32"></a> <span class="cf">return</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb10-33"><a href="#cb10-33"></a><span class="op">}</span></span></code></pre></div>
<ul>
2023-07-29 14:41:57 +02:00
<li>3-11: A call back function. The parameter is only one and it is a
this object. It is a GtkLabel and its label is assumed to be
“(number)+(number)”.</li>
<li>8-10: Retrieves two integers from the label and returns the sum of
them. This function has no error report. If you want to return error
report, change the return value type to be a pointer to a structure of
gboolean and integer. One for error and the other for the sum. The first
argument of <code>gtk_cclosure_expression_new</code> is
<code>G_TYPE_POINTER</code>. There is a sample program
<code>exp_closure_with_error_report</code> in
<code>src/expression</code> directory.</li>
<li>19: gtk_init initializes GTK. It is necessary for GtkLabel.</li>
<li>20: A GtkLabel instance is created with “123+456”.</li>
<li>21: The instance has floating reference. It is changed to an
ordinary reference count.</li>
<li>22-23: Create a closure expression. Its return value type is
<code>G_TYPE_INT</code> and no parameters or this object.</li>
<li>24: Evaluates the expression with the label as a this object.</li>
<li>25: If the evaluation successes, show the sum of “123+456”. Its
579.</li>
<li>27: If it fails, show an error message.</li>
<li>28-30: Releases the expression and the label. Unsets the value.</li>
</ul>
2023-07-29 14:41:57 +02:00
<p>Closure expression is flexible than other type of expression because
you can specify your own callback function.</p>
<h2 id="gtkexpressionwatch">GtkExpressionWatch</h2>
<p>GtkExpressionWatch is a structure, not an object. It represents a
watched GtkExpression. Two functions create GtkExpressionWatch
structure.</p>
<h3 id="gtk_expression_bind-function">gtk_expression_bind function</h3>
<p>This function binds the target objects property to the expression.
If the value of the expression changes, the property reflects the value
immediately.</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>GtkExpressionWatch<span class="op">*</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>gtk_expression_bind <span class="op">(</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> GtkExpression<span class="op">*</span> self<span class="op">,</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> target<span class="op">,</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">const</span> <span class="dt">char</span><span class="op">*</span> property<span class="op">,</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> this_</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div>
<p>This function takes the ownership of the expression. So, if you want
to own the expression, call <code>gtk_expression_ref ()</code> to
increase the reference count of the expression. And you should unref it
when it is useless. If you dont own the expression, you dont care
about releasing the expression.</p>
<p>An example <code>exp_bind.c</code> and <code>exp_bind.ui</code> is in
<code>src/expression</code> directory.</p>
<figure>
2023-07-29 14:41:57 +02:00
<img src="image/exp_bind.png" alt="exp_bind" />
<figcaption aria-hidden="true">exp_bind</figcaption>
</figure>
2023-07-29 14:41:57 +02:00
<p>It includes a label and a scale. If you move the slider to the right,
the scale value increases and the number on the label also increases. In
the same way, if you move it to the left, the number on the label
decreases. The label is bound to the scale value via an adjustment.</p>
<div class="sourceCode" id="cb12"><pre
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb12-1"><a href="#cb12-1"></a><span class="fu">&lt;?xml</span><span class="ot"> version=</span><span class="st">&#39;1.0&#39;</span><span class="ot"> encoding=</span><span class="st">&#39;UTF-8&#39;</span><span class="fu">?&gt;</span></span>
<span id="cb12-2"><a href="#cb12-2"></a>&lt;<span class="kw">interface</span>&gt;</span>
<span id="cb12-3"><a href="#cb12-3"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&#39;GtkApplicationWindow&#39;</span><span class="ot"> id=</span><span class="st">&#39;win&#39;</span>&gt;</span>
<span id="cb12-4"><a href="#cb12-4"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;default-width&#39;</span>&gt;600&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-5"><a href="#cb12-5"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb12-6"><a href="#cb12-6"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&#39;GtkBox&#39;</span>&gt;</span>
<span id="cb12-7"><a href="#cb12-7"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;orientation&#39;</span>&gt;GTK_ORIENTATION_VERTICAL&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-8"><a href="#cb12-8"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb12-9"><a href="#cb12-9"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&#39;GtkLabel&#39;</span><span class="ot"> id=</span><span class="st">&#39;label&#39;</span>&gt;</span>
<span id="cb12-10"><a href="#cb12-10"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;10&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-11"><a href="#cb12-11"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb12-12"><a href="#cb12-12"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb12-13"><a href="#cb12-13"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb12-14"><a href="#cb12-14"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&#39;GtkScale&#39;</span>&gt;</span>
<span id="cb12-15"><a href="#cb12-15"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;adjustment&#39;</span>&gt;</span>
<span id="cb12-16"><a href="#cb12-16"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&#39;GtkAdjustment&#39;</span><span class="ot"> id=</span><span class="st">&#39;adjustment&#39;</span>&gt;</span>
<span id="cb12-17"><a href="#cb12-17"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;upper&#39;</span>&gt;20.0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-18"><a href="#cb12-18"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;lower&#39;</span>&gt;0.0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-19"><a href="#cb12-19"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;value&#39;</span>&gt;10.0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-20"><a href="#cb12-20"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;step-increment&#39;</span>&gt;1.0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-21"><a href="#cb12-21"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;page-increment&#39;</span>&gt;5.0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-22"><a href="#cb12-22"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;page-size&#39;</span>&gt;0.0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-23"><a href="#cb12-23"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb12-24"><a href="#cb12-24"></a> &lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-25"><a href="#cb12-25"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;digits&#39;</span>&gt;0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-26"><a href="#cb12-26"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;draw-value&#39;</span>&gt;true&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-27"><a href="#cb12-27"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;has-origin&#39;</span>&gt;true&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-28"><a href="#cb12-28"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;round-digits&#39;</span>&gt;0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-29"><a href="#cb12-29"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb12-30"><a href="#cb12-30"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb12-31"><a href="#cb12-31"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb12-32"><a href="#cb12-32"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb12-33"><a href="#cb12-33"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb12-34"><a href="#cb12-34"></a>&lt;/<span class="kw">interface</span>&gt;</span></code></pre></div>
<p>The ui file describes the following parent-child relationship.</p>
<pre><code>GtkApplicationWindow (win) -- GtkBox -+- GtkLabel (label)
+- GtkScale</code></pre>
<p>Four GtkScale properties are defined.</p>
<ul>
2023-07-29 14:41:57 +02:00
<li>adjustment. GtkAdjustment provides the followings.
<ul>
2023-07-29 14:41:57 +02:00
<li>upper and lower: the range of the scale.</li>
<li>value: current value of the scale. It reflects the value of the
scale.</li>
<li>step increment and page increment: When a user press an arrow key or
page up/down key, the scale moves by the step increment or page
increment respectively.</li>
<li>page-size: When an adjustment is used with a scale, page-size is
zero.</li>
</ul></li>
2023-07-29 14:41:57 +02:00
<li>digits: The number of decimal places that are displayed in the
value.</li>
<li>draw-value: Whether the value is displayed.</li>
<li>has-origin: Whether the scale has the origin. If its true, an
orange bar appears between the origin and the current point.</li>
<li>round-digits: The number of digits to round the value to when it
changes. For example, if it is zero, the slider moves to an integer
point.</li>
</ul>
2023-07-29 14:41:57 +02:00
<div class="sourceCode" id="cb14"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb14-1"><a href="#cb14-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb14-2"><a href="#cb14-2"></a></span>
<span id="cb14-3"><a href="#cb14-3"></a>GtkExpressionWatch <span class="op">*</span>watch<span class="op">;</span></span>
<span id="cb14-4"><a href="#cb14-4"></a></span>
<span id="cb14-5"><a href="#cb14-5"></a><span class="dt">static</span> <span class="dt">int</span></span>
<span id="cb14-6"><a href="#cb14-6"></a>f2i <span class="op">(</span>GObject <span class="op">*</span>object<span class="op">,</span> <span class="dt">double</span> d<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-7"><a href="#cb14-7"></a> <span class="cf">return</span> <span class="op">(</span><span class="dt">int</span><span class="op">)</span> d<span class="op">;</span></span>
<span id="cb14-8"><a href="#cb14-8"></a><span class="op">}</span></span>
<span id="cb14-9"><a href="#cb14-9"></a></span>
<span id="cb14-10"><a href="#cb14-10"></a><span class="dt">static</span> <span class="dt">int</span></span>
<span id="cb14-11"><a href="#cb14-11"></a>close_request_cb <span class="op">(</span>GtkWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-12"><a href="#cb14-12"></a> gtk_expression_watch_unwatch <span class="op">(</span>watch<span class="op">);</span></span>
<span id="cb14-13"><a href="#cb14-13"></a> <span class="cf">return</span> false<span class="op">;</span></span>
<span id="cb14-14"><a href="#cb14-14"></a><span class="op">}</span></span>
<span id="cb14-15"><a href="#cb14-15"></a></span>
<span id="cb14-16"><a href="#cb14-16"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb14-17"><a href="#cb14-17"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-18"><a href="#cb14-18"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
<span id="cb14-19"><a href="#cb14-19"></a> gtk_window_present <span class="op">(</span>gtk_application_get_active_window<span class="op">(</span>app<span class="op">));</span></span>
<span id="cb14-20"><a href="#cb14-20"></a><span class="op">}</span></span>
<span id="cb14-21"><a href="#cb14-21"></a></span>
<span id="cb14-22"><a href="#cb14-22"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb14-23"><a href="#cb14-23"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-24"><a href="#cb14-24"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
<span id="cb14-25"><a href="#cb14-25"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
<span id="cb14-26"><a href="#cb14-26"></a> GtkWidget <span class="op">*</span>win<span class="op">,</span> <span class="op">*</span>label<span class="op">;</span></span>
<span id="cb14-27"><a href="#cb14-27"></a> GtkAdjustment <span class="op">*</span>adjustment<span class="op">;</span></span>
<span id="cb14-28"><a href="#cb14-28"></a> GtkExpression <span class="op">*</span>expression<span class="op">,</span> <span class="op">*</span>params<span class="op">[</span><span class="dv">1</span><span class="op">];</span></span>
<span id="cb14-29"><a href="#cb14-29"></a></span>
<span id="cb14-30"><a href="#cb14-30"></a> <span class="co">/* Builds a window with exp.ui resource */</span></span>
<span id="cb14-31"><a href="#cb14-31"></a> build <span class="op">=</span> gtk_builder_new_from_file <span class="op">(</span><span class="st">&quot;exp_bind.ui&quot;</span><span class="op">);</span></span>
<span id="cb14-32"><a href="#cb14-32"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;win&quot;</span><span class="op">));</span></span>
<span id="cb14-33"><a href="#cb14-33"></a> label <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;label&quot;</span><span class="op">));</span></span>
<span id="cb14-34"><a href="#cb14-34"></a> <span class="co">// scale = GTK_WIDGET (gtk_builder_get_object (build, &quot;scale&quot;));</span></span>
<span id="cb14-35"><a href="#cb14-35"></a> adjustment <span class="op">=</span> GTK_ADJUSTMENT <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;adjustment&quot;</span><span class="op">));</span></span>
<span id="cb14-36"><a href="#cb14-36"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> app<span class="op">);</span></span>
<span id="cb14-37"><a href="#cb14-37"></a> g_signal_connect <span class="op">(</span>win<span class="op">,</span> <span class="st">&quot;close-request&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>close_request_cb<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb14-38"><a href="#cb14-38"></a> g_object_unref <span class="op">(</span>build<span class="op">);</span></span>
<span id="cb14-39"><a href="#cb14-39"></a></span>
<span id="cb14-40"><a href="#cb14-40"></a> <span class="co">/* GtkExpressionWatch */</span></span>
<span id="cb14-41"><a href="#cb14-41"></a> params<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_ADJUSTMENT<span class="op">,</span> NULL<span class="op">,</span> <span class="st">&quot;value&quot;</span><span class="op">);</span></span>
<span id="cb14-42"><a href="#cb14-42"></a> expression <span class="op">=</span> gtk_cclosure_expression_new <span class="op">(</span>G_TYPE_INT<span class="op">,</span> NULL<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> params<span class="op">,</span> G_CALLBACK <span class="op">(</span>f2i<span class="op">),</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb14-43"><a href="#cb14-43"></a> watch <span class="op">=</span> gtk_expression_bind <span class="op">(</span>expression<span class="op">,</span> label<span class="op">,</span> <span class="st">&quot;label&quot;</span><span class="op">,</span> adjustment<span class="op">);</span> <span class="co">/* watch takes the ownership of the expression. */</span></span>
<span id="cb14-44"><a href="#cb14-44"></a><span class="op">}</span></span>
<span id="cb14-45"><a href="#cb14-45"></a></span>
<span id="cb14-46"><a href="#cb14-46"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.exp_watch&quot;</span></span>
<span id="cb14-47"><a href="#cb14-47"></a></span>
<span id="cb14-48"><a href="#cb14-48"></a><span class="dt">int</span></span>
<span id="cb14-49"><a href="#cb14-49"></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="cb14-50"><a href="#cb14-50"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb14-51"><a href="#cb14-51"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb14-52"><a href="#cb14-52"></a></span>
<span id="cb14-53"><a href="#cb14-53"></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="cb14-54"><a href="#cb14-54"></a></span>
<span id="cb14-55"><a href="#cb14-55"></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="cb14-56"><a href="#cb14-56"></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="cb14-57"><a href="#cb14-57"></a></span>
<span id="cb14-58"><a href="#cb14-58"></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="cb14-59"><a href="#cb14-59"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb14-60"><a href="#cb14-60"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb14-61"><a href="#cb14-61"></a><span class="op">}</span></span></code></pre></div>
<p>The point of the program is:</p>
<ul>
2023-07-29 14:41:57 +02:00
<li>41-42: Two expressions are defined. One is a property expression and
the other is a closure expression. The property expression look up the
“value”property of the adjustment instance. The closure expression just
converts the double into an integer.</li>
<li>43: <code>gtk_expression_bind</code> binds the label property of the
GtkLabel instance to the integer returned by the closure expression. It
creates a GtkExpressionWatch structure. The binding works during the
watch lives. When the window is destroyed, the scale and adjustment are
also destroyed. And the watch recognizes the value of the expression
changes and tries to change the property of the label. Obviously, it is
not a correct behavior. The watch should be unwatched before the window
is destroyed.</li>
<li>37: Connects the “close-request” signal on the window to a handler
<code>close_request_cb</code>. This signal is emitted when the close
button is clicked. The handler is called just before the window closes.
It is the right moment to make the GtkExpressionWatch unwatched.</li>
<li>10-14: “close-request” signal handler.
<code>gtk_expression_watch_unwatch (watch)</code> makes the watch stop
watching the expression. It releases the expression and calls
<code>gtk_expression_watch_unref (watch)</code> in it.</li>
</ul>
2023-07-29 14:41:57 +02:00
<p>If you want to bind a property to an expression,
<code>gtk_expression_bind</code> is the best choice. You can do it with
<code>gtk_expression_watch</code> function, but it is less suitable.</p>
<h3 id="gtk_expression_watch-function">gtk_expression_watch
function</h3>
<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>GtkExpressionWatch<span class="op">*</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>gtk_expression_watch <span class="op">(</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a> GtkExpression<span class="op">*</span> self<span class="op">,</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> this_<span class="op">,</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a> GtkExpressionNotify notify<span class="op">,</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a> gpointer user_data<span class="op">,</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a> GDestroyNotify user_destroy</span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div>
<p>The function doesnt take the ownership of the expression. It differs
from <code>gtk_expression_bind</code>. So, you need to release the
expression when it is useless. It creates a GtkExpressionWatch
structure. The third parameter <code>notify</code> is a callback to
invoke when the expression changes. You can set <code>user_data</code>
to give it to the callback. The last parameter is a function to destroy
the <code>user_data</code> when the watch is unwatched. Put NULL if you
dont need them.</p>
<p>Notify callback has the following format.</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>notify <span class="op">(</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a> gpointer user_data</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div>
<p>This function is used to do something when the value of the
expression changes. But if you want to bind a property to the value, use
<code>gtk_expression_bind</code> instead.</p>
<p>Theres a sample program <code>exp_watch.c</code> in
<code>src/expression</code> directory. It outputs the width of the
window to the standard output.</p>
<figure>
2023-07-29 14:41:57 +02:00
<img src="image/exp_watch.png" alt="exp_watch" />
<figcaption aria-hidden="true">exp_watch</figcaption>
</figure>
2023-07-29 14:41:57 +02:00
<p>When you resize the window, the width is displayed in the
terminal.</p>
<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>
<span id="cb17-3"><a href="#cb17-3"></a>GtkExpression <span class="op">*</span>expression<span class="op">;</span></span>
<span id="cb17-4"><a href="#cb17-4"></a>GtkExpressionWatch <span class="op">*</span>watch<span class="op">;</span></span>
<span id="cb17-5"><a href="#cb17-5"></a></span>
<span id="cb17-6"><a href="#cb17-6"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb17-7"><a href="#cb17-7"></a>notify <span class="op">(</span>gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-8"><a href="#cb17-8"></a> GValue value <span class="op">=</span> G_VALUE_INIT<span class="op">;</span></span>
<span id="cb17-9"><a href="#cb17-9"></a></span>
<span id="cb17-10"><a href="#cb17-10"></a> <span class="cf">if</span> <span class="op">(</span>gtk_expression_watch_evaluate <span class="op">(</span>watch<span class="op">,</span> <span class="op">&amp;</span>value<span class="op">))</span></span>
<span id="cb17-11"><a href="#cb17-11"></a> g_print <span class="op">(</span><span class="st">&quot;width = %d</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">,</span> g_value_get_int <span class="op">(&amp;</span>value<span class="op">));</span></span>
<span id="cb17-12"><a href="#cb17-12"></a> <span class="cf">else</span></span>
<span id="cb17-13"><a href="#cb17-13"></a> g_print <span class="op">(</span><span class="st">&quot;evaluation failed.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span>
<span id="cb17-14"><a href="#cb17-14"></a><span class="op">}</span></span>
<span id="cb17-15"><a href="#cb17-15"></a></span>
<span id="cb17-16"><a href="#cb17-16"></a><span class="dt">static</span> <span class="dt">int</span></span>
<span id="cb17-17"><a href="#cb17-17"></a>close_request_cb <span class="op">(</span>GtkWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-18"><a href="#cb17-18"></a> gtk_expression_watch_unwatch <span class="op">(</span>watch<span class="op">);</span></span>
<span id="cb17-19"><a href="#cb17-19"></a> gtk_expression_unref <span class="op">(</span>expression<span class="op">);</span></span>
<span id="cb17-20"><a href="#cb17-20"></a> <span class="cf">return</span> false<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="dt">static</span> <span class="dt">void</span></span>
<span id="cb17-24"><a href="#cb17-24"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-25"><a href="#cb17-25"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
<span id="cb17-26"><a href="#cb17-26"></a> gtk_window_present <span class="op">(</span>gtk_application_get_active_window<span class="op">(</span>app<span class="op">));</span></span>
<span id="cb17-27"><a href="#cb17-27"></a><span class="op">}</span></span>
<span id="cb17-28"><a href="#cb17-28"></a></span>
<span id="cb17-29"><a href="#cb17-29"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb17-30"><a href="#cb17-30"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-31"><a href="#cb17-31"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
<span id="cb17-32"><a href="#cb17-32"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
<span id="cb17-33"><a href="#cb17-33"></a></span>
<span id="cb17-34"><a href="#cb17-34"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_application_window_new <span class="op">(</span>app<span class="op">));</span></span>
<span id="cb17-35"><a href="#cb17-35"></a> g_signal_connect <span class="op">(</span>win<span class="op">,</span> <span class="st">&quot;close-request&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>close_request_cb<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb17-36"><a href="#cb17-36"></a></span>
<span id="cb17-37"><a href="#cb17-37"></a> expression <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_WINDOW<span class="op">,</span> NULL<span class="op">,</span> <span class="st">&quot;default-width&quot;</span><span class="op">);</span></span>
<span id="cb17-38"><a href="#cb17-38"></a> watch <span class="op">=</span> gtk_expression_watch <span class="op">(</span>expression<span class="op">,</span> win<span class="op">,</span> notify<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb17-39"><a href="#cb17-39"></a><span class="op">}</span></span>
<span id="cb17-40"><a href="#cb17-40"></a></span>
<span id="cb17-41"><a href="#cb17-41"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.exp_watch&quot;</span></span>
<span id="cb17-42"><a href="#cb17-42"></a></span>
<span id="cb17-43"><a href="#cb17-43"></a><span class="dt">int</span></span>
<span id="cb17-44"><a href="#cb17-44"></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="cb17-45"><a href="#cb17-45"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb17-46"><a href="#cb17-46"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb17-47"><a href="#cb17-47"></a></span>
<span id="cb17-48"><a href="#cb17-48"></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="cb17-49"><a href="#cb17-49"></a></span>
<span id="cb17-50"><a href="#cb17-50"></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="cb17-51"><a href="#cb17-51"></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="cb17-52"><a href="#cb17-52"></a></span>
<span id="cb17-53"><a href="#cb17-53"></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="cb17-54"><a href="#cb17-54"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb17-55"><a href="#cb17-55"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb17-56"><a href="#cb17-56"></a><span class="op">}</span></span></code></pre></div>
<ul>
<li>37: A property expression looks up the “default-width” property of
the window.</li>
<li>38: Create a watch structure for the expression. The callback
<code>notify</code> is called every time the value of the expression
changes. The this object is <code>win</code>, so the expression
returns the default width of the window.</li>
<li>6-14: The callback function <code>notify</code>. It uses
<code>gtk_expression_watch_evaluate</code> to get the value of the
expression. The this object is given in advance (when the watch is
created). It outputs the window width to the standard output.</li>
<li>16-21: A handler for the “close-request”signal on the window. It
stops the watch. In addition, it releases the reference to the
expression. Because <code>gtk_expression_watch</code> doesnt take the
ownership of the expression, you own it. So, the release is
necessary.</li>
</ul>
<h2 id="gtkexpression-in-ui-files">Gtkexpression in ui files</h2>
<p>GtkBuilder supports GtkExpressions. There are four tags.</p>
<ul>
<li>constant tag to create constant expression. Type attribute specifies
the type name of the value. If no type is specified, the type is assumed
to be an object. The content is the value of the expression.</li>
<li>lookup tag to create property expression. Type attribute specifies
the type of the object. Name attribute specifies the property name. The
content is an expression or object which has the property to look up. If
theres no content, this object is used.</li>
<li>closure tag to create closure expression. Type attribute specifies
the type of the returned value. Function attribute specifies the
callback function. The contents of the tag are arguments that are
expressions.</li>
<li>binding tag to bind a property to an expression. It is put in the
content of an object tag. Name attribute specifies the property name of
the object. The content is an expression.</li>
</ul>
<div class="sourceCode" id="cb18"><pre
class="sourceCode xml"><code class="sourceCode xml"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">constant</span><span class="ot"> type=</span><span class="st">&quot;gchararray&quot;</span>&gt;Hello world&lt;/<span class="kw">constant</span>&gt;</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span><span class="ot"> type=</span><span class="st">&quot;GtkLabel&quot;</span>&gt;label&lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">closure</span><span class="ot"> type=</span><span class="st">&quot;gint&quot;</span><span class="ot"> function=</span><span class="st">&quot;callback_function&quot;</span>&gt;&lt;/<span class="kw">closure</span>&gt;</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">bind</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span>&gt;win&lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>&lt;/<span class="kw">bind</span>&gt;</span></code></pre></div>
<p>These tags are usually used for GtkBuilderListItemFactory.</p>
<div class="sourceCode" id="cb19"><pre
class="sourceCode xml"><code class="sourceCode xml"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">interface</span>&gt;</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">template</span><span class="ot"> class=</span><span class="st">&quot;GtkListItem&quot;</span>&gt;</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;child&quot;</span>&gt;</span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span>&gt;</span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">binding</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;</span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;name&quot;</span><span class="ot"> type=</span><span class="st">&quot;string&quot;</span>&gt;</span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;item&quot;</span>&gt;GtkListItem&lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">binding</span>&gt;</span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">property</span>&gt;</span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">template</span>&gt;</span>
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a>&lt;/<span class="kw">interface</span>&gt;</span></code></pre></div>
<p>In the xml file above, “GtkListItem” is an instance of the
GtkListItem template. It is the this object given to the expressions.
(The information is in the <a href="https://blog.gtk.org/2020/09/">GTK
Development Blog</a>).</p>
<p>GtkBuilderListItemFactory uses GtkBuilder to build the XML data. It
sets the current object of the GtkBuilder to the GtkListItem
instance.</p>
<p>GtkBuilder calls <code>gtk_expression_bind</code> function in the
binding tag analysis. The function sets the this object like this:</p>
<ol type="1">
<li>If the binding tag has object attribute, the object will be the
this object.</li>
<li>If the current object of the GtkBuilder exists, it will be the
this object. Thats why a GtkListItem instance is the this object of
the XML data for a GtkBuilderListItemFactory.</li>
<li>Otherwise, the target object of the binding tag will be the this
object.</li>
</ol>
<p>GTK 4 document doesnt describe information about “this” object when
expressions are defined in a ui file. The information above is found
from the GTK 4 source files and it is possible to include mistakes. If
you have accurate information, please let me know.</p>
<p>A sample program <code>exp.c</code> and a ui file <code>exp.ui</code>
is in <code>src/expression</code> directory. The ui file includes
lookup, closure and bind tags. No constant tag is included. However,
constant tags are not used so often.</p>
<figure>
<img src="image/exp.png" alt="exp.c" />
<figcaption aria-hidden="true">exp.c</figcaption>
</figure>
<p>If you resize the window, the size is shown at the title of the
window. If you type characters in the entry, the same characters appear
on the label.</p>
<p>The ui file is as follows.</p>
<div class="sourceCode" id="cb20"><pre
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb20-1"><a href="#cb20-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="cb20-2"><a href="#cb20-2"></a>&lt;<span class="kw">interface</span>&gt;</span>
<span id="cb20-3"><a href="#cb20-3"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkApplicationWindow&quot;</span><span class="ot"> id=</span><span class="st">&quot;win&quot;</span>&gt;</span>
<span id="cb20-4"><a href="#cb20-4"></a> &lt;<span class="kw">binding</span><span class="ot"> name=</span><span class="st">&quot;title&quot;</span>&gt;</span>
<span id="cb20-5"><a href="#cb20-5"></a> &lt;<span class="kw">closure</span><span class="ot"> type=</span><span class="st">&quot;gchararray&quot;</span><span class="ot"> function=</span><span class="st">&quot;set_title&quot;</span>&gt;</span>
<span id="cb20-6"><a href="#cb20-6"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span><span class="ot"> type=</span><span class="st">&quot;GtkWindow&quot;</span>&gt;&lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb20-7"><a href="#cb20-7"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;default-height&quot;</span><span class="ot"> type=</span><span class="st">&quot;GtkWindow&quot;</span>&gt;&lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb20-8"><a href="#cb20-8"></a> &lt;/<span class="kw">closure</span>&gt;</span>
<span id="cb20-9"><a href="#cb20-9"></a> &lt;/<span class="kw">binding</span>&gt;</span>
<span id="cb20-10"><a href="#cb20-10"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span>&gt;600&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb20-11"><a href="#cb20-11"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;default-height&quot;</span>&gt;400&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb20-12"><a href="#cb20-12"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb20-13"><a href="#cb20-13"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkBox&quot;</span>&gt;</span>
<span id="cb20-14"><a href="#cb20-14"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;orientation&quot;</span>&gt;GTK_ORIENTATION_VERTICAL&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb20-15"><a href="#cb20-15"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb20-16"><a href="#cb20-16"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span>&gt;</span>
<span id="cb20-17"><a href="#cb20-17"></a> &lt;<span class="kw">binding</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;</span>
<span id="cb20-18"><a href="#cb20-18"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;text&quot;</span>&gt;</span>
<span id="cb20-19"><a href="#cb20-19"></a> buffer</span>
<span id="cb20-20"><a href="#cb20-20"></a> &lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb20-21"><a href="#cb20-21"></a> &lt;/<span class="kw">binding</span>&gt;</span>
<span id="cb20-22"><a href="#cb20-22"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb20-23"><a href="#cb20-23"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb20-24"><a href="#cb20-24"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb20-25"><a href="#cb20-25"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkEntry&quot;</span>&gt;</span>
<span id="cb20-26"><a href="#cb20-26"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;buffer&quot;</span>&gt;</span>
<span id="cb20-27"><a href="#cb20-27"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkEntryBuffer&quot;</span><span class="ot"> id=</span><span class="st">&quot;buffer&quot;</span>&gt;&lt;/<span class="kw">object</span>&gt;</span>
<span id="cb20-28"><a href="#cb20-28"></a> &lt;/<span class="kw">property</span>&gt;</span>
<span id="cb20-29"><a href="#cb20-29"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb20-30"><a href="#cb20-30"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb20-31"><a href="#cb20-31"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb20-32"><a href="#cb20-32"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb20-33"><a href="#cb20-33"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb20-34"><a href="#cb20-34"></a>&lt;/<span class="kw">interface</span>&gt;</span></code></pre></div>
<ul>
<li>4-9: The title property of the main window is bound to a closure
expression. Its callback function <code>set_title</code> is defined in
the C source file. It returns a string because the type attribute of the
tag is “gchararray”. Two parameters are given to the function. They are
width and height of the window. Lookup tags dont have contents, so
this object is used to look up the properties. The this object is
<code>win</code>, which is the target of the binding (<code>win</code>
includes the binding tag).</li>
<li>17-21: The “label” property of the GtkLabel instance is bound to the
“text” property of <code>buffer</code>, which is the buffer of GtkEntry
defined in line 25. If a user types characters in the entry, the same
characters appear on the label.</li>
</ul>
<p>The C source file is as follows.</p>
<div class="sourceCode" id="cb21"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb21-1"><a href="#cb21-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb21-2"><a href="#cb21-2"></a></span>
<span id="cb21-3"><a href="#cb21-3"></a><span class="dt">char</span> <span class="op">*</span></span>
<span id="cb21-4"><a href="#cb21-4"></a>set_title <span class="op">(</span>GtkWidget <span class="op">*</span>win<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">)</span> <span class="op">{</span></span>
<span id="cb21-5"><a href="#cb21-5"></a> <span class="cf">return</span> g_strdup_printf <span class="op">(</span><span class="st">&quot;%d x %d&quot;</span><span class="op">,</span> width<span class="op">,</span> height<span class="op">);</span></span>
<span id="cb21-6"><a href="#cb21-6"></a><span class="op">}</span></span>
<span id="cb21-7"><a href="#cb21-7"></a></span>
<span id="cb21-8"><a href="#cb21-8"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb21-9"><a href="#cb21-9"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb21-10"><a href="#cb21-10"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
<span id="cb21-11"><a href="#cb21-11"></a> gtk_window_present <span class="op">(</span>gtk_application_get_active_window<span class="op">(</span>app<span class="op">));</span></span>
<span id="cb21-12"><a href="#cb21-12"></a><span class="op">}</span></span>
<span id="cb21-13"><a href="#cb21-13"></a></span>
<span id="cb21-14"><a href="#cb21-14"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb21-15"><a href="#cb21-15"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb21-16"><a href="#cb21-16"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
<span id="cb21-17"><a href="#cb21-17"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
<span id="cb21-18"><a href="#cb21-18"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
<span id="cb21-19"><a href="#cb21-19"></a></span>
<span id="cb21-20"><a href="#cb21-20"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">&quot;/com/github/ToshioCP/exp/exp.ui&quot;</span><span class="op">);</span></span>
<span id="cb21-21"><a href="#cb21-21"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;win&quot;</span><span class="op">));</span></span>
<span id="cb21-22"><a href="#cb21-22"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> app<span class="op">);</span></span>
<span id="cb21-23"><a href="#cb21-23"></a> g_object_unref <span class="op">(</span>build<span class="op">);</span></span>
<span id="cb21-24"><a href="#cb21-24"></a><span class="op">}</span></span>
<span id="cb21-25"><a href="#cb21-25"></a></span>
<span id="cb21-26"><a href="#cb21-26"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.exp&quot;</span></span>
<span id="cb21-27"><a href="#cb21-27"></a></span>
<span id="cb21-28"><a href="#cb21-28"></a><span class="dt">int</span></span>
<span id="cb21-29"><a href="#cb21-29"></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="cb21-30"><a href="#cb21-30"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb21-31"><a href="#cb21-31"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb21-32"><a href="#cb21-32"></a></span>
<span id="cb21-33"><a href="#cb21-33"></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="cb21-34"><a href="#cb21-34"></a></span>
<span id="cb21-35"><a href="#cb21-35"></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="cb21-36"><a href="#cb21-36"></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="cb21-37"><a href="#cb21-37"></a></span>
<span id="cb21-38"><a href="#cb21-38"></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="cb21-39"><a href="#cb21-39"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb21-40"><a href="#cb21-40"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb21-41"><a href="#cb21-41"></a><span class="op">}</span></span></code></pre></div>
<ul>
<li>4-6: The callback function. It returns a string (w)x(h), where the w
and h are the width and height of the window. String duplication is
necessary.</li>
</ul>
<p>The C source file is very simple because almost everything is done in
the ui file.</p>
<h3 id="conversion-between-gvalues">Conversion between GValues</h3>
<p>If you bind different type properties, type conversion is
automatically done. Suppose a label property (string) is bound to
default-width property (int).</p>
<div class="sourceCode" id="cb22"><pre
class="sourceCode xml"><code class="sourceCode xml"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span>&gt;</span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">binding</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;</span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span>&gt;</span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a> win</span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">binding</span>&gt;</span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a>&lt;/<span class="kw">object</span>&gt;</span></code></pre></div>
<p>The expression created by the lookup tag returns a int type GValue.
On the other hand “label” property holds a string type GValue. When a
GValue is copied to another GValue, the type is automatically converted
if possible. If the current width is 100, an int <code>100</code> is
converted to a string <code>"100"</code>.</p>
<p>If you use <code>g_object_get</code> and <code>g_object_set</code> to
copy properties, the value is automatically converted.</p>
</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>