Merge branch 'dev'

This commit is contained in:
Toshio Sekiya 2023-01-19 21:06:35 +09:00
commit ae15d4abbd
15 changed files with 721 additions and 711 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

View file

@ -151,14 +151,14 @@ more features.</p>
lines, words and characters</h2>
<pre><code>$ LANG=C wc tfe5/meson.build tfe5/tfeapplication.c tfe5/tfe.gresource.xml tfe5/tfenotebook.c tfe5/tfenotebook.h tfetextview/tfetextview.c tfetextview/tfetextview.h tfe5/tfe.ui
10 17 294 tfe5/meson.build
101 308 3274 tfe5/tfeapplication.c
110 336 3631 tfe5/tfeapplication.c
6 9 153 tfe5/tfe.gresource.xml
145 387 3667 tfe5/tfenotebook.c
15 21 241 tfe5/tfenotebook.h
239 863 9264 tfetextview/tfetextview.c
35 60 701 tfetextview/tfetextview.h
61 100 2073 tfe5/tfe.ui
612 1765 19667 total</code></pre>
621 1793 20024 total</code></pre>
</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>

View file

@ -186,7 +186,7 @@ file</h2>
<p>If you want to install a developing version of GTK 4, you need to
build it from the source. See <a
href="https://docs.gtk.org/gtk4/building.html">Compiling the GTK
Libraries</a> secion in the GTK 4 API reference.</p>
Libraries</a> section in the GTK 4 API reference.</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>

View file

@ -5,7 +5,7 @@
<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>Gtk4 tutorial</title>
<title>GTK 4 tutorial</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
@ -112,352 +112,390 @@
</div>
</nav>
<h1 id="periodic-events">Periodic Events</h1>
<p>This chapter was written by Paul Schulz <a href="mailto:paul@mawsonlakes.org" class="email">paul@mawsonlakes.org</a>.</p>
<h2 id="how-do-we-create-an-animation">How do we create an animation?</h2>
<p>In this section we will continue to build on our previous work. We will create an analog clock application. By adding a function which periodically redraws GtkDrawingArea, the clock will be able to continuously display the time.</p>
<p>The application uses a compiled in resource file, so if the GTK4 libraries and their dependencies are installed and available, the application will run from anywhere.</p>
<p>The program also makes use of some standard mathematical and time handling functions.</p>
<p>The clocks mechanics were taken from a Cairo drawing example, using gtkmm4, which can be found <a href="https://developer-old.gnome.org/gtkmm-tutorial/stable/sec-drawing-clock-example.html.en">here</a>.</p>
<p>This chapter was written by Paul Schulz <a
href="mailto:paul@mawsonlakes.org"
class="email">paul@mawsonlakes.org</a>.</p>
<h2 id="how-do-we-create-an-animation">How do we create an
animation?</h2>
<p>In this section we will continue to build on our previous work. We
will create an analog clock application. By adding a function which
periodically redraws GtkDrawingArea, the clock will be able to
continuously display the time.</p>
<p>The application uses a compiled in resource file, so if the GTK4
libraries and their dependencies are installed and available, the
application will run from anywhere.</p>
<p>The program also makes use of some standard mathematical and time
handling functions.</p>
<p>The clocks mechanics were taken from a Cairo drawing example, using
gtkmm4, which can be found <a
href="https://developer-old.gnome.org/gtkmm-tutorial/stable/sec-drawing-clock-example.html.en">here</a>.</p>
<p>The complete code is at the end.</p>
<h2 id="drawing-the-clock-face-hour-minute-and-second-hands">Drawing the clock face, hour, minute and second hands</h2>
<p>The <code>draw_clock()</code> function does all the work. See the in-file comments for an explanation of how the Cairo drawing works.</p>
<p>For a detailed reference of what each of the Cairo functions does see the <a href="https://www.cairographics.org/manual/cairo-cairo-t.html">cairo_t reference</a>.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb1-2"><a href="#cb1-2"></a>draw_clock (GtkDrawingArea *area, cairo_t *cr, <span class="dt">int</span> width, <span class="dt">int</span> height, gpointer user_data) {</span>
<h2 id="drawing-the-clock-face-hour-minute-and-second-hands">Drawing the
clock face, hour, minute and second hands</h2>
<p>The <code>draw_clock()</code> function does all the work. See the
in-file comments for an explanation of how the Cairo drawing works.</p>
<p>For a detailed reference of what each of the Cairo functions does see
the <a
href="https://www.cairographics.org/manual/cairo-cairo-t.html">cairo_t
reference</a>.</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb1-2"><a href="#cb1-2"></a>draw_clock <span class="op">(</span>GtkDrawingArea <span class="op">*</span>area<span class="op">,</span> cairo_t <span class="op">*</span>cr<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-3"></a></span>
<span id="cb1-4"><a href="#cb1-4"></a> <span class="co">// Scale to unit square and translate (0, 0) to be (0.5, 0.5), i.e.</span></span>
<span id="cb1-5"><a href="#cb1-5"></a> <span class="co">// the center of the window</span></span>
<span id="cb1-6"><a href="#cb1-6"></a> cairo_scale(cr, width, height);</span>
<span id="cb1-7"><a href="#cb1-7"></a> cairo_translate(cr, <span class="fl">0.5</span>, <span class="fl">0.5</span>);</span>
<span id="cb1-6"><a href="#cb1-6"></a> cairo_scale<span class="op">(</span>cr<span class="op">,</span> width<span class="op">,</span> height<span class="op">);</span></span>
<span id="cb1-7"><a href="#cb1-7"></a> cairo_translate<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.5</span><span class="op">,</span> <span class="fl">0.5</span><span class="op">);</span></span>
<span id="cb1-8"><a href="#cb1-8"></a></span>
<span id="cb1-9"><a href="#cb1-9"></a> <span class="co">// Set the line width and save the cairo drawing state.</span></span>
<span id="cb1-10"><a href="#cb1-10"></a> cairo_set_line_width(cr, m_line_width);</span>
<span id="cb1-11"><a href="#cb1-11"></a> cairo_save(cr);</span>
<span id="cb1-10"><a href="#cb1-10"></a> cairo_set_line_width<span class="op">(</span>cr<span class="op">,</span> m_line_width<span class="op">);</span></span>
<span id="cb1-11"><a href="#cb1-11"></a> cairo_save<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-12"><a href="#cb1-12"></a></span>
<span id="cb1-13"><a href="#cb1-13"></a> <span class="co">// Set the background to a slightly transparent green.</span></span>
<span id="cb1-14"><a href="#cb1-14"></a> cairo_set_source_rgba(cr, <span class="fl">0.337</span>, <span class="fl">0.612</span>, <span class="fl">0.117</span>, <span class="fl">0.9</span>); <span class="co">// green</span></span>
<span id="cb1-15"><a href="#cb1-15"></a> cairo_paint(cr);</span>
<span id="cb1-14"><a href="#cb1-14"></a> cairo_set_source_rgba<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.337</span><span class="op">,</span> <span class="fl">0.612</span><span class="op">,</span> <span class="fl">0.117</span><span class="op">,</span> <span class="fl">0.9</span><span class="op">);</span> <span class="co">// green</span></span>
<span id="cb1-15"><a href="#cb1-15"></a> cairo_paint<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-16"><a href="#cb1-16"></a></span>
<span id="cb1-17"><a href="#cb1-17"></a> <span class="co">// Resore back to precious drawing state and draw the circular path</span></span>
<span id="cb1-18"><a href="#cb1-18"></a> <span class="co">// representing the clockface. Save this state (including the path) so we</span></span>
<span id="cb1-19"><a href="#cb1-19"></a> <span class="co">// can reuse it.</span></span>
<span id="cb1-20"><a href="#cb1-20"></a> cairo_restore(cr);</span>
<span id="cb1-21"><a href="#cb1-21"></a> cairo_arc(cr, <span class="fl">0.0</span>, <span class="fl">0.0</span>, m_radius, <span class="fl">0.0</span>, <span class="fl">2.0</span> * M_PI);</span>
<span id="cb1-22"><a href="#cb1-22"></a> cairo_save(cr);</span>
<span id="cb1-20"><a href="#cb1-20"></a> cairo_restore<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-21"><a href="#cb1-21"></a> cairo_arc<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> m_radius<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">2.0</span> <span class="op">*</span> M_PI<span class="op">);</span></span>
<span id="cb1-22"><a href="#cb1-22"></a> cairo_save<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-23"><a href="#cb1-23"></a></span>
<span id="cb1-24"><a href="#cb1-24"></a> <span class="co">// Fill the clockface with white</span></span>
<span id="cb1-25"><a href="#cb1-25"></a> cairo_set_source_rgba(cr, <span class="fl">1.0</span>, <span class="fl">1.0</span>, <span class="fl">1.0</span>, <span class="fl">0.8</span>);</span>
<span id="cb1-26"><a href="#cb1-26"></a> cairo_fill_preserve(cr);</span>
<span id="cb1-25"><a href="#cb1-25"></a> cairo_set_source_rgba<span class="op">(</span>cr<span class="op">,</span> <span class="fl">1.0</span><span class="op">,</span> <span class="fl">1.0</span><span class="op">,</span> <span class="fl">1.0</span><span class="op">,</span> <span class="fl">0.8</span><span class="op">);</span></span>
<span id="cb1-26"><a href="#cb1-26"></a> cairo_fill_preserve<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-27"><a href="#cb1-27"></a> <span class="co">// Restore the path, paint the outside of the clock face.</span></span>
<span id="cb1-28"><a href="#cb1-28"></a> cairo_restore(cr);</span>
<span id="cb1-29"><a href="#cb1-29"></a> cairo_stroke_preserve(cr);</span>
<span id="cb1-28"><a href="#cb1-28"></a> cairo_restore<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-29"><a href="#cb1-29"></a> cairo_stroke_preserve<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-30"><a href="#cb1-30"></a> <span class="co">// Set the &#39;clip region&#39; to the inside of the path (fill region).</span></span>
<span id="cb1-31"><a href="#cb1-31"></a> cairo_clip(cr);</span>
<span id="cb1-31"><a href="#cb1-31"></a> cairo_clip<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-32"><a href="#cb1-32"></a></span>
<span id="cb1-33"><a href="#cb1-33"></a> <span class="co">// Clock ticks</span></span>
<span id="cb1-34"><a href="#cb1-34"></a> <span class="cf">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">12</span>; i++)</span>
<span id="cb1-35"><a href="#cb1-35"></a> {</span>
<span id="cb1-34"><a href="#cb1-34"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">&lt;</span> <span class="dv">12</span><span class="op">;</span> i<span class="op">++)</span></span>
<span id="cb1-35"><a href="#cb1-35"></a> <span class="op">{</span></span>
<span id="cb1-36"><a href="#cb1-36"></a> <span class="co">// Major tick size</span></span>
<span id="cb1-37"><a href="#cb1-37"></a> <span class="dt">double</span> inset = <span class="fl">0.05</span>;</span>
<span id="cb1-37"><a href="#cb1-37"></a> <span class="dt">double</span> inset <span class="op">=</span> <span class="fl">0.05</span><span class="op">;</span></span>
<span id="cb1-38"><a href="#cb1-38"></a></span>
<span id="cb1-39"><a href="#cb1-39"></a> <span class="co">// Save the graphics state, restore after drawing tick to maintain pen</span></span>
<span id="cb1-40"><a href="#cb1-40"></a> <span class="co">// size</span></span>
<span id="cb1-41"><a href="#cb1-41"></a> cairo_save(cr);</span>
<span id="cb1-42"><a href="#cb1-42"></a> cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);</span>
<span id="cb1-41"><a href="#cb1-41"></a> cairo_save<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-42"><a href="#cb1-42"></a> cairo_set_line_cap<span class="op">(</span>cr<span class="op">,</span> CAIRO_LINE_CAP_ROUND<span class="op">);</span></span>
<span id="cb1-43"><a href="#cb1-43"></a></span>
<span id="cb1-44"><a href="#cb1-44"></a> <span class="co">// Minor ticks are shorter, and narrower.</span></span>
<span id="cb1-45"><a href="#cb1-45"></a> <span class="cf">if</span>(i % <span class="dv">3</span> != <span class="dv">0</span>)</span>
<span id="cb1-46"><a href="#cb1-46"></a> {</span>
<span id="cb1-47"><a href="#cb1-47"></a> inset *= <span class="fl">0.8</span>;</span>
<span id="cb1-48"><a href="#cb1-48"></a> cairo_set_line_width(cr, <span class="fl">0.03</span>);</span>
<span id="cb1-49"><a href="#cb1-49"></a> }</span>
<span id="cb1-45"><a href="#cb1-45"></a> <span class="cf">if</span><span class="op">(</span>i <span class="op">%</span> <span class="dv">3</span> <span class="op">!=</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb1-46"><a href="#cb1-46"></a> <span class="op">{</span></span>
<span id="cb1-47"><a href="#cb1-47"></a> inset <span class="op">*=</span> <span class="fl">0.8</span><span class="op">;</span></span>
<span id="cb1-48"><a href="#cb1-48"></a> cairo_set_line_width<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.03</span><span class="op">);</span></span>
<span id="cb1-49"><a href="#cb1-49"></a> <span class="op">}</span></span>
<span id="cb1-50"><a href="#cb1-50"></a></span>
<span id="cb1-51"><a href="#cb1-51"></a> <span class="co">// Draw tick mark</span></span>
<span id="cb1-52"><a href="#cb1-52"></a> cairo_move_to(</span>
<span id="cb1-53"><a href="#cb1-53"></a> cr,</span>
<span id="cb1-54"><a href="#cb1-54"></a> (m_radius - inset) * cos (i * M_PI / <span class="fl">6.0</span>),</span>
<span id="cb1-55"><a href="#cb1-55"></a> (m_radius - inset) * sin (i * M_PI / <span class="fl">6.0</span>));</span>
<span id="cb1-56"><a href="#cb1-56"></a> cairo_line_to(</span>
<span id="cb1-57"><a href="#cb1-57"></a> cr,</span>
<span id="cb1-58"><a href="#cb1-58"></a> m_radius * cos (i * M_PI / <span class="fl">6.0</span>),</span>
<span id="cb1-59"><a href="#cb1-59"></a> m_radius * sin (i * M_PI / <span class="fl">6.0</span>));</span>
<span id="cb1-60"><a href="#cb1-60"></a> cairo_stroke(cr);</span>
<span id="cb1-61"><a href="#cb1-61"></a> cairo_restore(cr); <span class="co">/* stack-pen-size */</span></span>
<span id="cb1-62"><a href="#cb1-62"></a> }</span>
<span id="cb1-52"><a href="#cb1-52"></a> cairo_move_to<span class="op">(</span></span>
<span id="cb1-53"><a href="#cb1-53"></a> cr<span class="op">,</span></span>
<span id="cb1-54"><a href="#cb1-54"></a> <span class="op">(</span>m_radius <span class="op">-</span> inset<span class="op">)</span> <span class="op">*</span> cos <span class="op">(</span>i <span class="op">*</span> M_PI <span class="op">/</span> <span class="fl">6.0</span><span class="op">),</span></span>
<span id="cb1-55"><a href="#cb1-55"></a> <span class="op">(</span>m_radius <span class="op">-</span> inset<span class="op">)</span> <span class="op">*</span> sin <span class="op">(</span>i <span class="op">*</span> M_PI <span class="op">/</span> <span class="fl">6.0</span><span class="op">));</span></span>
<span id="cb1-56"><a href="#cb1-56"></a> cairo_line_to<span class="op">(</span></span>
<span id="cb1-57"><a href="#cb1-57"></a> cr<span class="op">,</span></span>
<span id="cb1-58"><a href="#cb1-58"></a> m_radius <span class="op">*</span> cos <span class="op">(</span>i <span class="op">*</span> M_PI <span class="op">/</span> <span class="fl">6.0</span><span class="op">),</span></span>
<span id="cb1-59"><a href="#cb1-59"></a> m_radius <span class="op">*</span> sin <span class="op">(</span>i <span class="op">*</span> M_PI <span class="op">/</span> <span class="fl">6.0</span><span class="op">));</span></span>
<span id="cb1-60"><a href="#cb1-60"></a> cairo_stroke<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-61"><a href="#cb1-61"></a> cairo_restore<span class="op">(</span>cr<span class="op">);</span> <span class="co">/* stack-pen-size */</span></span>
<span id="cb1-62"><a href="#cb1-62"></a> <span class="op">}</span></span>
<span id="cb1-63"><a href="#cb1-63"></a></span>
<span id="cb1-64"><a href="#cb1-64"></a> <span class="co">// Draw the analog hands</span></span>
<span id="cb1-65"><a href="#cb1-65"></a></span>
<span id="cb1-66"><a href="#cb1-66"></a> <span class="co">// Get the current Unix time, convert to the local time and break into time</span></span>
<span id="cb1-67"><a href="#cb1-67"></a> <span class="co">// structure to read various time parts.</span></span>
<span id="cb1-68"><a href="#cb1-68"></a> <span class="dt">time_t</span> rawtime;</span>
<span id="cb1-69"><a href="#cb1-69"></a> time(&amp;rawtime);</span>
<span id="cb1-70"><a href="#cb1-70"></a> <span class="kw">struct</span> tm * timeinfo = localtime (&amp;rawtime);</span>
<span id="cb1-68"><a href="#cb1-68"></a> <span class="dt">time_t</span> rawtime<span class="op">;</span></span>
<span id="cb1-69"><a href="#cb1-69"></a> time<span class="op">(&amp;</span>rawtime<span class="op">);</span></span>
<span id="cb1-70"><a href="#cb1-70"></a> <span class="kw">struct</span> tm <span class="op">*</span> timeinfo <span class="op">=</span> localtime <span class="op">(&amp;</span>rawtime<span class="op">);</span></span>
<span id="cb1-71"><a href="#cb1-71"></a></span>
<span id="cb1-72"><a href="#cb1-72"></a> <span class="co">// Calculate the angles of the hands of our clock</span></span>
<span id="cb1-73"><a href="#cb1-73"></a> <span class="dt">double</span> hours = timeinfo-&gt;tm_hour * M_PI / <span class="fl">6.0</span>;</span>
<span id="cb1-74"><a href="#cb1-74"></a> <span class="dt">double</span> minutes = timeinfo-&gt;tm_min * M_PI / <span class="fl">30.0</span>;</span>
<span id="cb1-75"><a href="#cb1-75"></a> <span class="dt">double</span> seconds = timeinfo-&gt;tm_sec * M_PI / <span class="fl">30.0</span>;</span>
<span id="cb1-73"><a href="#cb1-73"></a> <span class="dt">double</span> hours <span class="op">=</span> timeinfo<span class="op">-&gt;</span>tm_hour <span class="op">*</span> M_PI <span class="op">/</span> <span class="fl">6.0</span><span class="op">;</span></span>
<span id="cb1-74"><a href="#cb1-74"></a> <span class="dt">double</span> minutes <span class="op">=</span> timeinfo<span class="op">-&gt;</span>tm_min <span class="op">*</span> M_PI <span class="op">/</span> <span class="fl">30.0</span><span class="op">;</span></span>
<span id="cb1-75"><a href="#cb1-75"></a> <span class="dt">double</span> seconds <span class="op">=</span> timeinfo<span class="op">-&gt;</span>tm_sec <span class="op">*</span> M_PI <span class="op">/</span> <span class="fl">30.0</span><span class="op">;</span></span>
<span id="cb1-76"><a href="#cb1-76"></a></span>
<span id="cb1-77"><a href="#cb1-77"></a> <span class="co">// Save the graphics state</span></span>
<span id="cb1-78"><a href="#cb1-78"></a> cairo_save(cr);</span>
<span id="cb1-79"><a href="#cb1-79"></a> cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);</span>
<span id="cb1-78"><a href="#cb1-78"></a> cairo_save<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-79"><a href="#cb1-79"></a> cairo_set_line_cap<span class="op">(</span>cr<span class="op">,</span> CAIRO_LINE_CAP_ROUND<span class="op">);</span></span>
<span id="cb1-80"><a href="#cb1-80"></a></span>
<span id="cb1-81"><a href="#cb1-81"></a> cairo_save(cr);</span>
<span id="cb1-81"><a href="#cb1-81"></a> cairo_save<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-82"><a href="#cb1-82"></a></span>
<span id="cb1-83"><a href="#cb1-83"></a> <span class="co">// Draw the seconds hand</span></span>
<span id="cb1-84"><a href="#cb1-84"></a> cairo_set_line_width(cr, m_line_width / <span class="fl">3.0</span>);</span>
<span id="cb1-85"><a href="#cb1-85"></a> cairo_set_source_rgba(cr, <span class="fl">0.7</span>, <span class="fl">0.7</span>, <span class="fl">0.7</span>, <span class="fl">0.8</span>); <span class="co">// gray</span></span>
<span id="cb1-86"><a href="#cb1-86"></a> cairo_move_to(cr, <span class="fl">0.0</span>, <span class="fl">0.0</span>);</span>
<span id="cb1-87"><a href="#cb1-87"></a> cairo_line_to(cr,</span>
<span id="cb1-88"><a href="#cb1-88"></a> sin(seconds) * (m_radius * <span class="fl">0.9</span>),</span>
<span id="cb1-89"><a href="#cb1-89"></a> -cos(seconds) * (m_radius * <span class="fl">0.9</span>));</span>
<span id="cb1-90"><a href="#cb1-90"></a> cairo_stroke(cr);</span>
<span id="cb1-91"><a href="#cb1-91"></a> cairo_restore(cr);</span>
<span id="cb1-84"><a href="#cb1-84"></a> cairo_set_line_width<span class="op">(</span>cr<span class="op">,</span> m_line_width <span class="op">/</span> <span class="fl">3.0</span><span class="op">);</span></span>
<span id="cb1-85"><a href="#cb1-85"></a> cairo_set_source_rgba<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.7</span><span class="op">,</span> <span class="fl">0.7</span><span class="op">,</span> <span class="fl">0.7</span><span class="op">,</span> <span class="fl">0.8</span><span class="op">);</span> <span class="co">// gray</span></span>
<span id="cb1-86"><a href="#cb1-86"></a> cairo_move_to<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">);</span></span>
<span id="cb1-87"><a href="#cb1-87"></a> cairo_line_to<span class="op">(</span>cr<span class="op">,</span></span>
<span id="cb1-88"><a href="#cb1-88"></a> sin<span class="op">(</span>seconds<span class="op">)</span> <span class="op">*</span> <span class="op">(</span>m_radius <span class="op">*</span> <span class="fl">0.9</span><span class="op">),</span></span>
<span id="cb1-89"><a href="#cb1-89"></a> <span class="op">-</span>cos<span class="op">(</span>seconds<span class="op">)</span> <span class="op">*</span> <span class="op">(</span>m_radius <span class="op">*</span> <span class="fl">0.9</span><span class="op">));</span></span>
<span id="cb1-90"><a href="#cb1-90"></a> cairo_stroke<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-91"><a href="#cb1-91"></a> cairo_restore<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-92"><a href="#cb1-92"></a></span>
<span id="cb1-93"><a href="#cb1-93"></a> <span class="co">// Draw the minutes hand</span></span>
<span id="cb1-94"><a href="#cb1-94"></a> cairo_set_source_rgba(cr, <span class="fl">0.117</span>, <span class="fl">0.337</span>, <span class="fl">0.612</span>, <span class="fl">0.9</span>); <span class="co">// blue</span></span>
<span id="cb1-95"><a href="#cb1-95"></a> cairo_move_to(cr, <span class="dv">0</span>, <span class="dv">0</span>);</span>
<span id="cb1-96"><a href="#cb1-96"></a> cairo_line_to(cr,</span>
<span id="cb1-97"><a href="#cb1-97"></a> sin(minutes + seconds / <span class="dv">60</span>) * (m_radius * <span class="fl">0.8</span>),</span>
<span id="cb1-98"><a href="#cb1-98"></a> -cos(minutes + seconds / <span class="dv">60</span>) * (m_radius * <span class="fl">0.8</span>));</span>
<span id="cb1-99"><a href="#cb1-99"></a> cairo_stroke(cr);</span>
<span id="cb1-94"><a href="#cb1-94"></a> cairo_set_source_rgba<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.117</span><span class="op">,</span> <span class="fl">0.337</span><span class="op">,</span> <span class="fl">0.612</span><span class="op">,</span> <span class="fl">0.9</span><span class="op">);</span> <span class="co">// blue</span></span>
<span id="cb1-95"><a href="#cb1-95"></a> cairo_move_to<span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
<span id="cb1-96"><a href="#cb1-96"></a> cairo_line_to<span class="op">(</span>cr<span class="op">,</span></span>
<span id="cb1-97"><a href="#cb1-97"></a> sin<span class="op">(</span>minutes <span class="op">+</span> seconds <span class="op">/</span> <span class="dv">60</span><span class="op">)</span> <span class="op">*</span> <span class="op">(</span>m_radius <span class="op">*</span> <span class="fl">0.8</span><span class="op">),</span></span>
<span id="cb1-98"><a href="#cb1-98"></a> <span class="op">-</span>cos<span class="op">(</span>minutes <span class="op">+</span> seconds <span class="op">/</span> <span class="dv">60</span><span class="op">)</span> <span class="op">*</span> <span class="op">(</span>m_radius <span class="op">*</span> <span class="fl">0.8</span><span class="op">));</span></span>
<span id="cb1-99"><a href="#cb1-99"></a> cairo_stroke<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-100"><a href="#cb1-100"></a></span>
<span id="cb1-101"><a href="#cb1-101"></a> <span class="co">// draw the hours hand</span></span>
<span id="cb1-102"><a href="#cb1-102"></a> cairo_set_source_rgba(cr, <span class="fl">0.337</span>, <span class="fl">0.612</span>, <span class="fl">0.117</span>, <span class="fl">0.9</span>); <span class="co">// green</span></span>
<span id="cb1-103"><a href="#cb1-103"></a> cairo_move_to(cr, <span class="fl">0.0</span>, <span class="fl">0.0</span>);</span>
<span id="cb1-104"><a href="#cb1-104"></a> cairo_line_to(cr,</span>
<span id="cb1-105"><a href="#cb1-105"></a> sin(hours + minutes / <span class="fl">12.0</span>) * (m_radius * <span class="fl">0.5</span>),</span>
<span id="cb1-106"><a href="#cb1-106"></a> -cos(hours + minutes / <span class="fl">12.0</span>) * (m_radius * <span class="fl">0.5</span>));</span>
<span id="cb1-107"><a href="#cb1-107"></a> cairo_stroke(cr);</span>
<span id="cb1-108"><a href="#cb1-108"></a> cairo_restore(cr);</span>
<span id="cb1-102"><a href="#cb1-102"></a> cairo_set_source_rgba<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.337</span><span class="op">,</span> <span class="fl">0.612</span><span class="op">,</span> <span class="fl">0.117</span><span class="op">,</span> <span class="fl">0.9</span><span class="op">);</span> <span class="co">// green</span></span>
<span id="cb1-103"><a href="#cb1-103"></a> cairo_move_to<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">);</span></span>
<span id="cb1-104"><a href="#cb1-104"></a> cairo_line_to<span class="op">(</span>cr<span class="op">,</span></span>
<span id="cb1-105"><a href="#cb1-105"></a> sin<span class="op">(</span>hours <span class="op">+</span> minutes <span class="op">/</span> <span class="fl">12.0</span><span class="op">)</span> <span class="op">*</span> <span class="op">(</span>m_radius <span class="op">*</span> <span class="fl">0.5</span><span class="op">),</span></span>
<span id="cb1-106"><a href="#cb1-106"></a> <span class="op">-</span>cos<span class="op">(</span>hours <span class="op">+</span> minutes <span class="op">/</span> <span class="fl">12.0</span><span class="op">)</span> <span class="op">*</span> <span class="op">(</span>m_radius <span class="op">*</span> <span class="fl">0.5</span><span class="op">));</span></span>
<span id="cb1-107"><a href="#cb1-107"></a> cairo_stroke<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-108"><a href="#cb1-108"></a> cairo_restore<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-109"><a href="#cb1-109"></a></span>
<span id="cb1-110"><a href="#cb1-110"></a> <span class="co">// Draw a little dot in the middle</span></span>
<span id="cb1-111"><a href="#cb1-111"></a> cairo_arc(cr, <span class="fl">0.0</span>, <span class="fl">0.0</span>, m_line_width / <span class="fl">3.0</span>, <span class="fl">0.0</span>, <span class="fl">2.0</span> * M_PI);</span>
<span id="cb1-112"><a href="#cb1-112"></a> cairo_fill(cr);</span>
<span id="cb1-113"><a href="#cb1-113"></a>}</span></code></pre></div>
<p>In order for the clock to be drawn, the drawing function <code>draw_clock()</code> needs to be registered with GTK4. This is done in the <code>app_activate()</code> function (on line 24).</p>
<p>Whenever the application needs to redraw the GtkDrawingArea, it will now call <code>draw_clock()</code>.</p>
<p>There is still a problem though. In order to animate the clock we need to also tell the application that the clock needs to be redrawn every second. This process starts by registering (on the next line, line 15) a timeout function with <code>g_timeout_add()</code> that will wakeup and run another function <code>time_handler</code>, every second (or 1000ms).</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="dt">static</span> <span class="dt">void</span></span>
<span id="cb2-2"><a href="#cb2-2"></a>app_activate (GApplication *app, gpointer user_data) {</span>
<span id="cb2-3"><a href="#cb2-3"></a> GtkWidget *win;</span>
<span id="cb2-4"><a href="#cb2-4"></a> GtkWidget *clock;</span>
<span id="cb2-5"><a href="#cb2-5"></a> GtkBuilder *build;</span>
<span id="cb1-111"><a href="#cb1-111"></a> cairo_arc<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> m_line_width <span class="op">/</span> <span class="fl">3.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">2.0</span> <span class="op">*</span> M_PI<span class="op">);</span></span>
<span id="cb1-112"><a href="#cb1-112"></a> cairo_fill<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb1-113"><a href="#cb1-113"></a><span class="op">}</span></span></code></pre></div>
<p>In order for the clock to be drawn, the drawing function
<code>draw_clock()</code> needs to be registered with GTK4. This is done
in the <code>app_activate()</code> function (on line 24).</p>
<p>Whenever the application needs to redraw the GtkDrawingArea, it will
now call <code>draw_clock()</code>.</p>
<p>There is still a problem though. In order to animate the clock we
need to also tell the application that the clock needs to be redrawn
every second. This process starts by registering (on the next line, line
15) a timeout function with <code>g_timeout_add()</code> that will
wakeup and run another function <code>time_handler</code>, every second
(or 1000ms).</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="dt">static</span> <span class="dt">void</span></span>
<span id="cb2-2"><a href="#cb2-2"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-3"><a href="#cb2-3"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
<span id="cb2-4"><a href="#cb2-4"></a> GtkWidget <span class="op">*</span>clock<span class="op">;</span></span>
<span id="cb2-5"><a href="#cb2-5"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
<span id="cb2-6"><a href="#cb2-6"></a></span>
<span id="cb2-7"><a href="#cb2-7"></a> build = gtk_builder_new_from_resource (<span class="st">&quot;/com/github/ToshioCP/tfc/tfc.ui&quot;</span>);</span>
<span id="cb2-8"><a href="#cb2-8"></a> win = GTK_WIDGET (gtk_builder_get_object (build, <span class="st">&quot;win&quot;</span>));</span>
<span id="cb2-9"><a href="#cb2-9"></a> gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));</span>
<span id="cb2-7"><a href="#cb2-7"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">&quot;/com/github/ToshioCP/tfc/tfc.ui&quot;</span><span class="op">);</span></span>
<span id="cb2-8"><a href="#cb2-8"></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="cb2-9"><a href="#cb2-9"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> GTK_APPLICATION <span class="op">(</span>app<span class="op">));</span></span>
<span id="cb2-10"><a href="#cb2-10"></a></span>
<span id="cb2-11"><a href="#cb2-11"></a> clock = GTK_WIDGET (gtk_builder_get_object (build, <span class="st">&quot;clock&quot;</span>));</span>
<span id="cb2-12"><a href="#cb2-12"></a> g_object_unref(build);</span>
<span id="cb2-11"><a href="#cb2-11"></a> clock <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;clock&quot;</span><span class="op">));</span></span>
<span id="cb2-12"><a href="#cb2-12"></a> g_object_unref<span class="op">(</span>build<span class="op">);</span></span>
<span id="cb2-13"><a href="#cb2-13"></a></span>
<span id="cb2-14"><a href="#cb2-14"></a> gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA (clock), draw_clock, NULL, NULL);</span>
<span id="cb2-15"><a href="#cb2-15"></a> g_timeout_add(<span class="dv">1000</span>, (GSourceFunc) time_handler, (gpointer) clock);</span>
<span id="cb2-16"><a href="#cb2-16"></a> gtk_widget_show(win);</span>
<span id="cb2-14"><a href="#cb2-14"></a> gtk_drawing_area_set_draw_func<span class="op">(</span>GTK_DRAWING_AREA <span class="op">(</span>clock<span class="op">),</span> draw_clock<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb2-15"><a href="#cb2-15"></a> g_timeout_add<span class="op">(</span><span class="dv">1000</span><span class="op">,</span> <span class="op">(</span>GSourceFunc<span class="op">)</span> time_handler<span class="op">,</span> <span class="op">(</span>gpointer<span class="op">)</span> clock<span class="op">);</span></span>
<span id="cb2-16"><a href="#cb2-16"></a> gtk_widget_show<span class="op">(</span>win<span class="op">);</span></span>
<span id="cb2-17"><a href="#cb2-17"></a></span>
<span id="cb2-18"><a href="#cb2-18"></a>}</span></code></pre></div>
<p>Our <code>time_handler()</code> function is very simple, as it just calls <code>gtk_widget_queue_draw()</code> which schedules a redraw of the widget.</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>gboolean</span>
<span id="cb3-2"><a href="#cb3-2"></a>time_handler(GtkWidget* widget) {</span>
<span id="cb3-3"><a href="#cb3-3"></a> gtk_widget_queue_draw(widget);</span>
<span id="cb2-18"><a href="#cb2-18"></a><span class="op">}</span></span></code></pre></div>
<p>Our <code>time_handler()</code> function is very simple, as it just
calls <code>gtk_widget_queue_draw()</code> which schedules a redraw of
the widget.</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>gboolean</span>
<span id="cb3-2"><a href="#cb3-2"></a>time_handler<span class="op">(</span>GtkWidget<span class="op">*</span> widget<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-3"><a href="#cb3-3"></a> gtk_widget_queue_draw<span class="op">(</span>widget<span class="op">);</span></span>
<span id="cb3-4"><a href="#cb3-4"></a></span>
<span id="cb3-5"><a href="#cb3-5"></a> <span class="cf">return</span> TRUE;</span>
<span id="cb3-6"><a href="#cb3-6"></a>}</span></code></pre></div>
<p>.. and that is all there is to it. If you compile and run the example you will get a ticking analog clock.</p>
<p>If you get this working, you can try modifying some of the code in <code>draw_clock()</code> to tweak the application (such as change the color or size and length of the hands) or even add text, or create a digital clock.</p>
<span id="cb3-5"><a href="#cb3-5"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span>
<span id="cb3-6"><a href="#cb3-6"></a><span class="op">}</span></span></code></pre></div>
<p>.. and that is all there is to it. If you compile and run the example
you will get a ticking analog clock.</p>
<p>If you get this working, you can try modifying some of the code in
<code>draw_clock()</code> to tweak the application (such as change the
color or size and length of the hands) or even add text, or create a
digital clock.</p>
<h2 id="the-complete-code">The Complete code</h2>
<p>You can find the source files in the <code>tfc</code> directory. it can be compiled with <code>./comp tfc</code>.</p>
<p>You can find the source files in the <code>tfc</code> directory. it
can be compiled with <code>./comp tfc</code>.</p>
<p><code>tfc.c</code></p>
<div class="sourceCode" id="cb4"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<div class="sourceCode" id="cb4"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2"></a><span class="pp">#include </span><span class="im">&lt;math.h&gt;</span></span>
<span id="cb4-3"><a href="#cb4-3"></a><span class="pp">#include </span><span class="im">&lt;time.h&gt;</span></span>
<span id="cb4-4"><a href="#cb4-4"></a></span>
<span id="cb4-5"><a href="#cb4-5"></a><span class="dt">float</span> m_radius = <span class="fl">0.42</span>;</span>
<span id="cb4-6"><a href="#cb4-6"></a><span class="dt">float</span> m_line_width = <span class="fl">0.05</span>;</span>
<span id="cb4-5"><a href="#cb4-5"></a><span class="dt">float</span> m_radius <span class="op">=</span> <span class="fl">0.42</span><span class="op">;</span></span>
<span id="cb4-6"><a href="#cb4-6"></a><span class="dt">float</span> m_line_width <span class="op">=</span> <span class="fl">0.05</span><span class="op">;</span></span>
<span id="cb4-7"><a href="#cb4-7"></a></span>
<span id="cb4-8"><a href="#cb4-8"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-9"><a href="#cb4-9"></a>draw_clock (GtkDrawingArea *area, cairo_t *cr, <span class="dt">int</span> width, <span class="dt">int</span> height, gpointer user_data) {</span>
<span id="cb4-9"><a href="#cb4-9"></a>draw_clock <span class="op">(</span>GtkDrawingArea <span class="op">*</span>area<span class="op">,</span> cairo_t <span class="op">*</span>cr<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-10"><a href="#cb4-10"></a></span>
<span id="cb4-11"><a href="#cb4-11"></a> <span class="co">// Scale to unit square and translate (0, 0) to be (0.5, 0.5), i.e.</span></span>
<span id="cb4-12"><a href="#cb4-12"></a> <span class="co">// the center of the window</span></span>
<span id="cb4-13"><a href="#cb4-13"></a> cairo_scale(cr, width, height);</span>
<span id="cb4-14"><a href="#cb4-14"></a> cairo_translate(cr, <span class="fl">0.5</span>, <span class="fl">0.5</span>);</span>
<span id="cb4-13"><a href="#cb4-13"></a> cairo_scale<span class="op">(</span>cr<span class="op">,</span> width<span class="op">,</span> height<span class="op">);</span></span>
<span id="cb4-14"><a href="#cb4-14"></a> cairo_translate<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.5</span><span class="op">,</span> <span class="fl">0.5</span><span class="op">);</span></span>
<span id="cb4-15"><a href="#cb4-15"></a></span>
<span id="cb4-16"><a href="#cb4-16"></a> <span class="co">// Set the line width and save the cairo drawing state.</span></span>
<span id="cb4-17"><a href="#cb4-17"></a> cairo_set_line_width(cr, m_line_width);</span>
<span id="cb4-18"><a href="#cb4-18"></a> cairo_save(cr);</span>
<span id="cb4-17"><a href="#cb4-17"></a> cairo_set_line_width<span class="op">(</span>cr<span class="op">,</span> m_line_width<span class="op">);</span></span>
<span id="cb4-18"><a href="#cb4-18"></a> cairo_save<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-19"><a href="#cb4-19"></a></span>
<span id="cb4-20"><a href="#cb4-20"></a> <span class="co">// Set the background to a slightly transparent green.</span></span>
<span id="cb4-21"><a href="#cb4-21"></a> cairo_set_source_rgba(cr, <span class="fl">0.337</span>, <span class="fl">0.612</span>, <span class="fl">0.117</span>, <span class="fl">0.9</span>); <span class="co">// green</span></span>
<span id="cb4-22"><a href="#cb4-22"></a> cairo_paint(cr);</span>
<span id="cb4-21"><a href="#cb4-21"></a> cairo_set_source_rgba<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.337</span><span class="op">,</span> <span class="fl">0.612</span><span class="op">,</span> <span class="fl">0.117</span><span class="op">,</span> <span class="fl">0.9</span><span class="op">);</span> <span class="co">// green</span></span>
<span id="cb4-22"><a href="#cb4-22"></a> cairo_paint<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-23"><a href="#cb4-23"></a></span>
<span id="cb4-24"><a href="#cb4-24"></a> <span class="co">// Resore back to precious drawing state and draw the circular path</span></span>
<span id="cb4-25"><a href="#cb4-25"></a> <span class="co">// representing the clockface. Save this state (including the path) so we</span></span>
<span id="cb4-26"><a href="#cb4-26"></a> <span class="co">// can reuse it.</span></span>
<span id="cb4-27"><a href="#cb4-27"></a> cairo_restore(cr);</span>
<span id="cb4-28"><a href="#cb4-28"></a> cairo_arc(cr, <span class="fl">0.0</span>, <span class="fl">0.0</span>, m_radius, <span class="fl">0.0</span>, <span class="fl">2.0</span> * M_PI);</span>
<span id="cb4-29"><a href="#cb4-29"></a> cairo_save(cr);</span>
<span id="cb4-27"><a href="#cb4-27"></a> cairo_restore<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-28"><a href="#cb4-28"></a> cairo_arc<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> m_radius<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">2.0</span> <span class="op">*</span> M_PI<span class="op">);</span></span>
<span id="cb4-29"><a href="#cb4-29"></a> cairo_save<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-30"><a href="#cb4-30"></a></span>
<span id="cb4-31"><a href="#cb4-31"></a> <span class="co">// Fill the clockface with white</span></span>
<span id="cb4-32"><a href="#cb4-32"></a> cairo_set_source_rgba(cr, <span class="fl">1.0</span>, <span class="fl">1.0</span>, <span class="fl">1.0</span>, <span class="fl">0.8</span>);</span>
<span id="cb4-33"><a href="#cb4-33"></a> cairo_fill_preserve(cr);</span>
<span id="cb4-32"><a href="#cb4-32"></a> cairo_set_source_rgba<span class="op">(</span>cr<span class="op">,</span> <span class="fl">1.0</span><span class="op">,</span> <span class="fl">1.0</span><span class="op">,</span> <span class="fl">1.0</span><span class="op">,</span> <span class="fl">0.8</span><span class="op">);</span></span>
<span id="cb4-33"><a href="#cb4-33"></a> cairo_fill_preserve<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-34"><a href="#cb4-34"></a> <span class="co">// Restore the path, paint the outside of the clock face.</span></span>
<span id="cb4-35"><a href="#cb4-35"></a> cairo_restore(cr);</span>
<span id="cb4-36"><a href="#cb4-36"></a> cairo_stroke_preserve(cr);</span>
<span id="cb4-35"><a href="#cb4-35"></a> cairo_restore<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-36"><a href="#cb4-36"></a> cairo_stroke_preserve<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-37"><a href="#cb4-37"></a> <span class="co">// Set the &#39;clip region&#39; to the inside of the path (fill region).</span></span>
<span id="cb4-38"><a href="#cb4-38"></a> cairo_clip(cr);</span>
<span id="cb4-38"><a href="#cb4-38"></a> cairo_clip<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-39"><a href="#cb4-39"></a></span>
<span id="cb4-40"><a href="#cb4-40"></a> <span class="co">// Clock ticks</span></span>
<span id="cb4-41"><a href="#cb4-41"></a> <span class="cf">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">12</span>; i++)</span>
<span id="cb4-42"><a href="#cb4-42"></a> {</span>
<span id="cb4-41"><a href="#cb4-41"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">&lt;</span> <span class="dv">12</span><span class="op">;</span> i<span class="op">++)</span></span>
<span id="cb4-42"><a href="#cb4-42"></a> <span class="op">{</span></span>
<span id="cb4-43"><a href="#cb4-43"></a> <span class="co">// Major tick size</span></span>
<span id="cb4-44"><a href="#cb4-44"></a> <span class="dt">double</span> inset = <span class="fl">0.05</span>;</span>
<span id="cb4-44"><a href="#cb4-44"></a> <span class="dt">double</span> inset <span class="op">=</span> <span class="fl">0.05</span><span class="op">;</span></span>
<span id="cb4-45"><a href="#cb4-45"></a></span>
<span id="cb4-46"><a href="#cb4-46"></a> <span class="co">// Save the graphics state, restore after drawing tick to maintain pen</span></span>
<span id="cb4-47"><a href="#cb4-47"></a> <span class="co">// size</span></span>
<span id="cb4-48"><a href="#cb4-48"></a> cairo_save(cr);</span>
<span id="cb4-49"><a href="#cb4-49"></a> cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);</span>
<span id="cb4-48"><a href="#cb4-48"></a> cairo_save<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-49"><a href="#cb4-49"></a> cairo_set_line_cap<span class="op">(</span>cr<span class="op">,</span> CAIRO_LINE_CAP_ROUND<span class="op">);</span></span>
<span id="cb4-50"><a href="#cb4-50"></a></span>
<span id="cb4-51"><a href="#cb4-51"></a> <span class="co">// Minor ticks are shorter, and narrower.</span></span>
<span id="cb4-52"><a href="#cb4-52"></a> <span class="cf">if</span>(i % <span class="dv">3</span> != <span class="dv">0</span>)</span>
<span id="cb4-53"><a href="#cb4-53"></a> {</span>
<span id="cb4-54"><a href="#cb4-54"></a> inset *= <span class="fl">0.8</span>;</span>
<span id="cb4-55"><a href="#cb4-55"></a> cairo_set_line_width(cr, <span class="fl">0.03</span>);</span>
<span id="cb4-56"><a href="#cb4-56"></a> }</span>
<span id="cb4-52"><a href="#cb4-52"></a> <span class="cf">if</span><span class="op">(</span>i <span class="op">%</span> <span class="dv">3</span> <span class="op">!=</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb4-53"><a href="#cb4-53"></a> <span class="op">{</span></span>
<span id="cb4-54"><a href="#cb4-54"></a> inset <span class="op">*=</span> <span class="fl">0.8</span><span class="op">;</span></span>
<span id="cb4-55"><a href="#cb4-55"></a> cairo_set_line_width<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.03</span><span class="op">);</span></span>
<span id="cb4-56"><a href="#cb4-56"></a> <span class="op">}</span></span>
<span id="cb4-57"><a href="#cb4-57"></a></span>
<span id="cb4-58"><a href="#cb4-58"></a> <span class="co">// Draw tick mark</span></span>
<span id="cb4-59"><a href="#cb4-59"></a> cairo_move_to(</span>
<span id="cb4-60"><a href="#cb4-60"></a> cr,</span>
<span id="cb4-61"><a href="#cb4-61"></a> (m_radius - inset) * cos (i * M_PI / <span class="fl">6.0</span>),</span>
<span id="cb4-62"><a href="#cb4-62"></a> (m_radius - inset) * sin (i * M_PI / <span class="fl">6.0</span>));</span>
<span id="cb4-63"><a href="#cb4-63"></a> cairo_line_to(</span>
<span id="cb4-64"><a href="#cb4-64"></a> cr,</span>
<span id="cb4-65"><a href="#cb4-65"></a> m_radius * cos (i * M_PI / <span class="fl">6.0</span>),</span>
<span id="cb4-66"><a href="#cb4-66"></a> m_radius * sin (i * M_PI / <span class="fl">6.0</span>));</span>
<span id="cb4-67"><a href="#cb4-67"></a> cairo_stroke(cr);</span>
<span id="cb4-68"><a href="#cb4-68"></a> cairo_restore(cr); <span class="co">/* stack-pen-size */</span></span>
<span id="cb4-69"><a href="#cb4-69"></a> }</span>
<span id="cb4-59"><a href="#cb4-59"></a> cairo_move_to<span class="op">(</span></span>
<span id="cb4-60"><a href="#cb4-60"></a> cr<span class="op">,</span></span>
<span id="cb4-61"><a href="#cb4-61"></a> <span class="op">(</span>m_radius <span class="op">-</span> inset<span class="op">)</span> <span class="op">*</span> cos <span class="op">(</span>i <span class="op">*</span> M_PI <span class="op">/</span> <span class="fl">6.0</span><span class="op">),</span></span>
<span id="cb4-62"><a href="#cb4-62"></a> <span class="op">(</span>m_radius <span class="op">-</span> inset<span class="op">)</span> <span class="op">*</span> sin <span class="op">(</span>i <span class="op">*</span> M_PI <span class="op">/</span> <span class="fl">6.0</span><span class="op">));</span></span>
<span id="cb4-63"><a href="#cb4-63"></a> cairo_line_to<span class="op">(</span></span>
<span id="cb4-64"><a href="#cb4-64"></a> cr<span class="op">,</span></span>
<span id="cb4-65"><a href="#cb4-65"></a> m_radius <span class="op">*</span> cos <span class="op">(</span>i <span class="op">*</span> M_PI <span class="op">/</span> <span class="fl">6.0</span><span class="op">),</span></span>
<span id="cb4-66"><a href="#cb4-66"></a> m_radius <span class="op">*</span> sin <span class="op">(</span>i <span class="op">*</span> M_PI <span class="op">/</span> <span class="fl">6.0</span><span class="op">));</span></span>
<span id="cb4-67"><a href="#cb4-67"></a> cairo_stroke<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-68"><a href="#cb4-68"></a> cairo_restore<span class="op">(</span>cr<span class="op">);</span> <span class="co">/* stack-pen-size */</span></span>
<span id="cb4-69"><a href="#cb4-69"></a> <span class="op">}</span></span>
<span id="cb4-70"><a href="#cb4-70"></a></span>
<span id="cb4-71"><a href="#cb4-71"></a> <span class="co">// Draw the analog hands</span></span>
<span id="cb4-72"><a href="#cb4-72"></a></span>
<span id="cb4-73"><a href="#cb4-73"></a> <span class="co">// Get the current Unix time, convert to the local time and break into time</span></span>
<span id="cb4-74"><a href="#cb4-74"></a> <span class="co">// structure to read various time parts.</span></span>
<span id="cb4-75"><a href="#cb4-75"></a> <span class="dt">time_t</span> rawtime;</span>
<span id="cb4-76"><a href="#cb4-76"></a> time(&amp;rawtime);</span>
<span id="cb4-77"><a href="#cb4-77"></a> <span class="kw">struct</span> tm * timeinfo = localtime (&amp;rawtime);</span>
<span id="cb4-75"><a href="#cb4-75"></a> <span class="dt">time_t</span> rawtime<span class="op">;</span></span>
<span id="cb4-76"><a href="#cb4-76"></a> time<span class="op">(&amp;</span>rawtime<span class="op">);</span></span>
<span id="cb4-77"><a href="#cb4-77"></a> <span class="kw">struct</span> tm <span class="op">*</span> timeinfo <span class="op">=</span> localtime <span class="op">(&amp;</span>rawtime<span class="op">);</span></span>
<span id="cb4-78"><a href="#cb4-78"></a></span>
<span id="cb4-79"><a href="#cb4-79"></a> <span class="co">// Calculate the angles of the hands of our clock</span></span>
<span id="cb4-80"><a href="#cb4-80"></a> <span class="dt">double</span> hours = timeinfo-&gt;tm_hour * M_PI / <span class="fl">6.0</span>;</span>
<span id="cb4-81"><a href="#cb4-81"></a> <span class="dt">double</span> minutes = timeinfo-&gt;tm_min * M_PI / <span class="fl">30.0</span>;</span>
<span id="cb4-82"><a href="#cb4-82"></a> <span class="dt">double</span> seconds = timeinfo-&gt;tm_sec * M_PI / <span class="fl">30.0</span>;</span>
<span id="cb4-80"><a href="#cb4-80"></a> <span class="dt">double</span> hours <span class="op">=</span> timeinfo<span class="op">-&gt;</span>tm_hour <span class="op">*</span> M_PI <span class="op">/</span> <span class="fl">6.0</span><span class="op">;</span></span>
<span id="cb4-81"><a href="#cb4-81"></a> <span class="dt">double</span> minutes <span class="op">=</span> timeinfo<span class="op">-&gt;</span>tm_min <span class="op">*</span> M_PI <span class="op">/</span> <span class="fl">30.0</span><span class="op">;</span></span>
<span id="cb4-82"><a href="#cb4-82"></a> <span class="dt">double</span> seconds <span class="op">=</span> timeinfo<span class="op">-&gt;</span>tm_sec <span class="op">*</span> M_PI <span class="op">/</span> <span class="fl">30.0</span><span class="op">;</span></span>
<span id="cb4-83"><a href="#cb4-83"></a></span>
<span id="cb4-84"><a href="#cb4-84"></a> <span class="co">// Save the graphics state</span></span>
<span id="cb4-85"><a href="#cb4-85"></a> cairo_save(cr);</span>
<span id="cb4-86"><a href="#cb4-86"></a> cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);</span>
<span id="cb4-85"><a href="#cb4-85"></a> cairo_save<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-86"><a href="#cb4-86"></a> cairo_set_line_cap<span class="op">(</span>cr<span class="op">,</span> CAIRO_LINE_CAP_ROUND<span class="op">);</span></span>
<span id="cb4-87"><a href="#cb4-87"></a></span>
<span id="cb4-88"><a href="#cb4-88"></a> cairo_save(cr);</span>
<span id="cb4-88"><a href="#cb4-88"></a> cairo_save<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-89"><a href="#cb4-89"></a></span>
<span id="cb4-90"><a href="#cb4-90"></a> <span class="co">// Draw the seconds hand</span></span>
<span id="cb4-91"><a href="#cb4-91"></a> cairo_set_line_width(cr, m_line_width / <span class="fl">3.0</span>);</span>
<span id="cb4-92"><a href="#cb4-92"></a> cairo_set_source_rgba(cr, <span class="fl">0.7</span>, <span class="fl">0.7</span>, <span class="fl">0.7</span>, <span class="fl">0.8</span>); <span class="co">// gray</span></span>
<span id="cb4-93"><a href="#cb4-93"></a> cairo_move_to(cr, <span class="fl">0.0</span>, <span class="fl">0.0</span>);</span>
<span id="cb4-94"><a href="#cb4-94"></a> cairo_line_to(cr,</span>
<span id="cb4-95"><a href="#cb4-95"></a> sin(seconds) * (m_radius * <span class="fl">0.9</span>),</span>
<span id="cb4-96"><a href="#cb4-96"></a> -cos(seconds) * (m_radius * <span class="fl">0.9</span>));</span>
<span id="cb4-97"><a href="#cb4-97"></a> cairo_stroke(cr);</span>
<span id="cb4-98"><a href="#cb4-98"></a> cairo_restore(cr);</span>
<span id="cb4-91"><a href="#cb4-91"></a> cairo_set_line_width<span class="op">(</span>cr<span class="op">,</span> m_line_width <span class="op">/</span> <span class="fl">3.0</span><span class="op">);</span></span>
<span id="cb4-92"><a href="#cb4-92"></a> cairo_set_source_rgba<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.7</span><span class="op">,</span> <span class="fl">0.7</span><span class="op">,</span> <span class="fl">0.7</span><span class="op">,</span> <span class="fl">0.8</span><span class="op">);</span> <span class="co">// gray</span></span>
<span id="cb4-93"><a href="#cb4-93"></a> cairo_move_to<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">);</span></span>
<span id="cb4-94"><a href="#cb4-94"></a> cairo_line_to<span class="op">(</span>cr<span class="op">,</span></span>
<span id="cb4-95"><a href="#cb4-95"></a> sin<span class="op">(</span>seconds<span class="op">)</span> <span class="op">*</span> <span class="op">(</span>m_radius <span class="op">*</span> <span class="fl">0.9</span><span class="op">),</span></span>
<span id="cb4-96"><a href="#cb4-96"></a> <span class="op">-</span>cos<span class="op">(</span>seconds<span class="op">)</span> <span class="op">*</span> <span class="op">(</span>m_radius <span class="op">*</span> <span class="fl">0.9</span><span class="op">));</span></span>
<span id="cb4-97"><a href="#cb4-97"></a> cairo_stroke<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-98"><a href="#cb4-98"></a> cairo_restore<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-99"><a href="#cb4-99"></a></span>
<span id="cb4-100"><a href="#cb4-100"></a> <span class="co">// Draw the minutes hand</span></span>
<span id="cb4-101"><a href="#cb4-101"></a> cairo_set_source_rgba(cr, <span class="fl">0.117</span>, <span class="fl">0.337</span>, <span class="fl">0.612</span>, <span class="fl">0.9</span>); <span class="co">// blue</span></span>
<span id="cb4-102"><a href="#cb4-102"></a> cairo_move_to(cr, <span class="dv">0</span>, <span class="dv">0</span>);</span>
<span id="cb4-103"><a href="#cb4-103"></a> cairo_line_to(cr,</span>
<span id="cb4-104"><a href="#cb4-104"></a> sin(minutes + seconds / <span class="dv">60</span>) * (m_radius * <span class="fl">0.8</span>),</span>
<span id="cb4-105"><a href="#cb4-105"></a> -cos(minutes + seconds / <span class="dv">60</span>) * (m_radius * <span class="fl">0.8</span>));</span>
<span id="cb4-106"><a href="#cb4-106"></a> cairo_stroke(cr);</span>
<span id="cb4-101"><a href="#cb4-101"></a> cairo_set_source_rgba<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.117</span><span class="op">,</span> <span class="fl">0.337</span><span class="op">,</span> <span class="fl">0.612</span><span class="op">,</span> <span class="fl">0.9</span><span class="op">);</span> <span class="co">// blue</span></span>
<span id="cb4-102"><a href="#cb4-102"></a> cairo_move_to<span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
<span id="cb4-103"><a href="#cb4-103"></a> cairo_line_to<span class="op">(</span>cr<span class="op">,</span></span>
<span id="cb4-104"><a href="#cb4-104"></a> sin<span class="op">(</span>minutes <span class="op">+</span> seconds <span class="op">/</span> <span class="dv">60</span><span class="op">)</span> <span class="op">*</span> <span class="op">(</span>m_radius <span class="op">*</span> <span class="fl">0.8</span><span class="op">),</span></span>
<span id="cb4-105"><a href="#cb4-105"></a> <span class="op">-</span>cos<span class="op">(</span>minutes <span class="op">+</span> seconds <span class="op">/</span> <span class="dv">60</span><span class="op">)</span> <span class="op">*</span> <span class="op">(</span>m_radius <span class="op">*</span> <span class="fl">0.8</span><span class="op">));</span></span>
<span id="cb4-106"><a href="#cb4-106"></a> cairo_stroke<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-107"><a href="#cb4-107"></a></span>
<span id="cb4-108"><a href="#cb4-108"></a> <span class="co">// draw the hours hand</span></span>
<span id="cb4-109"><a href="#cb4-109"></a> cairo_set_source_rgba(cr, <span class="fl">0.337</span>, <span class="fl">0.612</span>, <span class="fl">0.117</span>, <span class="fl">0.9</span>); <span class="co">// green</span></span>
<span id="cb4-110"><a href="#cb4-110"></a> cairo_move_to(cr, <span class="fl">0.0</span>, <span class="fl">0.0</span>);</span>
<span id="cb4-111"><a href="#cb4-111"></a> cairo_line_to(cr,</span>
<span id="cb4-112"><a href="#cb4-112"></a> sin(hours + minutes / <span class="fl">12.0</span>) * (m_radius * <span class="fl">0.5</span>),</span>
<span id="cb4-113"><a href="#cb4-113"></a> -cos(hours + minutes / <span class="fl">12.0</span>) * (m_radius * <span class="fl">0.5</span>));</span>
<span id="cb4-114"><a href="#cb4-114"></a> cairo_stroke(cr);</span>
<span id="cb4-115"><a href="#cb4-115"></a> cairo_restore(cr);</span>
<span id="cb4-109"><a href="#cb4-109"></a> cairo_set_source_rgba<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.337</span><span class="op">,</span> <span class="fl">0.612</span><span class="op">,</span> <span class="fl">0.117</span><span class="op">,</span> <span class="fl">0.9</span><span class="op">);</span> <span class="co">// green</span></span>
<span id="cb4-110"><a href="#cb4-110"></a> cairo_move_to<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">);</span></span>
<span id="cb4-111"><a href="#cb4-111"></a> cairo_line_to<span class="op">(</span>cr<span class="op">,</span></span>
<span id="cb4-112"><a href="#cb4-112"></a> sin<span class="op">(</span>hours <span class="op">+</span> minutes <span class="op">/</span> <span class="fl">12.0</span><span class="op">)</span> <span class="op">*</span> <span class="op">(</span>m_radius <span class="op">*</span> <span class="fl">0.5</span><span class="op">),</span></span>
<span id="cb4-113"><a href="#cb4-113"></a> <span class="op">-</span>cos<span class="op">(</span>hours <span class="op">+</span> minutes <span class="op">/</span> <span class="fl">12.0</span><span class="op">)</span> <span class="op">*</span> <span class="op">(</span>m_radius <span class="op">*</span> <span class="fl">0.5</span><span class="op">));</span></span>
<span id="cb4-114"><a href="#cb4-114"></a> cairo_stroke<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-115"><a href="#cb4-115"></a> cairo_restore<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-116"><a href="#cb4-116"></a></span>
<span id="cb4-117"><a href="#cb4-117"></a> <span class="co">// Draw a little dot in the middle</span></span>
<span id="cb4-118"><a href="#cb4-118"></a> cairo_arc(cr, <span class="fl">0.0</span>, <span class="fl">0.0</span>, m_line_width / <span class="fl">3.0</span>, <span class="fl">0.0</span>, <span class="fl">2.0</span> * M_PI);</span>
<span id="cb4-119"><a href="#cb4-119"></a> cairo_fill(cr);</span>
<span id="cb4-120"><a href="#cb4-120"></a>}</span>
<span id="cb4-118"><a href="#cb4-118"></a> cairo_arc<span class="op">(</span>cr<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> m_line_width <span class="op">/</span> <span class="fl">3.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">2.0</span> <span class="op">*</span> M_PI<span class="op">);</span></span>
<span id="cb4-119"><a href="#cb4-119"></a> cairo_fill<span class="op">(</span>cr<span class="op">);</span></span>
<span id="cb4-120"><a href="#cb4-120"></a><span class="op">}</span></span>
<span id="cb4-121"><a href="#cb4-121"></a></span>
<span id="cb4-122"><a href="#cb4-122"></a></span>
<span id="cb4-123"><a href="#cb4-123"></a>gboolean</span>
<span id="cb4-124"><a href="#cb4-124"></a>time_handler(GtkWidget* widget) {</span>
<span id="cb4-125"><a href="#cb4-125"></a> gtk_widget_queue_draw(widget);</span>
<span id="cb4-124"><a href="#cb4-124"></a>time_handler<span class="op">(</span>GtkWidget<span class="op">*</span> widget<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-125"><a href="#cb4-125"></a> gtk_widget_queue_draw<span class="op">(</span>widget<span class="op">);</span></span>
<span id="cb4-126"><a href="#cb4-126"></a></span>
<span id="cb4-127"><a href="#cb4-127"></a> <span class="cf">return</span> TRUE;</span>
<span id="cb4-128"><a href="#cb4-128"></a>}</span>
<span id="cb4-127"><a href="#cb4-127"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span>
<span id="cb4-128"><a href="#cb4-128"></a><span class="op">}</span></span>
<span id="cb4-129"><a href="#cb4-129"></a></span>
<span id="cb4-130"><a href="#cb4-130"></a></span>
<span id="cb4-131"><a href="#cb4-131"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-132"><a href="#cb4-132"></a>app_activate (GApplication *app, gpointer user_data) {</span>
<span id="cb4-133"><a href="#cb4-133"></a> GtkWidget *win;</span>
<span id="cb4-134"><a href="#cb4-134"></a> GtkWidget *clock;</span>
<span id="cb4-135"><a href="#cb4-135"></a> GtkBuilder *build;</span>
<span id="cb4-132"><a href="#cb4-132"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-133"><a href="#cb4-133"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
<span id="cb4-134"><a href="#cb4-134"></a> GtkWidget <span class="op">*</span>clock<span class="op">;</span></span>
<span id="cb4-135"><a href="#cb4-135"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
<span id="cb4-136"><a href="#cb4-136"></a></span>
<span id="cb4-137"><a href="#cb4-137"></a> build = gtk_builder_new_from_resource (<span class="st">&quot;/com/github/ToshioCP/tfc/tfc.ui&quot;</span>);</span>
<span id="cb4-138"><a href="#cb4-138"></a> win = GTK_WIDGET (gtk_builder_get_object (build, <span class="st">&quot;win&quot;</span>));</span>
<span id="cb4-139"><a href="#cb4-139"></a> gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));</span>
<span id="cb4-137"><a href="#cb4-137"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">&quot;/com/github/ToshioCP/tfc/tfc.ui&quot;</span><span class="op">);</span></span>
<span id="cb4-138"><a href="#cb4-138"></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="cb4-139"><a href="#cb4-139"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> GTK_APPLICATION <span class="op">(</span>app<span class="op">));</span></span>
<span id="cb4-140"><a href="#cb4-140"></a></span>
<span id="cb4-141"><a href="#cb4-141"></a> clock = GTK_WIDGET (gtk_builder_get_object (build, <span class="st">&quot;clock&quot;</span>));</span>
<span id="cb4-142"><a href="#cb4-142"></a> g_object_unref(build);</span>
<span id="cb4-141"><a href="#cb4-141"></a> clock <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;clock&quot;</span><span class="op">));</span></span>
<span id="cb4-142"><a href="#cb4-142"></a> g_object_unref<span class="op">(</span>build<span class="op">);</span></span>
<span id="cb4-143"><a href="#cb4-143"></a></span>
<span id="cb4-144"><a href="#cb4-144"></a> gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA (clock), draw_clock, NULL, NULL);</span>
<span id="cb4-145"><a href="#cb4-145"></a> g_timeout_add(<span class="dv">1000</span>, (GSourceFunc) time_handler, (gpointer) clock);</span>
<span id="cb4-146"><a href="#cb4-146"></a> gtk_widget_show(win);</span>
<span id="cb4-144"><a href="#cb4-144"></a> gtk_drawing_area_set_draw_func<span class="op">(</span>GTK_DRAWING_AREA <span class="op">(</span>clock<span class="op">),</span> draw_clock<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb4-145"><a href="#cb4-145"></a> g_timeout_add<span class="op">(</span><span class="dv">1000</span><span class="op">,</span> <span class="op">(</span>GSourceFunc<span class="op">)</span> time_handler<span class="op">,</span> <span class="op">(</span>gpointer<span class="op">)</span> clock<span class="op">);</span></span>
<span id="cb4-146"><a href="#cb4-146"></a> gtk_widget_show<span class="op">(</span>win<span class="op">);</span></span>
<span id="cb4-147"><a href="#cb4-147"></a></span>
<span id="cb4-148"><a href="#cb4-148"></a>}</span>
<span id="cb4-148"><a href="#cb4-148"></a><span class="op">}</span></span>
<span id="cb4-149"><a href="#cb4-149"></a></span>
<span id="cb4-150"><a href="#cb4-150"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-151"><a href="#cb4-151"></a>app_open (GApplication *app, GFile **files, gint n_files, gchar *hint, gpointer user_data) {</span>
<span id="cb4-152"><a href="#cb4-152"></a> app_activate(app,user_data);</span>
<span id="cb4-153"><a href="#cb4-153"></a>}</span>
<span id="cb4-151"><a href="#cb4-151"></a>app_open <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">,</span> GFile <span class="op">**</span>files<span class="op">,</span> gint n_files<span class="op">,</span> gchar <span class="op">*</span>hint<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-152"><a href="#cb4-152"></a> app_activate<span class="op">(</span>app<span class="op">,</span>user_data<span class="op">);</span></span>
<span id="cb4-153"><a href="#cb4-153"></a><span class="op">}</span></span>
<span id="cb4-154"><a href="#cb4-154"></a></span>
<span id="cb4-155"><a href="#cb4-155"></a><span class="dt">int</span></span>
<span id="cb4-156"><a href="#cb4-156"></a>main (<span class="dt">int</span> argc, <span class="dt">char</span> **argv) {</span>
<span id="cb4-157"><a href="#cb4-157"></a> GtkApplication *app;</span>
<span id="cb4-158"><a href="#cb4-158"></a> <span class="dt">int</span> stat;</span>
<span id="cb4-156"><a href="#cb4-156"></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="cb4-157"><a href="#cb4-157"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb4-158"><a href="#cb4-158"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb4-159"><a href="#cb4-159"></a></span>
<span id="cb4-160"><a href="#cb4-160"></a> app = gtk_application_new (<span class="st">&quot;com.github.ToshioCP.tfc&quot;</span>, G_APPLICATION_HANDLES_OPEN);</span>
<span id="cb4-161"><a href="#cb4-161"></a> g_signal_connect (app, <span class="st">&quot;activate&quot;</span>, G_CALLBACK (app_activate), NULL);</span>
<span id="cb4-162"><a href="#cb4-162"></a> g_signal_connect (app, <span class="st">&quot;open&quot;</span>, G_CALLBACK (app_open), NULL);</span>
<span id="cb4-163"><a href="#cb4-163"></a> stat = g_application_run (G_APPLICATION (app), argc, argv);</span>
<span id="cb4-164"><a href="#cb4-164"></a> g_object_unref (app);</span>
<span id="cb4-165"><a href="#cb4-165"></a> <span class="cf">return</span> stat;</span>
<span id="cb4-166"><a href="#cb4-166"></a>}</span></code></pre></div>
<span id="cb4-160"><a href="#cb4-160"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span><span class="st">&quot;com.github.ToshioCP.tfc&quot;</span><span class="op">,</span> G_APPLICATION_HANDLES_OPEN<span class="op">);</span></span>
<span id="cb4-161"><a href="#cb4-161"></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="cb4-162"><a href="#cb4-162"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;open&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_open<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb4-163"><a href="#cb4-163"></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="cb4-164"><a href="#cb4-164"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb4-165"><a href="#cb4-165"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb4-166"><a href="#cb4-166"></a><span class="op">}</span></span></code></pre></div>
<p><code>tfc.ui</code></p>
<div class="sourceCode" id="cb5"><pre class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw">&lt;?xml</span> version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;<span class="kw">?&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="kw">&lt;interface&gt;</span></span>
<span id="cb5-3"><a href="#cb5-3"></a> <span class="kw">&lt;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><span class="kw">&gt;</span></span>
<span id="cb5-4"><a href="#cb5-4"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;title&quot;</span><span class="kw">&gt;</span>Clock<span class="kw">&lt;/property&gt;</span></span>
<span id="cb5-5"><a href="#cb5-5"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span><span class="kw">&gt;</span>200<span class="kw">&lt;/property&gt;</span></span>
<span id="cb5-6"><a href="#cb5-6"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;default-height&quot;</span><span class="kw">&gt;</span>200<span class="kw">&lt;/property&gt;</span></span>
<span id="cb5-7"><a href="#cb5-7"></a> <span class="kw">&lt;child&gt;</span></span>
<span id="cb5-8"><a href="#cb5-8"></a> <span class="kw">&lt;object</span><span class="ot"> class=</span><span class="st">&quot;GtkDrawingArea&quot;</span><span class="ot"> id=</span><span class="st">&quot;clock&quot;</span><span class="kw">&gt;</span></span>
<span id="cb5-9"><a href="#cb5-9"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;hexpand&quot;</span><span class="kw">&gt;</span>TRUE<span class="kw">&lt;/property&gt;</span></span>
<span id="cb5-10"><a href="#cb5-10"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;vexpand&quot;</span><span class="kw">&gt;</span>TRUE<span class="kw">&lt;/property&gt;</span></span>
<span id="cb5-11"><a href="#cb5-11"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb5-12"><a href="#cb5-12"></a> <span class="kw">&lt;/child&gt;</span></span>
<span id="cb5-13"><a href="#cb5-13"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb5-14"><a href="#cb5-14"></a><span class="kw">&lt;/interface&gt;</span></span></code></pre></div>
<div class="sourceCode" id="cb5"><pre
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb5-1"><a href="#cb5-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="cb5-2"><a href="#cb5-2"></a>&lt;<span class="kw">interface</span>&gt;</span>
<span id="cb5-3"><a href="#cb5-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="cb5-4"><a href="#cb5-4"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;title&quot;</span>&gt;Clock&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb5-5"><a href="#cb5-5"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span>&gt;200&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb5-6"><a href="#cb5-6"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;default-height&quot;</span>&gt;200&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb5-7"><a href="#cb5-7"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb5-8"><a href="#cb5-8"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkDrawingArea&quot;</span><span class="ot"> id=</span><span class="st">&quot;clock&quot;</span>&gt;</span>
<span id="cb5-9"><a href="#cb5-9"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;hexpand&quot;</span>&gt;TRUE&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb5-10"><a href="#cb5-10"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;vexpand&quot;</span>&gt;TRUE&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb5-11"><a href="#cb5-11"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb5-12"><a href="#cb5-12"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb5-13"><a href="#cb5-13"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb5-14"><a href="#cb5-14"></a>&lt;/<span class="kw">interface</span>&gt;</span></code></pre></div>
<p><code>tfc.gresource.xml</code></p>
<div class="sourceCode" id="cb6"><pre class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">&lt;?xml</span> version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;<span class="kw">?&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2"></a><span class="kw">&lt;gresources&gt;</span></span>
<span id="cb6-3"><a href="#cb6-3"></a> <span class="kw">&lt;gresource</span><span class="ot"> prefix=</span><span class="st">&quot;/com/github/ToshioCP/tfc&quot;</span><span class="kw">&gt;</span></span>
<span id="cb6-4"><a href="#cb6-4"></a> <span class="kw">&lt;file&gt;</span>tfc.ui<span class="kw">&lt;/file&gt;</span></span>
<span id="cb6-5"><a href="#cb6-5"></a> <span class="kw">&lt;/gresource&gt;</span></span>
<span id="cb6-6"><a href="#cb6-6"></a><span class="kw">&lt;/gresources&gt;</span></span></code></pre></div>
<div class="sourceCode" id="cb6"><pre
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb6-1"><a href="#cb6-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="cb6-2"><a href="#cb6-2"></a>&lt;<span class="kw">gresources</span>&gt;</span>
<span id="cb6-3"><a href="#cb6-3"></a> &lt;<span class="kw">gresource</span><span class="ot"> prefix=</span><span class="st">&quot;/com/github/ToshioCP/tfc&quot;</span>&gt;</span>
<span id="cb6-4"><a href="#cb6-4"></a> &lt;<span class="kw">file</span>&gt;tfc.ui&lt;/<span class="kw">file</span>&gt;</span>
<span id="cb6-5"><a href="#cb6-5"></a> &lt;/<span class="kw">gresource</span>&gt;</span>
<span id="cb6-6"><a href="#cb6-6"></a>&lt;/<span class="kw">gresources</span>&gt;</span></code></pre></div>
<p><code>comp</code></p>
<div class="sourceCode" id="cb7"><pre class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb7-1"><a href="#cb7-1"></a>glib-compile-resources $1.gresource.xml --target=$1.gresource.c --generate-source</span>
<div class="sourceCode" id="cb7"><pre
class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb7-1"><a href="#cb7-1"></a>glib-compile-resources $1.gresource.xml --target=$1.gresource.c --generate-source</span>
<span id="cb7-2"><a href="#cb7-2"></a>gcc `pkg-config --cflags gtk4` $1.gresource.c $1.c `pkg-config --libs gtk4` -lm</span></code></pre></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>

View file

@ -132,13 +132,13 @@ point. So, each item can be referred by the index of the item (first
item, second item, …, nth item, …). There are two cases. One is the
index starts from one (one-based) and the other is from zero
(zero-based).</p>
<p>Gio provides GListModel interface. It is a zero-based list of the
same type of GObject descendants, or objects that implement the same
interface. An object implements GListModel is not a widget. So, the list
is not displayed on the screen directly. Theres another object
GtkListView which is a widget to display the list. The items in the list
need to be connected to the items in GtkListView. GtkListItemFactory
object maps items in the list to GListView.</p>
<p>Gio provides GListModel interface. It is a zero-based list and its
items are the same type of GObject descendants, or objects that
implement the same interface. An object implements GListModel is not a
widget. So, the list is not displayed on the screen directly. Theres
another object GtkListView which is a widget to display the list. The
items in the list need to be connected to the items in GtkListView.
GtkListItemFactory instance maps items in the list to GListView.</p>
<figure>
<img src="image/list.png" alt="List" />
<figcaption aria-hidden="true">List</figcaption>
@ -172,8 +172,8 @@ API Reference GtkStringList</a> for further information.</p>
to this model, user can select items by clicking on them. It is
implemented by GtkMultiSelection, GtkNoSelection and GtkSingleSelection
objects. These three objects are usually enough to build an application.
They are created with GListModel. You can also create them alone and add
GListModel later.</p>
They are created with another GListModel. You can also create them alone
and add a GListModel later.</p>
<ul>
<li>GtkMultiSelection supports multiple selection.</li>
<li>GtkNoSelection supports no selection. This is a wrapper to
@ -199,7 +199,7 @@ growth of memory consumption so that GListModel can contain lots of
items, for example, more than a million items.</p>
<h2 id="gtklistitemfactory">GtkListItemFactory</h2>
<p>GtkListItemFactory creates or recycles GtkListItem and connects it
with an item of the list model. There are two child objects of this
with an item of the list model. There are two child classes of this
factory, GtkSignalListItemFactory and GtkBuilderListItemFactory.</p>
<h3 id="gtksignallistitemfactory">GtkSignalListItemFactory</h3>
<p>GtkSignalListItemFactory provides signals for users to configure a
@ -207,7 +207,7 @@ GtkListItem object. There are four signals.</p>
<ol type="1">
<li>“setup” is emitted to set up GtkListItem object. A user sets its
child widget in the handler. For example, creates a GtkLabel widget and
sets the child property of GtkListItem with it. This setting is kept
sets the child property of the GtkListItem to it. This setting is kept
even the GtkListItem instance is recycled (to bind to another item of
GListModel).</li>
<li>“bind” is emitted to bind an item in the list model to the widget.
@ -233,16 +233,16 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
<span id="cb2-4"><a href="#cb2-4"></a>setup_cb <span class="op">(</span>GtkSignalListItemFactory <span class="op">*</span>self<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-5"><a href="#cb2-5"></a> GtkWidget <span class="op">*</span>lb <span class="op">=</span> gtk_label_new <span class="op">(</span>NULL<span class="op">);</span></span>
<span id="cb2-6"><a href="#cb2-6"></a> gtk_list_item_set_child <span class="op">(</span>listitem<span class="op">,</span> lb<span class="op">);</span></span>
<span id="cb2-7"><a href="#cb2-7"></a><span class="op">}</span></span>
<span id="cb2-8"><a href="#cb2-8"></a></span>
<span id="cb2-9"><a href="#cb2-9"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb2-10"><a href="#cb2-10"></a>bind_cb <span class="op">(</span>GtkSignalListItemFactory <span class="op">*</span>self<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-11"><a href="#cb2-11"></a> GtkWidget <span class="op">*</span>lb <span class="op">=</span> gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">);</span></span>
<span id="cb2-12"><a href="#cb2-12"></a> <span class="co">/* Strobj is owned by the instance. Caller mustn&#39;t change or destroy it. */</span></span>
<span id="cb2-13"><a href="#cb2-13"></a> GtkStringObject <span class="op">*</span>strobj <span class="op">=</span> gtk_list_item_get_item <span class="op">(</span>listitem<span class="op">);</span></span>
<span id="cb2-14"><a href="#cb2-14"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>text <span class="op">=</span> gtk_string_object_get_string <span class="op">(</span>strobj<span class="op">);</span></span>
<span id="cb2-15"><a href="#cb2-15"></a></span>
<span id="cb2-16"><a href="#cb2-16"></a> gtk_label_set_text <span class="op">(</span>GTK_LABEL <span class="op">(</span>lb<span class="op">),</span> text<span class="op">);</span></span>
<span id="cb2-7"><a href="#cb2-7"></a> <span class="co">/* Because gtk_list_item_set_child sunk the floating reference of lb, releasing (unref) isn&#39;t necessary for lb. */</span></span>
<span id="cb2-8"><a href="#cb2-8"></a><span class="op">}</span></span>
<span id="cb2-9"><a href="#cb2-9"></a></span>
<span id="cb2-10"><a href="#cb2-10"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb2-11"><a href="#cb2-11"></a>bind_cb <span class="op">(</span>GtkSignalListItemFactory <span class="op">*</span>self<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-12"><a href="#cb2-12"></a> GtkWidget <span class="op">*</span>lb <span class="op">=</span> gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">);</span></span>
<span id="cb2-13"><a href="#cb2-13"></a> <span class="co">/* Strobj is owned by the instance. Caller mustn&#39;t change or destroy it. */</span></span>
<span id="cb2-14"><a href="#cb2-14"></a> GtkStringObject <span class="op">*</span>strobj <span class="op">=</span> gtk_list_item_get_item <span class="op">(</span>listitem<span class="op">);</span></span>
<span id="cb2-15"><a href="#cb2-15"></a> <span class="co">/* The string returned by gtk_string_object_get_string is owned by the instance. */</span></span>
<span id="cb2-16"><a href="#cb2-16"></a> gtk_label_set_text <span class="op">(</span>GTK_LABEL <span class="op">(</span>lb<span class="op">),</span> gtk_string_object_get_string <span class="op">(</span>strobj<span class="op">));</span></span>
<span id="cb2-17"><a href="#cb2-17"></a><span class="op">}</span></span>
<span id="cb2-18"><a href="#cb2-18"></a></span>
<span id="cb2-19"><a href="#cb2-19"></a><span class="dt">static</span> <span class="dt">void</span></span>
@ -252,8 +252,8 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
<span id="cb2-23"><a href="#cb2-23"></a></span>
<span id="cb2-24"><a href="#cb2-24"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb2-25"><a href="#cb2-25"></a>teardown_cb <span class="op">(</span>GtkSignalListItemFactory <span class="op">*</span>self<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-26"><a href="#cb2-26"></a> gtk_list_item_set_child <span class="op">(</span>listitem<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb2-27"><a href="#cb2-27"></a> <span class="co">/* The previous child is destroyed automatically. */</span></span>
<span id="cb2-26"><a href="#cb2-26"></a> <span class="co">/* There&#39;s nothing to do here. */</span></span>
<span id="cb2-27"><a href="#cb2-27"></a> <span class="co">/* GtkListItem instance will be destroyed soon. You don&#39;t need to set the child to NULL. */</span></span>
<span id="cb2-28"><a href="#cb2-28"></a><span class="op">}</span></span>
<span id="cb2-29"><a href="#cb2-29"></a></span>
<span id="cb2-30"><a href="#cb2-30"></a><span class="dt">static</span> <span class="dt">void</span></span>
@ -276,30 +276,31 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
<span id="cb2-47"><a href="#cb2-47"></a> GtkListItemFactory <span class="op">*</span>factory <span class="op">=</span> gtk_signal_list_item_factory_new <span class="op">();</span></span>
<span id="cb2-48"><a href="#cb2-48"></a> g_signal_connect <span class="op">(</span>factory<span class="op">,</span> <span class="st">&quot;setup&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>setup_cb<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb2-49"><a href="#cb2-49"></a> g_signal_connect <span class="op">(</span>factory<span class="op">,</span> <span class="st">&quot;bind&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>bind_cb<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb2-50"><a href="#cb2-50"></a> g_signal_connect <span class="op">(</span>factory<span class="op">,</span> <span class="st">&quot;unbind&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>unbind_cb<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb2-51"><a href="#cb2-51"></a> g_signal_connect <span class="op">(</span>factory<span class="op">,</span> <span class="st">&quot;teardown&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>teardown_cb<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb2-52"><a href="#cb2-52"></a></span>
<span id="cb2-53"><a href="#cb2-53"></a> GtkWidget <span class="op">*</span>lv <span class="op">=</span> gtk_list_view_new <span class="op">(</span>GTK_SELECTION_MODEL <span class="op">(</span>ns<span class="op">),</span> factory<span class="op">);</span></span>
<span id="cb2-54"><a href="#cb2-54"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> lv<span class="op">);</span></span>
<span id="cb2-55"><a href="#cb2-55"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
<span id="cb2-56"><a href="#cb2-56"></a><span class="op">}</span></span>
<span id="cb2-57"><a href="#cb2-57"></a></span>
<span id="cb2-58"><a href="#cb2-58"></a><span class="co">/* ----- main ----- */</span></span>
<span id="cb2-59"><a href="#cb2-59"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.list1&quot;</span></span>
<span id="cb2-60"><a href="#cb2-60"></a></span>
<span id="cb2-61"><a href="#cb2-61"></a><span class="dt">int</span></span>
<span id="cb2-62"><a href="#cb2-62"></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="cb2-63"><a href="#cb2-63"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb2-64"><a href="#cb2-64"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb2-65"><a href="#cb2-65"></a></span>
<span id="cb2-66"><a href="#cb2-66"></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="cb2-67"><a href="#cb2-67"></a></span>
<span id="cb2-68"><a href="#cb2-68"></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="cb2-69"><a href="#cb2-69"></a></span>
<span id="cb2-70"><a href="#cb2-70"></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="cb2-71"><a href="#cb2-71"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb2-72"><a href="#cb2-72"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb2-73"><a href="#cb2-73"></a><span class="op">}</span></span></code></pre></div>
<span id="cb2-50"><a href="#cb2-50"></a> <span class="co">/* The following two lines can be left out. The handlers do nothing. */</span></span>
<span id="cb2-51"><a href="#cb2-51"></a> g_signal_connect <span class="op">(</span>factory<span class="op">,</span> <span class="st">&quot;unbind&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>unbind_cb<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb2-52"><a href="#cb2-52"></a> g_signal_connect <span class="op">(</span>factory<span class="op">,</span> <span class="st">&quot;teardown&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>teardown_cb<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb2-53"><a href="#cb2-53"></a></span>
<span id="cb2-54"><a href="#cb2-54"></a> GtkWidget <span class="op">*</span>lv <span class="op">=</span> gtk_list_view_new <span class="op">(</span>GTK_SELECTION_MODEL <span class="op">(</span>ns<span class="op">),</span> factory<span class="op">);</span></span>
<span id="cb2-55"><a href="#cb2-55"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> lv<span class="op">);</span></span>
<span id="cb2-56"><a href="#cb2-56"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
<span id="cb2-57"><a href="#cb2-57"></a><span class="op">}</span></span>
<span id="cb2-58"><a href="#cb2-58"></a></span>
<span id="cb2-59"><a href="#cb2-59"></a><span class="co">/* ----- main ----- */</span></span>
<span id="cb2-60"><a href="#cb2-60"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.list1&quot;</span></span>
<span id="cb2-61"><a href="#cb2-61"></a></span>
<span id="cb2-62"><a href="#cb2-62"></a><span class="dt">int</span></span>
<span id="cb2-63"><a href="#cb2-63"></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="cb2-64"><a href="#cb2-64"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb2-65"><a href="#cb2-65"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb2-66"><a href="#cb2-66"></a></span>
<span id="cb2-67"><a href="#cb2-67"></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="cb2-68"><a href="#cb2-68"></a></span>
<span id="cb2-69"><a href="#cb2-69"></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="cb2-70"><a href="#cb2-70"></a></span>
<span id="cb2-71"><a href="#cb2-71"></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="cb2-72"><a href="#cb2-72"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb2-73"><a href="#cb2-73"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb2-74"><a href="#cb2-74"></a><span class="op">}</span></span></code></pre></div>
<p>The file <code>list1.c</code> is located under the directory
src/misc. Make a shell script below and save it to your bin directory,
for example <code>$HOME/bin</code>.</p>
@ -339,13 +340,13 @@ class="sourceCode xml"><code class="sourceCode xml"><span id="cb5-1"><a href="#c
GtkLabel object. The factory sees this template and creates GtkLabel and
sets the child property of GtkListItem. This is the same as what setup
handler of GtkSignalListItemFactory did.</p>
<p>Then, bind the label property of GtkLabel to string property of
GtkStringObject. The string object is referred to by item property of
GtkListItem. So, the lookup tag is like this:</p>
<pre><code>string &lt;- GtkStringObject &lt;- item &lt;- GtkListItem</code></pre>
<p>Then, bind the label property of the GtkLabel to the string property
of a GtkStringObject. The string object refers to the item property of
the GtkListItem. So, the lookup tag is like this:</p>
<pre><code>label &lt;- string &lt;- GtkStringObject &lt;- item &lt;- GtkListItem</code></pre>
<p>The last lookup tag has a content <code>GtkListItem</code>. Usually,
C type like <code>GtkListItem</code> doesnt appear in the content of
tags. This is a special case. There is an explanation about it in the <a
tags. This is a special case. There is an explanation in the <a
href="https://blog.gtk.org/2020/09/05/a-primer-on-gtklistview/">GTK
Development Blog</a> by Matthias Clasen.</p>
<blockquote>
@ -361,60 +362,65 @@ located under src/misc directory.</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb7-2"><a href="#cb7-2"></a></span>
<span id="cb7-3"><a href="#cb7-3"></a><span class="co">/* ----- activate, open, startup handlers ----- */</span></span>
<span id="cb7-4"><a href="#cb7-4"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb7-5"><a href="#cb7-5"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-6"><a href="#cb7-6"></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="cb7-7"><a href="#cb7-7"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> gtk_application_window_new <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb7-8"><a href="#cb7-8"></a> gtk_window_set_default_size <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="dv">600</span><span class="op">,</span> <span class="dv">400</span><span class="op">);</span></span>
<span id="cb7-9"><a href="#cb7-9"></a> GtkWidget <span class="op">*</span>scr <span class="op">=</span> gtk_scrolled_window_new <span class="op">();</span></span>
<span id="cb7-10"><a href="#cb7-10"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> scr<span class="op">);</span></span>
<span id="cb7-11"><a href="#cb7-11"></a></span>
<span id="cb7-12"><a href="#cb7-12"></a> <span class="dt">char</span> <span class="op">*</span>array<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span></span>
<span id="cb7-13"><a href="#cb7-13"></a> <span class="st">&quot;one&quot;</span><span class="op">,</span> <span class="st">&quot;two&quot;</span><span class="op">,</span> <span class="st">&quot;three&quot;</span><span class="op">,</span> <span class="st">&quot;four&quot;</span><span class="op">,</span> NULL</span>
<span id="cb7-14"><a href="#cb7-14"></a> <span class="op">};</span></span>
<span id="cb7-15"><a href="#cb7-15"></a> GtkStringList <span class="op">*</span>sl <span class="op">=</span> gtk_string_list_new <span class="op">((</span><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span> <span class="dt">const</span> <span class="op">*)</span> array<span class="op">);</span></span>
<span id="cb7-16"><a href="#cb7-16"></a> GtkSingleSelection <span class="op">*</span>ss <span class="op">=</span> gtk_single_selection_new <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>sl<span class="op">));</span></span>
<span id="cb7-17"><a href="#cb7-17"></a></span>
<span id="cb7-18"><a href="#cb7-18"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>ui_string <span class="op">=</span></span>
<span id="cb7-19"><a href="#cb7-19"></a><span class="st">&quot;&lt;interface&gt;&quot;</span></span>
<span id="cb7-20"><a href="#cb7-20"></a> <span class="st">&quot;&lt;template class=</span><span class="sc">\&quot;</span><span class="st">GtkListItem</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb7-21"><a href="#cb7-21"></a> <span class="st">&quot;&lt;property name=</span><span class="sc">\&quot;</span><span class="st">child</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb7-22"><a href="#cb7-22"></a> <span class="st">&quot;&lt;object class=</span><span class="sc">\&quot;</span><span class="st">GtkLabel</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb7-23"><a href="#cb7-23"></a> <span class="st">&quot;&lt;binding name=</span><span class="sc">\&quot;</span><span class="st">label</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb7-24"><a href="#cb7-24"></a> <span class="st">&quot;&lt;lookup name=</span><span class="sc">\&quot;</span><span class="st">string</span><span class="sc">\&quot;</span><span class="st"> type=</span><span class="sc">\&quot;</span><span class="st">GtkStringObject</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb7-25"><a href="#cb7-25"></a> <span class="st">&quot;&lt;lookup name=</span><span class="sc">\&quot;</span><span class="st">item</span><span class="sc">\&quot;</span><span class="st">&gt;GtkListItem&lt;/lookup&gt;&quot;</span></span>
<span id="cb7-26"><a href="#cb7-26"></a> <span class="st">&quot;&lt;/lookup&gt;&quot;</span></span>
<span id="cb7-27"><a href="#cb7-27"></a> <span class="st">&quot;&lt;/binding&gt;&quot;</span></span>
<span id="cb7-28"><a href="#cb7-28"></a> <span class="st">&quot;&lt;/object&gt;&quot;</span></span>
<span id="cb7-29"><a href="#cb7-29"></a> <span class="st">&quot;&lt;/property&gt;&quot;</span></span>
<span id="cb7-30"><a href="#cb7-30"></a> <span class="st">&quot;&lt;/template&gt;&quot;</span></span>
<span id="cb7-31"><a href="#cb7-31"></a><span class="st">&quot;&lt;/interface&gt;&quot;</span></span>
<span id="cb7-32"><a href="#cb7-32"></a><span class="op">;</span></span>
<span id="cb7-33"><a href="#cb7-33"></a> GBytes <span class="op">*</span>gbytes <span class="op">=</span> g_bytes_new_static <span class="op">(</span>ui_string<span class="op">,</span> strlen <span class="op">(</span>ui_string<span class="op">));</span></span>
<span id="cb7-34"><a href="#cb7-34"></a> GtkListItemFactory <span class="op">*</span>factory <span class="op">=</span> gtk_builder_list_item_factory_new_from_bytes <span class="op">(</span>NULL<span class="op">,</span> gbytes<span class="op">);</span></span>
<span id="cb7-35"><a href="#cb7-35"></a></span>
<span id="cb7-36"><a href="#cb7-36"></a> GtkWidget <span class="op">*</span>lv <span class="op">=</span> gtk_list_view_new <span class="op">(</span>GTK_SELECTION_MODEL <span class="op">(</span>ss<span class="op">),</span> factory<span class="op">);</span></span>
<span id="cb7-37"><a href="#cb7-37"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> lv<span class="op">);</span></span>
<span id="cb7-38"><a href="#cb7-38"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
<span id="cb7-39"><a href="#cb7-39"></a><span class="op">}</span></span>
<span id="cb7-3"><a href="#cb7-3"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb7-4"><a href="#cb7-4"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-5"><a href="#cb7-5"></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="cb7-6"><a href="#cb7-6"></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="cb7-7"><a href="#cb7-7"></a><span class="op">}</span></span>
<span id="cb7-8"><a href="#cb7-8"></a></span>
<span id="cb7-9"><a href="#cb7-9"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb7-10"><a href="#cb7-10"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-11"><a href="#cb7-11"></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="cb7-12"><a href="#cb7-12"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> gtk_application_window_new <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb7-13"><a href="#cb7-13"></a> gtk_window_set_default_size <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="dv">600</span><span class="op">,</span> <span class="dv">400</span><span class="op">);</span></span>
<span id="cb7-14"><a href="#cb7-14"></a> GtkWidget <span class="op">*</span>scr <span class="op">=</span> gtk_scrolled_window_new <span class="op">();</span></span>
<span id="cb7-15"><a href="#cb7-15"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> scr<span class="op">);</span></span>
<span id="cb7-16"><a href="#cb7-16"></a></span>
<span id="cb7-17"><a href="#cb7-17"></a> <span class="dt">char</span> <span class="op">*</span>array<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span></span>
<span id="cb7-18"><a href="#cb7-18"></a> <span class="st">&quot;one&quot;</span><span class="op">,</span> <span class="st">&quot;two&quot;</span><span class="op">,</span> <span class="st">&quot;three&quot;</span><span class="op">,</span> <span class="st">&quot;four&quot;</span><span class="op">,</span> NULL</span>
<span id="cb7-19"><a href="#cb7-19"></a> <span class="op">};</span></span>
<span id="cb7-20"><a href="#cb7-20"></a> GtkStringList <span class="op">*</span>sl <span class="op">=</span> gtk_string_list_new <span class="op">((</span><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span> <span class="dt">const</span> <span class="op">*)</span> array<span class="op">);</span></span>
<span id="cb7-21"><a href="#cb7-21"></a> GtkSingleSelection <span class="op">*</span>ss <span class="op">=</span> gtk_single_selection_new <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>sl<span class="op">));</span></span>
<span id="cb7-22"><a href="#cb7-22"></a></span>
<span id="cb7-23"><a href="#cb7-23"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>ui_string <span class="op">=</span></span>
<span id="cb7-24"><a href="#cb7-24"></a><span class="st">&quot;&lt;interface&gt;&quot;</span></span>
<span id="cb7-25"><a href="#cb7-25"></a> <span class="st">&quot;&lt;template class=</span><span class="sc">\&quot;</span><span class="st">GtkListItem</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb7-26"><a href="#cb7-26"></a> <span class="st">&quot;&lt;property name=</span><span class="sc">\&quot;</span><span class="st">child</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb7-27"><a href="#cb7-27"></a> <span class="st">&quot;&lt;object class=</span><span class="sc">\&quot;</span><span class="st">GtkLabel</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb7-28"><a href="#cb7-28"></a> <span class="st">&quot;&lt;binding name=</span><span class="sc">\&quot;</span><span class="st">label</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb7-29"><a href="#cb7-29"></a> <span class="st">&quot;&lt;lookup name=</span><span class="sc">\&quot;</span><span class="st">string</span><span class="sc">\&quot;</span><span class="st"> type=</span><span class="sc">\&quot;</span><span class="st">GtkStringObject</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb7-30"><a href="#cb7-30"></a> <span class="st">&quot;&lt;lookup name=</span><span class="sc">\&quot;</span><span class="st">item</span><span class="sc">\&quot;</span><span class="st">&gt;GtkListItem&lt;/lookup&gt;&quot;</span></span>
<span id="cb7-31"><a href="#cb7-31"></a> <span class="st">&quot;&lt;/lookup&gt;&quot;</span></span>
<span id="cb7-32"><a href="#cb7-32"></a> <span class="st">&quot;&lt;/binding&gt;&quot;</span></span>
<span id="cb7-33"><a href="#cb7-33"></a> <span class="st">&quot;&lt;/object&gt;&quot;</span></span>
<span id="cb7-34"><a href="#cb7-34"></a> <span class="st">&quot;&lt;/property&gt;&quot;</span></span>
<span id="cb7-35"><a href="#cb7-35"></a> <span class="st">&quot;&lt;/template&gt;&quot;</span></span>
<span id="cb7-36"><a href="#cb7-36"></a><span class="st">&quot;&lt;/interface&gt;&quot;</span></span>
<span id="cb7-37"><a href="#cb7-37"></a><span class="op">;</span></span>
<span id="cb7-38"><a href="#cb7-38"></a> GBytes <span class="op">*</span>gbytes <span class="op">=</span> g_bytes_new_static <span class="op">(</span>ui_string<span class="op">,</span> strlen <span class="op">(</span>ui_string<span class="op">));</span></span>
<span id="cb7-39"><a href="#cb7-39"></a> GtkListItemFactory <span class="op">*</span>factory <span class="op">=</span> gtk_builder_list_item_factory_new_from_bytes <span class="op">(</span>NULL<span class="op">,</span> gbytes<span class="op">);</span></span>
<span id="cb7-40"><a href="#cb7-40"></a></span>
<span id="cb7-41"><a href="#cb7-41"></a><span class="co">/* ----- main ----- */</span></span>
<span id="cb7-42"><a href="#cb7-42"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.list2&quot;</span></span>
<span id="cb7-43"><a href="#cb7-43"></a></span>
<span id="cb7-44"><a href="#cb7-44"></a><span class="dt">int</span></span>
<span id="cb7-45"><a href="#cb7-45"></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="cb7-46"><a href="#cb7-46"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb7-47"><a href="#cb7-47"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb7-48"><a href="#cb7-48"></a></span>
<span id="cb7-49"><a href="#cb7-49"></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="cb7-50"><a href="#cb7-50"></a></span>
<span id="cb7-51"><a href="#cb7-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="cb7-41"><a href="#cb7-41"></a> GtkWidget <span class="op">*</span>lv <span class="op">=</span> gtk_list_view_new <span class="op">(</span>GTK_SELECTION_MODEL <span class="op">(</span>ss<span class="op">),</span> factory<span class="op">);</span></span>
<span id="cb7-42"><a href="#cb7-42"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> lv<span class="op">);</span></span>
<span id="cb7-43"><a href="#cb7-43"></a><span class="op">}</span></span>
<span id="cb7-44"><a href="#cb7-44"></a></span>
<span id="cb7-45"><a href="#cb7-45"></a><span class="co">/* ----- main ----- */</span></span>
<span id="cb7-46"><a href="#cb7-46"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.list2&quot;</span></span>
<span id="cb7-47"><a href="#cb7-47"></a></span>
<span id="cb7-48"><a href="#cb7-48"></a><span class="dt">int</span></span>
<span id="cb7-49"><a href="#cb7-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="cb7-50"><a href="#cb7-50"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb7-51"><a href="#cb7-51"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb7-52"><a href="#cb7-52"></a></span>
<span id="cb7-53"><a href="#cb7-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="cb7-54"><a href="#cb7-54"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb7-55"><a href="#cb7-55"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb7-56"><a href="#cb7-56"></a><span class="op">}</span></span></code></pre></div>
<span id="cb7-53"><a href="#cb7-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="cb7-54"><a href="#cb7-54"></a></span>
<span id="cb7-55"><a href="#cb7-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="cb7-56"><a href="#cb7-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="cb7-57"><a href="#cb7-57"></a></span>
<span id="cb7-58"><a href="#cb7-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="cb7-59"><a href="#cb7-59"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb7-60"><a href="#cb7-60"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb7-61"><a href="#cb7-61"></a><span class="op">}</span></span></code></pre></div>
<p>No signal handler is needed for GtkBulderListItemFactory.
GtkSingleSelection is used, so user can select one item at a time.</p>
<p>Because this is a small program, the ui data is given as a
@ -482,37 +488,33 @@ closure tag is appropriate in this case. Closure tag specifies a
function and the type of the return value of the function.</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>get_file_name <span class="op">(</span>GtkListItem <span class="op">*</span>item<span class="op">,</span> GFileInfo <span class="op">*</span>info<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(!</span> G_IS_FILE_INFO <span class="op">(</span>info<span class="op">))</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> NULL<span class="op">;</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> g_strdup <span class="op">(</span>g_file_info_get_name <span class="op">(</span>info<span class="op">));</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;&lt;interface&gt;&quot;</span></span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;template class=</span><span class="sc">\&quot;</span><span class="st">GtkListItem</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;property name=</span><span class="sc">\&quot;</span><span class="st">child</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;object class=</span><span class="sc">\&quot;</span><span class="st">GtkLabel</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;binding name=</span><span class="sc">\&quot;</span><span class="st">label</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;closure type=</span><span class="sc">\&quot;</span><span class="st">gchararray</span><span class="sc">\&quot;</span><span class="st"> function=</span><span class="sc">\&quot;</span><span class="st">get_file_name</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;lookup name=</span><span class="sc">\&quot;</span><span class="st">item</span><span class="sc">\&quot;</span><span class="st">&gt;GtkListItem&lt;/lookup&gt;&quot;</span></span>
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;/closure&gt;&quot;</span></span>
<span id="cb10-20"><a href="#cb10-20" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;/binding&gt;&quot;</span></span>
<span id="cb10-21"><a href="#cb10-21" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;/object&gt;&quot;</span></span>
<span id="cb10-22"><a href="#cb10-22" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;/property&gt;&quot;</span></span>
<span id="cb10-23"><a href="#cb10-23" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;/template&gt;&quot;</span></span>
<span id="cb10-24"><a href="#cb10-24" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;&lt;/interface&gt;&quot;</span></span></code></pre></div>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> G_IS_FILE_INFO <span class="op">(</span>info<span class="op">)</span> <span class="op">?</span> g_strdup <span class="op">(</span>g_file_info_get_name <span class="op">(</span>info<span class="op">))</span> <span class="op">:</span> NULL<span class="op">;</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;&lt;interface&gt;&quot;</span></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;template class=</span><span class="sc">\&quot;</span><span class="st">GtkListItem</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;property name=</span><span class="sc">\&quot;</span><span class="st">child</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;object class=</span><span class="sc">\&quot;</span><span class="st">GtkLabel</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;binding name=</span><span class="sc">\&quot;</span><span class="st">label</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;closure type=</span><span class="sc">\&quot;</span><span class="st">gchararray</span><span class="sc">\&quot;</span><span class="st"> function=</span><span class="sc">\&quot;</span><span class="st">get_file_name</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;lookup name=</span><span class="sc">\&quot;</span><span class="st">item</span><span class="sc">\&quot;</span><span class="st">&gt;GtkListItem&lt;/lookup&gt;&quot;</span></span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;/closure&gt;&quot;</span></span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;/binding&gt;&quot;</span></span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;/object&gt;&quot;</span></span>
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;/property&gt;&quot;</span></span>
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;&lt;/template&gt;&quot;</span></span>
<span id="cb10-20"><a href="#cb10-20" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;&lt;/interface&gt;&quot;</span></span></code></pre></div>
<ul>
<li>The string “gchararray” is the type name of strings. The type
“gchar” is the same as “char”. Therefore, “gchararray” is “an array of
char type”, which is the same as string type. It is used to get the type
of GValue object. GValue is a generic value and it can contain various
type of values. For example, the type name can be gboolean, gchar
(char), gint (int), gfloat (float), gdouble (double), gchararray (char
*) and so on. These type names are the names of the fundamental types
that are registered to the type system. See <a
<li>The string “gchararray” is a type name. The type “gchar” is a type
name and it is the same as C type “char”. Therefore, “gchararray” is “an
array of char type”, which is the same as string type. It is used to get
the type of GValue object. GValue is a generic value and it can contain
various type of values. For example, the type name can be gboolean,
gchar (char), gint (int), gfloat (float), gdouble (double), gchararray
(char *) and so on. These type names are the names of the fundamental
types that are registered to the type system. See <a
href="https://github.com/ToshioCP/Gobject-tutorial/blob/main/gfm/sec5.md#gvalue">GObject
tutorial</a>.</li>
<li>Closure tag has type attribute and function attribute. Function
@ -523,14 +525,16 @@ the function.
<code>&lt;lookup name="item"&gt;GtkListItem&lt;/lookup&gt;</code> gives
the value of the item property of the GtkListItem. This will be the
second argument of the function. The first parameter is always the
GListItem instance.</li>
<li><code>gtk_file_name</code> function first checks the
<code>info</code> parameter. Because it can be NULL when GListItem
<code>item</code> is unbounded. If its GFileInfo, it returns the
filename. The filename is owned by GFileInfo object. So, the function
<code>get_file_name</code> duplicates the string to own the newly
created one. Closure tag binds the property of the outer tag (GtkLabel)
to the filename.</li>
GListItem instance, which is a this object. The this object is
explained in section 28.</li>
<li><code>gtk_file_name</code> function is the callback function for the
closure tag. It first checks the <code>info</code> parameter. Because it
can be NULL when GListItem <code>item</code> is unbounded. If its
GFileInfo, it returns the copied filename. Because the return value
(filename) of <code>g_file_info_get_name</code> is owned by GFileInfo
object. So, the the string needs to be duplicated to give the ownership
to the caller. Binding tag binds the “label” property of the GtkLabel to
the closure tag.</li>
</ul>
<p>The whole program (<code>list3.c</code>) is as follows. The program
is located in src/misc directory.</p>
@ -539,70 +543,67 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
<span id="cb11-2"><a href="#cb11-2"></a></span>
<span id="cb11-3"><a href="#cb11-3"></a><span class="dt">char</span> <span class="op">*</span></span>
<span id="cb11-4"><a href="#cb11-4"></a>get_file_name <span class="op">(</span>GtkListItem <span class="op">*</span>item<span class="op">,</span> GFileInfo <span class="op">*</span>info<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-5"><a href="#cb11-5"></a> <span class="cf">if</span> <span class="op">(!</span> G_IS_FILE_INFO <span class="op">(</span>info<span class="op">))</span></span>
<span id="cb11-6"><a href="#cb11-6"></a> <span class="cf">return</span> NULL<span class="op">;</span></span>
<span id="cb11-7"><a href="#cb11-7"></a> <span class="cf">else</span></span>
<span id="cb11-8"><a href="#cb11-8"></a> <span class="cf">return</span> g_strdup <span class="op">(</span>g_file_info_get_name <span class="op">(</span>info<span class="op">));</span></span>
<span id="cb11-9"><a href="#cb11-9"></a><span class="op">}</span></span>
<span id="cb11-10"><a href="#cb11-10"></a></span>
<span id="cb11-11"><a href="#cb11-11"></a><span class="co">/* ----- activate, open, startup handlers ----- */</span></span>
<span id="cb11-12"><a href="#cb11-12"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb11-13"><a href="#cb11-13"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-14"><a href="#cb11-14"></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="cb11-15"><a href="#cb11-15"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> gtk_application_window_new <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb11-16"><a href="#cb11-16"></a> gtk_window_set_default_size <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="dv">600</span><span class="op">,</span> <span class="dv">400</span><span class="op">);</span></span>
<span id="cb11-17"><a href="#cb11-17"></a> GtkWidget <span class="op">*</span>scr <span class="op">=</span> gtk_scrolled_window_new <span class="op">();</span></span>
<span id="cb11-18"><a href="#cb11-18"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> scr<span class="op">);</span></span>
<span id="cb11-19"><a href="#cb11-19"></a></span>
<span id="cb11-20"><a href="#cb11-20"></a> GFile <span class="op">*</span>file <span class="op">=</span> g_file_new_for_path <span class="op">(</span><span class="st">&quot;.&quot;</span><span class="op">);</span></span>
<span id="cb11-21"><a href="#cb11-21"></a> GtkDirectoryList <span class="op">*</span>dl <span class="op">=</span> gtk_directory_list_new <span class="op">(</span><span class="st">&quot;standard::name&quot;</span><span class="op">,</span> file<span class="op">);</span></span>
<span id="cb11-22"><a href="#cb11-22"></a> g_object_unref <span class="op">(</span>file<span class="op">);</span></span>
<span id="cb11-23"><a href="#cb11-23"></a> GtkNoSelection <span class="op">*</span>ns <span class="op">=</span> gtk_no_selection_new <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>dl<span class="op">));</span></span>
<span id="cb11-24"><a href="#cb11-24"></a></span>
<span id="cb11-25"><a href="#cb11-25"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>ui_string <span class="op">=</span></span>
<span id="cb11-26"><a href="#cb11-26"></a><span class="st">&quot;&lt;interface&gt;&quot;</span></span>
<span id="cb11-27"><a href="#cb11-27"></a> <span class="st">&quot;&lt;template class=</span><span class="sc">\&quot;</span><span class="st">GtkListItem</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb11-28"><a href="#cb11-28"></a> <span class="st">&quot;&lt;property name=</span><span class="sc">\&quot;</span><span class="st">child</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb11-29"><a href="#cb11-29"></a> <span class="st">&quot;&lt;object class=</span><span class="sc">\&quot;</span><span class="st">GtkLabel</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb11-30"><a href="#cb11-30"></a> <span class="st">&quot;&lt;binding name=</span><span class="sc">\&quot;</span><span class="st">label</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb11-31"><a href="#cb11-31"></a> <span class="st">&quot;&lt;closure type=</span><span class="sc">\&quot;</span><span class="st">gchararray</span><span class="sc">\&quot;</span><span class="st"> function=</span><span class="sc">\&quot;</span><span class="st">get_file_name</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb11-32"><a href="#cb11-32"></a> <span class="st">&quot;&lt;lookup name=</span><span class="sc">\&quot;</span><span class="st">item</span><span class="sc">\&quot;</span><span class="st">&gt;GtkListItem&lt;/lookup&gt;&quot;</span></span>
<span id="cb11-33"><a href="#cb11-33"></a> <span class="st">&quot;&lt;/closure&gt;&quot;</span></span>
<span id="cb11-34"><a href="#cb11-34"></a> <span class="st">&quot;&lt;/binding&gt;&quot;</span></span>
<span id="cb11-35"><a href="#cb11-35"></a> <span class="st">&quot;&lt;/object&gt;&quot;</span></span>
<span id="cb11-36"><a href="#cb11-36"></a> <span class="st">&quot;&lt;/property&gt;&quot;</span></span>
<span id="cb11-37"><a href="#cb11-37"></a> <span class="st">&quot;&lt;/template&gt;&quot;</span></span>
<span id="cb11-38"><a href="#cb11-38"></a><span class="st">&quot;&lt;/interface&gt;&quot;</span></span>
<span id="cb11-39"><a href="#cb11-39"></a><span class="op">;</span></span>
<span id="cb11-40"><a href="#cb11-40"></a> GBytes <span class="op">*</span>gbytes <span class="op">=</span> g_bytes_new_static <span class="op">(</span>ui_string<span class="op">,</span> strlen <span class="op">(</span>ui_string<span class="op">));</span></span>
<span id="cb11-41"><a href="#cb11-41"></a> GtkListItemFactory <span class="op">*</span>factory <span class="op">=</span> gtk_builder_list_item_factory_new_from_bytes <span class="op">(</span>NULL<span class="op">,</span> gbytes<span class="op">);</span></span>
<span id="cb11-42"><a href="#cb11-42"></a></span>
<span id="cb11-43"><a href="#cb11-43"></a> GtkWidget <span class="op">*</span>lv <span class="op">=</span> gtk_list_view_new <span class="op">(</span>GTK_SELECTION_MODEL <span class="op">(</span>ns<span class="op">),</span> factory<span class="op">);</span></span>
<span id="cb11-44"><a href="#cb11-44"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> lv<span class="op">);</span></span>
<span id="cb11-45"><a href="#cb11-45"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
<span id="cb11-46"><a href="#cb11-46"></a><span class="op">}</span></span>
<span id="cb11-47"><a href="#cb11-47"></a></span>
<span id="cb11-48"><a href="#cb11-48"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb11-49"><a href="#cb11-49"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-50"><a href="#cb11-50"></a><span class="op">}</span></span>
<span id="cb11-5"><a href="#cb11-5"></a> <span class="cf">return</span> G_IS_FILE_INFO <span class="op">(</span>info<span class="op">)</span> <span class="op">?</span> g_strdup <span class="op">(</span>g_file_info_get_name <span class="op">(</span>info<span class="op">))</span> <span class="op">:</span> NULL<span class="op">;</span></span>
<span id="cb11-6"><a href="#cb11-6"></a><span class="op">}</span></span>
<span id="cb11-7"><a href="#cb11-7"></a></span>
<span id="cb11-8"><a href="#cb11-8"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb11-9"><a href="#cb11-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="cb11-10"><a href="#cb11-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="cb11-11"><a href="#cb11-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="cb11-12"><a href="#cb11-12"></a><span class="op">}</span></span>
<span id="cb11-13"><a href="#cb11-13"></a></span>
<span id="cb11-14"><a href="#cb11-14"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb11-15"><a href="#cb11-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="cb11-16"><a href="#cb11-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="cb11-17"><a href="#cb11-17"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> gtk_application_window_new <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb11-18"><a href="#cb11-18"></a> gtk_window_set_default_size <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="dv">600</span><span class="op">,</span> <span class="dv">400</span><span class="op">);</span></span>
<span id="cb11-19"><a href="#cb11-19"></a> GtkWidget <span class="op">*</span>scr <span class="op">=</span> gtk_scrolled_window_new <span class="op">();</span></span>
<span id="cb11-20"><a href="#cb11-20"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> scr<span class="op">);</span></span>
<span id="cb11-21"><a href="#cb11-21"></a></span>
<span id="cb11-22"><a href="#cb11-22"></a> GFile <span class="op">*</span>file <span class="op">=</span> g_file_new_for_path <span class="op">(</span><span class="st">&quot;.&quot;</span><span class="op">);</span></span>
<span id="cb11-23"><a href="#cb11-23"></a> GtkDirectoryList <span class="op">*</span>dl <span class="op">=</span> gtk_directory_list_new <span class="op">(</span><span class="st">&quot;standard::name&quot;</span><span class="op">,</span> file<span class="op">);</span></span>
<span id="cb11-24"><a href="#cb11-24"></a> g_object_unref <span class="op">(</span>file<span class="op">);</span></span>
<span id="cb11-25"><a href="#cb11-25"></a> GtkNoSelection <span class="op">*</span>ns <span class="op">=</span> gtk_no_selection_new <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>dl<span class="op">));</span></span>
<span id="cb11-26"><a href="#cb11-26"></a></span>
<span id="cb11-27"><a href="#cb11-27"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>ui_string <span class="op">=</span></span>
<span id="cb11-28"><a href="#cb11-28"></a><span class="st">&quot;&lt;interface&gt;&quot;</span></span>
<span id="cb11-29"><a href="#cb11-29"></a> <span class="st">&quot;&lt;template class=</span><span class="sc">\&quot;</span><span class="st">GtkListItem</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb11-30"><a href="#cb11-30"></a> <span class="st">&quot;&lt;property name=</span><span class="sc">\&quot;</span><span class="st">child</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb11-31"><a href="#cb11-31"></a> <span class="st">&quot;&lt;object class=</span><span class="sc">\&quot;</span><span class="st">GtkLabel</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb11-32"><a href="#cb11-32"></a> <span class="st">&quot;&lt;binding name=</span><span class="sc">\&quot;</span><span class="st">label</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb11-33"><a href="#cb11-33"></a> <span class="st">&quot;&lt;closure type=</span><span class="sc">\&quot;</span><span class="st">gchararray</span><span class="sc">\&quot;</span><span class="st"> function=</span><span class="sc">\&quot;</span><span class="st">get_file_name</span><span class="sc">\&quot;</span><span class="st">&gt;&quot;</span></span>
<span id="cb11-34"><a href="#cb11-34"></a> <span class="st">&quot;&lt;lookup name=</span><span class="sc">\&quot;</span><span class="st">item</span><span class="sc">\&quot;</span><span class="st">&gt;GtkListItem&lt;/lookup&gt;&quot;</span></span>
<span id="cb11-35"><a href="#cb11-35"></a> <span class="st">&quot;&lt;/closure&gt;&quot;</span></span>
<span id="cb11-36"><a href="#cb11-36"></a> <span class="st">&quot;&lt;/binding&gt;&quot;</span></span>
<span id="cb11-37"><a href="#cb11-37"></a> <span class="st">&quot;&lt;/object&gt;&quot;</span></span>
<span id="cb11-38"><a href="#cb11-38"></a> <span class="st">&quot;&lt;/property&gt;&quot;</span></span>
<span id="cb11-39"><a href="#cb11-39"></a> <span class="st">&quot;&lt;/template&gt;&quot;</span></span>
<span id="cb11-40"><a href="#cb11-40"></a><span class="st">&quot;&lt;/interface&gt;&quot;</span></span>
<span id="cb11-41"><a href="#cb11-41"></a><span class="op">;</span></span>
<span id="cb11-42"><a href="#cb11-42"></a> GBytes <span class="op">*</span>gbytes <span class="op">=</span> g_bytes_new_static <span class="op">(</span>ui_string<span class="op">,</span> strlen <span class="op">(</span>ui_string<span class="op">));</span></span>
<span id="cb11-43"><a href="#cb11-43"></a> GtkListItemFactory <span class="op">*</span>factory <span class="op">=</span> gtk_builder_list_item_factory_new_from_bytes <span class="op">(</span>NULL<span class="op">,</span> gbytes<span class="op">);</span></span>
<span id="cb11-44"><a href="#cb11-44"></a></span>
<span id="cb11-45"><a href="#cb11-45"></a> GtkWidget <span class="op">*</span>lv <span class="op">=</span> gtk_list_view_new <span class="op">(</span>GTK_SELECTION_MODEL <span class="op">(</span>ns<span class="op">),</span> factory<span class="op">);</span></span>
<span id="cb11-46"><a href="#cb11-46"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> lv<span class="op">);</span></span>
<span id="cb11-47"><a href="#cb11-47"></a><span class="op">}</span></span>
<span id="cb11-48"><a href="#cb11-48"></a></span>
<span id="cb11-49"><a href="#cb11-49"></a><span class="co">/* ----- main ----- */</span></span>
<span id="cb11-50"><a href="#cb11-50"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.list3&quot;</span></span>
<span id="cb11-51"><a href="#cb11-51"></a></span>
<span id="cb11-52"><a href="#cb11-52"></a><span class="co">/* ----- main ----- */</span></span>
<span id="cb11-53"><a href="#cb11-53"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.list3&quot;</span></span>
<span id="cb11-54"><a href="#cb11-54"></a></span>
<span id="cb11-55"><a href="#cb11-55"></a><span class="dt">int</span></span>
<span id="cb11-56"><a href="#cb11-56"></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="cb11-57"><a href="#cb11-57"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb11-58"><a href="#cb11-58"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb11-59"><a href="#cb11-59"></a></span>
<span id="cb11-60"><a href="#cb11-60"></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="cb11-52"><a href="#cb11-52"></a><span class="dt">int</span></span>
<span id="cb11-53"><a href="#cb11-53"></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="cb11-54"><a href="#cb11-54"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb11-55"><a href="#cb11-55"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb11-56"><a href="#cb11-56"></a></span>
<span id="cb11-57"><a href="#cb11-57"></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="cb11-58"><a href="#cb11-58"></a></span>
<span id="cb11-59"><a href="#cb11-59"></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="cb11-60"><a href="#cb11-60"></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="cb11-61"><a href="#cb11-61"></a></span>
<span id="cb11-62"><a href="#cb11-62"></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="cb11-63"><a href="#cb11-63"></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="cb11-64"><a href="#cb11-64"></a></span>
<span id="cb11-65"><a href="#cb11-65"></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="cb11-66"><a href="#cb11-66"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb11-67"><a href="#cb11-67"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb11-68"><a href="#cb11-68"></a><span class="op">}</span></span></code></pre></div>
<span id="cb11-62"><a href="#cb11-62"></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="cb11-63"><a href="#cb11-63"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb11-64"><a href="#cb11-64"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb11-65"><a href="#cb11-65"></a><span class="op">}</span></span></code></pre></div>
<p>The ui data (xml data above) is used to build the GListItem template
at runtime. GtkBuilder refers to the symbol table to find the function
<code>get_file_name</code>.</p>

View file

@ -396,26 +396,18 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
<span id="cb8-2"><a href="#cb8-2"></a>get_icon <span class="op">(</span>GtkListItem <span class="op">*</span>item<span class="op">,</span> GFileInfo <span class="op">*</span>info<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-3"><a href="#cb8-3"></a> GIcon <span class="op">*</span>icon<span class="op">;</span></span>
<span id="cb8-4"><a href="#cb8-4"></a></span>
<span id="cb8-5"><a href="#cb8-5"></a> <span class="cf">if</span> <span class="op">(!</span> G_IS_FILE_INFO <span class="op">(</span>info<span class="op">))</span></span>
<span id="cb8-6"><a href="#cb8-6"></a> <span class="cf">return</span> NULL<span class="op">;</span></span>
<span id="cb8-7"><a href="#cb8-7"></a> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb8-8"><a href="#cb8-8"></a> icon <span class="op">=</span> g_file_info_get_icon <span class="op">(</span>info<span class="op">);</span></span>
<span id="cb8-9"><a href="#cb8-9"></a> g_object_ref <span class="op">(</span>icon<span class="op">);</span></span>
<span id="cb8-10"><a href="#cb8-10"></a> <span class="cf">return</span> icon<span class="op">;</span></span>
<span id="cb8-11"><a href="#cb8-11"></a> <span class="op">}</span></span>
<span id="cb8-12"><a href="#cb8-12"></a><span class="op">}</span></span>
<span id="cb8-13"><a href="#cb8-13"></a></span>
<span id="cb8-14"><a href="#cb8-14"></a><span class="dt">char</span> <span class="op">*</span></span>
<span id="cb8-15"><a href="#cb8-15"></a>get_file_name <span class="op">(</span>GtkListItem <span class="op">*</span>item<span class="op">,</span> GFileInfo <span class="op">*</span>info<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-16"><a href="#cb8-16"></a> <span class="cf">if</span> <span class="op">(!</span> G_IS_FILE_INFO <span class="op">(</span>info<span class="op">))</span></span>
<span id="cb8-17"><a href="#cb8-17"></a> <span class="cf">return</span> NULL<span class="op">;</span></span>
<span id="cb8-18"><a href="#cb8-18"></a> <span class="cf">else</span></span>
<span id="cb8-19"><a href="#cb8-19"></a> <span class="cf">return</span> g_strdup <span class="op">(</span>g_file_info_get_name <span class="op">(</span>info<span class="op">));</span></span>
<span id="cb8-20"><a href="#cb8-20"></a><span class="op">}</span></span></code></pre></div>
<p>One important thing is the ownership of the return values. When
GtkExpression (closure tag creates a GtkCClosureExpression a child
class of GtkExpression) is evaluated, the value is owned by the caller.
So, <code>g_obect_ref</code> or <code>g_strdup</code> is necessary.</p>
<span id="cb8-5"><a href="#cb8-5"></a> <span class="co">/* g_file_info_get_icon can return NULL */</span></span>
<span id="cb8-6"><a href="#cb8-6"></a> icon <span class="op">=</span> G_IS_FILE_INFO <span class="op">(</span>info<span class="op">)</span> <span class="op">?</span> g_file_info_get_icon <span class="op">(</span>info<span class="op">)</span> <span class="op">:</span> NULL<span class="op">;</span></span>
<span id="cb8-7"><a href="#cb8-7"></a> <span class="cf">return</span> icon <span class="op">?</span> g_object_ref <span class="op">(</span>icon<span class="op">)</span> <span class="op">:</span> NULL<span class="op">;</span></span>
<span id="cb8-8"><a href="#cb8-8"></a><span class="op">}</span></span>
<span id="cb8-9"><a href="#cb8-9"></a></span>
<span id="cb8-10"><a href="#cb8-10"></a><span class="dt">char</span> <span class="op">*</span></span>
<span id="cb8-11"><a href="#cb8-11"></a>get_file_name <span class="op">(</span>GtkListItem <span class="op">*</span>item<span class="op">,</span> GFileInfo <span class="op">*</span>info<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-12"><a href="#cb8-12"></a> <span class="cf">return</span> G_IS_FILE_INFO <span class="op">(</span>info<span class="op">)</span> <span class="op">?</span> g_strdup <span class="op">(</span>g_file_info_get_name <span class="op">(</span>info<span class="op">))</span> <span class="op">:</span> NULL<span class="op">;</span></span>
<span id="cb8-13"><a href="#cb8-13"></a><span class="op">}</span></span></code></pre></div>
<p>One important thing is the ownership of the return values. The return
value is owned by the caller. So, <code>g_obect_ref</code> or
<code>g_strdup</code> is necessary.</p>
<h2 id="an-activate-signal-handler-of-the-button-action">An activate
signal handler of the button action</h2>
<p>An activate signal handler <code>view_activate</code> switches the

View file

@ -24,12 +24,12 @@ There are two cases.
One is the index starts from one (one-based) and the other is from zero (zero-based).
Gio provides GListModel interface.
It is a zero-based list of the same type of GObject descendants, or objects that implement the same interface.
It is a zero-based list and its items are the same type of GObject descendants, or objects that implement the same interface.
An object implements GListModel is not a widget.
So, the list is not displayed on the screen directly.
There's another object GtkListView which is a widget to display the list.
The items in the list need to be connected to the items in GtkListView.
GtkListItemFactory object maps items in the list to GListView.
GtkListItemFactory instance maps items in the list to GListView.
![List](../image/list.png)
@ -64,8 +64,8 @@ GtkSelectionModel is an interface to support for selections.
Thanks to this model, user can select items by clicking on them.
It is implemented by GtkMultiSelection, GtkNoSelection and GtkSingleSelection objects.
These three objects are usually enough to build an application.
They are created with GListModel.
You can also create them alone and add GListModel later.
They are created with another GListModel.
You can also create them alone and add a GListModel later.
- GtkMultiSelection supports multiple selection.
- GtkNoSelection supports no selection. This is a wrapper to GListModel when GtkSelectionModel is needed.
@ -87,7 +87,7 @@ This is very effective to restrain the growth of memory consumption so that GLis
## GtkListItemFactory
GtkListItemFactory creates or recycles GtkListItem and connects it with an item of the list model.
There are two child objects of this factory, GtkSignalListItemFactory and GtkBuilderListItemFactory.
There are two child classes of this factory, GtkSignalListItemFactory and GtkBuilderListItemFactory.
### GtkSignalListItemFactory
@ -96,7 +96,7 @@ There are four signals.
1. "setup" is emitted to set up GtkListItem object.
A user sets its child widget in the handler.
For example, creates a GtkLabel widget and sets the child property of GtkListItem with it.
For example, creates a GtkLabel widget and sets the child property of the GtkListItem to it.
This setting is kept even the GtkListItem instance is recycled (to bind to another item of GListModel).
2. "bind" is emitted to bind an item in the list model to the widget.
For example, a user gets the item from "item" property of the GtkListItem instance.
@ -119,16 +119,16 @@ GtkNoSelection is used, so user can't select any item.
4 setup_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
5 GtkWidget *lb = gtk_label_new (NULL);
6 gtk_list_item_set_child (listitem, lb);
7 }
8
9 static void
10 bind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
11 GtkWidget *lb = gtk_list_item_get_child (listitem);
12 /* Strobj is owned by the instance. Caller mustn't change or destroy it. */
13 GtkStringObject *strobj = gtk_list_item_get_item (listitem);
14 const char *text = gtk_string_object_get_string (strobj);
15
16 gtk_label_set_text (GTK_LABEL (lb), text);
7 /* Because gtk_list_item_set_child sunk the floating reference of lb, releasing (unref) isn't necessary for lb. */
8 }
9
10 static void
11 bind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
12 GtkWidget *lb = gtk_list_item_get_child (listitem);
13 /* Strobj is owned by the instance. Caller mustn't change or destroy it. */
14 GtkStringObject *strobj = gtk_list_item_get_item (listitem);
15 /* The string returned by gtk_string_object_get_string is owned by the instance. */
16 gtk_label_set_text (GTK_LABEL (lb), gtk_string_object_get_string (strobj));
17 }
18
19 static void
@ -138,8 +138,8 @@ GtkNoSelection is used, so user can't select any item.
23
24 static void
25 teardown_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
26 gtk_list_item_set_child (listitem, NULL);
27 /* The previous child is destroyed automatically. */
26 /* There's nothing to do here. */
27 /* GtkListItem instance will be destroyed soon. You don't need to set the child to NULL. */
28 }
29
30 static void
@ -162,30 +162,31 @@ GtkNoSelection is used, so user can't select any item.
47 GtkListItemFactory *factory = gtk_signal_list_item_factory_new ();
48 g_signal_connect (factory, "setup", G_CALLBACK (setup_cb), NULL);
49 g_signal_connect (factory, "bind", G_CALLBACK (bind_cb), NULL);
50 g_signal_connect (factory, "unbind", G_CALLBACK (unbind_cb), NULL);
51 g_signal_connect (factory, "teardown", G_CALLBACK (teardown_cb), NULL);
52
53 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
54 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
55 gtk_window_present (GTK_WINDOW (win));
56 }
57
58 /* ----- main ----- */
59 #define APPLICATION_ID "com.github.ToshioCP.list1"
60
61 int
62 main (int argc, char **argv) {
63 GtkApplication *app;
64 int stat;
65
66 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
67
68 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
69
70 stat =g_application_run (G_APPLICATION (app), argc, argv);
71 g_object_unref (app);
72 return stat;
73 }
50 /* The following two lines can be left out. The handlers do nothing. */
51 g_signal_connect (factory, "unbind", G_CALLBACK (unbind_cb), NULL);
52 g_signal_connect (factory, "teardown", G_CALLBACK (teardown_cb), NULL);
53
54 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
55 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
56 gtk_window_present (GTK_WINDOW (win));
57 }
58
59 /* ----- main ----- */
60 #define APPLICATION_ID "com.github.ToshioCP.list1"
61
62 int
63 main (int argc, char **argv) {
64 GtkApplication *app;
65 int stat;
66
67 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
68
69 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
70
71 stat =g_application_run (G_APPLICATION (app), argc, argv);
72 g_object_unref (app);
73 return stat;
74 }
~~~
The file `list1.c` is located under the directory [src/misc](../src/misc).
@ -236,18 +237,18 @@ And its child property is GtkLabel object.
The factory sees this template and creates GtkLabel and sets the child property of GtkListItem.
This is the same as what setup handler of GtkSignalListItemFactory did.
Then, bind the label property of GtkLabel to string property of GtkStringObject.
The string object is referred to by item property of GtkListItem.
Then, bind the label property of the GtkLabel to the string property of a GtkStringObject.
The string object refers to the item property of the GtkListItem.
So, the lookup tag is like this:
~~~
string <- GtkStringObject <- item <- GtkListItem
label <- string <- GtkStringObject <- item <- GtkListItem
~~~
The last lookup tag has a content `GtkListItem`.
Usually, C type like `GtkListItem` doesn't appear in the content of tags.
This is a special case.
There is an explanation about it in the [GTK Development Blog](https://blog.gtk.org/2020/09/05/a-primer-on-gtklistview/) by Matthias Clasen.
There is an explanation in the [GTK Development Blog](https://blog.gtk.org/2020/09/05/a-primer-on-gtklistview/) by Matthias Clasen.
> Remember that the classname (GtkListItem) in a ui template is used as the “this” pointer referring to the object that is being instantiated.
@ -260,61 +261,66 @@ Its name is `list2.c` and located under [src/misc](../src/misc) directory.
~~~C
1 #include <gtk/gtk.h>
2
3 /* ----- activate, open, startup handlers ----- */
4 static void
5 app_activate (GApplication *application) {
6 GtkApplication *app = GTK_APPLICATION (application);
7 GtkWidget *win = gtk_application_window_new (app);
8 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
9 GtkWidget *scr = gtk_scrolled_window_new ();
10 gtk_window_set_child (GTK_WINDOW (win), scr);
11
12 char *array[] = {
13 "one", "two", "three", "four", NULL
14 };
15 GtkStringList *sl = gtk_string_list_new ((const char * const *) array);
16 GtkSingleSelection *ss = gtk_single_selection_new (G_LIST_MODEL (sl));
17
18 const char *ui_string =
19 "<interface>"
20 "<template class=\"GtkListItem\">"
21 "<property name=\"child\">"
22 "<object class=\"GtkLabel\">"
23 "<binding name=\"label\">"
24 "<lookup name=\"string\" type=\"GtkStringObject\">"
25 "<lookup name=\"item\">GtkListItem</lookup>"
26 "</lookup>"
27 "</binding>"
28 "</object>"
29 "</property>"
30 "</template>"
31 "</interface>"
32 ;
33 GBytes *gbytes = g_bytes_new_static (ui_string, strlen (ui_string));
34 GtkListItemFactory *factory = gtk_builder_list_item_factory_new_from_bytes (NULL, gbytes);
35
36 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ss), factory);
37 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
38 gtk_window_present (GTK_WINDOW (win));
39 }
3 static void
4 app_activate (GApplication *application) {
5 GtkApplication *app = GTK_APPLICATION (application);
6 gtk_window_present (gtk_application_get_active_window(app));
7 }
8
9 static void
10 app_startup (GApplication *application) {
11 GtkApplication *app = GTK_APPLICATION (application);
12 GtkWidget *win = gtk_application_window_new (app);
13 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
14 GtkWidget *scr = gtk_scrolled_window_new ();
15 gtk_window_set_child (GTK_WINDOW (win), scr);
16
17 char *array[] = {
18 "one", "two", "three", "four", NULL
19 };
20 GtkStringList *sl = gtk_string_list_new ((const char * const *) array);
21 GtkSingleSelection *ss = gtk_single_selection_new (G_LIST_MODEL (sl));
22
23 const char *ui_string =
24 "<interface>"
25 "<template class=\"GtkListItem\">"
26 "<property name=\"child\">"
27 "<object class=\"GtkLabel\">"
28 "<binding name=\"label\">"
29 "<lookup name=\"string\" type=\"GtkStringObject\">"
30 "<lookup name=\"item\">GtkListItem</lookup>"
31 "</lookup>"
32 "</binding>"
33 "</object>"
34 "</property>"
35 "</template>"
36 "</interface>"
37 ;
38 GBytes *gbytes = g_bytes_new_static (ui_string, strlen (ui_string));
39 GtkListItemFactory *factory = gtk_builder_list_item_factory_new_from_bytes (NULL, gbytes);
40
41 /* ----- main ----- */
42 #define APPLICATION_ID "com.github.ToshioCP.list2"
43
44 int
45 main (int argc, char **argv) {
46 GtkApplication *app;
47 int stat;
48
49 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
50
51 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
41 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ss), factory);
42 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
43 }
44
45 /* ----- main ----- */
46 #define APPLICATION_ID "com.github.ToshioCP.list2"
47
48 int
49 main (int argc, char **argv) {
50 GtkApplication *app;
51 int stat;
52
53 stat =g_application_run (G_APPLICATION (app), argc, argv);
54 g_object_unref (app);
55 return stat;
56 }
53 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
54
55 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
56 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
57
58 stat =g_application_run (G_APPLICATION (app), argc, argv);
59 g_object_unref (app);
60 return stat;
61 }
62
~~~
No signal handler is needed for GtkBulderListItemFactory.
@ -366,12 +372,8 @@ Closure tag specifies a function and the type of the return value of the functio
~~~C
const char *
get_file_name (GtkListItem *item, GFileInfo *info) {
if (! G_IS_FILE_INFO (info))
return NULL;
else
return g_strdup (g_file_info_get_name (info));
return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
}
... ...
... ...
@ -390,8 +392,8 @@ get_file_name (GtkListItem *item, GFileInfo *info) {
"</interface>"
~~~
- The string "gchararray" is the type name of strings.
The type "gchar" is the same as "char".
- The string "gchararray" is a type name.
The type "gchar" is a type name and it is the same as C type "char".
Therefore, "gchararray" is "an array of char type", which is the same as string type.
It is used to get the type of GValue object.
GValue is a generic value and it can contain various type of values.
@ -403,13 +405,15 @@ Function attribute specifies the function name and type attribute specifies the
The contents of closure tag (it is between \<closure...\> and\</closure\>) is parameters of the function.
`<lookup name="item">GtkListItem</lookup>` gives the value of the item property of the GtkListItem.
This will be the second argument of the function.
The first parameter is always the GListItem instance.
- `gtk_file_name` function first checks the `info` parameter.
The first parameter is always the GListItem instance, which is a 'this' object.
The 'this' object is explained in section 28.
- `gtk_file_name` function is the callback function for the closure tag.
It first checks the `info` parameter.
Because it can be NULL when GListItem `item` is unbounded.
If it's GFileInfo, it returns the filename.
The filename is owned by GFileInfo object.
So, the function `get_file_name` duplicates the string to own the newly created one.
Closure tag binds the property of the outer tag (GtkLabel) to the filename.
If it's GFileInfo, it returns the copied filename.
Because the return value (filename) of `g_file_info_get_name` is owned by GFileInfo object.
So, the the string needs to be duplicated to give the ownership to the caller.
Binding tag binds the "label" property of the GtkLabel to the closure tag.
The whole program (`list3.c`) is as follows.
The program is located in [src/misc](../src/misc) directory.
@ -419,70 +423,67 @@ The program is located in [src/misc](../src/misc) directory.
2
3 char *
4 get_file_name (GtkListItem *item, GFileInfo *info) {
5 if (! G_IS_FILE_INFO (info))
6 return NULL;
7 else
8 return g_strdup (g_file_info_get_name (info));
9 }
10
11 /* ----- activate, open, startup handlers ----- */
12 static void
13 app_activate (GApplication *application) {
14 GtkApplication *app = GTK_APPLICATION (application);
15 GtkWidget *win = gtk_application_window_new (app);
16 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
17 GtkWidget *scr = gtk_scrolled_window_new ();
18 gtk_window_set_child (GTK_WINDOW (win), scr);
19
20 GFile *file = g_file_new_for_path (".");
21 GtkDirectoryList *dl = gtk_directory_list_new ("standard::name", file);
22 g_object_unref (file);
23 GtkNoSelection *ns = gtk_no_selection_new (G_LIST_MODEL (dl));
24
25 const char *ui_string =
26 "<interface>"
27 "<template class=\"GtkListItem\">"
28 "<property name=\"child\">"
29 "<object class=\"GtkLabel\">"
30 "<binding name=\"label\">"
31 "<closure type=\"gchararray\" function=\"get_file_name\">"
32 "<lookup name=\"item\">GtkListItem</lookup>"
33 "</closure>"
34 "</binding>"
35 "</object>"
36 "</property>"
37 "</template>"
38 "</interface>"
39 ;
40 GBytes *gbytes = g_bytes_new_static (ui_string, strlen (ui_string));
41 GtkListItemFactory *factory = gtk_builder_list_item_factory_new_from_bytes (NULL, gbytes);
42
43 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
44 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
45 gtk_window_present (GTK_WINDOW (win));
46 }
47
48 static void
49 app_startup (GApplication *application) {
50 }
5 return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
6 }
7
8 static void
9 app_activate (GApplication *application) {
10 GtkApplication *app = GTK_APPLICATION (application);
11 gtk_window_present (gtk_application_get_active_window(app));
12 }
13
14 static void
15 app_startup (GApplication *application) {
16 GtkApplication *app = GTK_APPLICATION (application);
17 GtkWidget *win = gtk_application_window_new (app);
18 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
19 GtkWidget *scr = gtk_scrolled_window_new ();
20 gtk_window_set_child (GTK_WINDOW (win), scr);
21
22 GFile *file = g_file_new_for_path (".");
23 GtkDirectoryList *dl = gtk_directory_list_new ("standard::name", file);
24 g_object_unref (file);
25 GtkNoSelection *ns = gtk_no_selection_new (G_LIST_MODEL (dl));
26
27 const char *ui_string =
28 "<interface>"
29 "<template class=\"GtkListItem\">"
30 "<property name=\"child\">"
31 "<object class=\"GtkLabel\">"
32 "<binding name=\"label\">"
33 "<closure type=\"gchararray\" function=\"get_file_name\">"
34 "<lookup name=\"item\">GtkListItem</lookup>"
35 "</closure>"
36 "</binding>"
37 "</object>"
38 "</property>"
39 "</template>"
40 "</interface>"
41 ;
42 GBytes *gbytes = g_bytes_new_static (ui_string, strlen (ui_string));
43 GtkListItemFactory *factory = gtk_builder_list_item_factory_new_from_bytes (NULL, gbytes);
44
45 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
46 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
47 }
48
49 /* ----- main ----- */
50 #define APPLICATION_ID "com.github.ToshioCP.list3"
51
52 /* ----- main ----- */
53 #define APPLICATION_ID "com.github.ToshioCP.list3"
54
55 int
56 main (int argc, char **argv) {
57 GtkApplication *app;
58 int stat;
59
60 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
52 int
53 main (int argc, char **argv) {
54 GtkApplication *app;
55 int stat;
56
57 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
58
59 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
60 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
61
62 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
63 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
64
65 stat =g_application_run (G_APPLICATION (app), argc, argv);
66 g_object_unref (app);
67 return stat;
68 }
62 stat =g_application_run (G_APPLICATION (app), argc, argv);
63 g_object_unref (app);
64 return stat;
65 }
~~~
The ui data (xml data above) is used to build the GListItem template at runtime.

View file

@ -306,27 +306,19 @@ And a function `get_file_name` gets a filename from the GFileInfo object.
2 get_icon (GtkListItem *item, GFileInfo *info) {
3 GIcon *icon;
4
5 if (! G_IS_FILE_INFO (info))
6 return NULL;
7 else {
8 icon = g_file_info_get_icon (info);
9 g_object_ref (icon);
10 return icon;
11 }
12 }
13
14 char *
15 get_file_name (GtkListItem *item, GFileInfo *info) {
16 if (! G_IS_FILE_INFO (info))
17 return NULL;
18 else
19 return g_strdup (g_file_info_get_name (info));
20 }
5 /* g_file_info_get_icon can return NULL */
6 icon = G_IS_FILE_INFO (info) ? g_file_info_get_icon (info) : NULL;
7 return icon ? g_object_ref (icon) : NULL;
8 }
9
10 char *
11 get_file_name (GtkListItem *item, GFileInfo *info) {
12 return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
13 }
~~~
One important thing is the ownership of the return values.
When GtkExpression (closure tag creates a GtkCClosureExpression -- a child class of GtkExpression) is evaluated,
the value is owned by the caller.
The return value is owned by the caller.
So, `g_obect_ref` or `g_strdup` is necessary.
## An activate signal handler of the button action

View file

@ -88,21 +88,14 @@ GIcon *
get_icon (GtkListItem *item, GFileInfo *info) {
GIcon *icon;
if (! G_IS_FILE_INFO (info))
return NULL;
else {
icon = g_file_info_get_icon (info);
g_object_ref (icon);
return icon;
}
/* g_file_info_get_icon can return NULL */
icon = G_IS_FILE_INFO (info) ? g_file_info_get_icon (info) : NULL;
return icon ? g_object_ref (icon) : NULL;
}
char *
get_file_name (GtkListItem *item, GFileInfo *info) {
if (! G_IS_FILE_INFO (info))
return NULL;
else
return g_strdup (g_file_info_get_name (info));
return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
}
static void

View file

@ -88,21 +88,14 @@ GIcon *
get_icon (GtkListItem *item, GFileInfo *info) {
GIcon *icon;
if (! G_IS_FILE_INFO (info))
return NULL;
else {
icon = g_file_info_get_icon (info);
g_object_ref (icon);
return icon;
}
/* g_file_info_get_icon can return NULL */
icon = G_IS_FILE_INFO (info) ? g_file_info_get_icon (info) : NULL;
return icon ? g_object_ref (icon) : NULL;
}
char *
get_file_name (GtkListItem *item, GFileInfo *info) {
if (! G_IS_FILE_INFO (info))
return NULL;
else
return g_strdup (g_file_info_get_name (info));
return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
}
static void

View file

@ -4,6 +4,7 @@ static void
setup_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
GtkWidget *lb = gtk_label_new (NULL);
gtk_list_item_set_child (listitem, lb);
/* Because gtk_list_item_set_child sunk the floating reference of lb, releasing (unref) isn't necessary for lb. */
}
static void
@ -11,9 +12,8 @@ bind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_da
GtkWidget *lb = gtk_list_item_get_child (listitem);
/* Strobj is owned by the instance. Caller mustn't change or destroy it. */
GtkStringObject *strobj = gtk_list_item_get_item (listitem);
const char *text = gtk_string_object_get_string (strobj);
gtk_label_set_text (GTK_LABEL (lb), text);
/* The string returned by gtk_string_object_get_string is owned by the instance. */
gtk_label_set_text (GTK_LABEL (lb), gtk_string_object_get_string (strobj));
}
static void
@ -23,8 +23,8 @@ unbind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_
static void
teardown_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
gtk_list_item_set_child (listitem, NULL);
/* The previous child is destroyed automatically. */
/* There's nothing to do here. */
/* GtkListItem instance will be destroyed soon. You don't need to set the child to NULL. */
}
static void
@ -47,6 +47,7 @@ app_activate (GApplication *application) {
GtkListItemFactory *factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_cb), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (bind_cb), NULL);
/* The following two lines can be left out. The handlers do nothing. */
g_signal_connect (factory, "unbind", G_CALLBACK (unbind_cb), NULL);
g_signal_connect (factory, "teardown", G_CALLBACK (teardown_cb), NULL);

View file

@ -1,8 +1,13 @@
#include <gtk/gtk.h>
/* ----- activate, open, startup handlers ----- */
static void
app_activate (GApplication *application) {
GtkApplication *app = GTK_APPLICATION (application);
gtk_window_present (gtk_application_get_active_window(app));
}
static void
app_startup (GApplication *application) {
GtkApplication *app = GTK_APPLICATION (application);
GtkWidget *win = gtk_application_window_new (app);
gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
@ -35,7 +40,6 @@ app_activate (GApplication *application) {
GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ss), factory);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
gtk_window_present (GTK_WINDOW (win));
}
/* ----- main ----- */
@ -48,6 +52,7 @@ main (int argc, char **argv) {
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
stat =g_application_run (G_APPLICATION (app), argc, argv);

View file

@ -2,15 +2,17 @@
char *
get_file_name (GtkListItem *item, GFileInfo *info) {
if (! G_IS_FILE_INFO (info))
return NULL;
else
return g_strdup (g_file_info_get_name (info));
return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
}
/* ----- activate, open, startup handlers ----- */
static void
app_activate (GApplication *application) {
GtkApplication *app = GTK_APPLICATION (application);
gtk_window_present (gtk_application_get_active_window(app));
}
static void
app_startup (GApplication *application) {
GtkApplication *app = GTK_APPLICATION (application);
GtkWidget *win = gtk_application_window_new (app);
gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
@ -42,11 +44,6 @@ app_activate (GApplication *application) {
GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
gtk_window_present (GTK_WINDOW (win));
}
static void
app_startup (GApplication *application) {
}
/* ----- main ----- */

View file

@ -22,12 +22,12 @@ There are two cases.
One is the index starts from one (one-based) and the other is from zero (zero-based).
Gio provides GListModel interface.
It is a zero-based list of the same type of GObject descendants, or objects that implement the same interface.
It is a zero-based list and its items are the same type of GObject descendants, or objects that implement the same interface.
An object implements GListModel is not a widget.
So, the list is not displayed on the screen directly.
There's another object GtkListView which is a widget to display the list.
The items in the list need to be connected to the items in GtkListView.
GtkListItemFactory object maps items in the list to GListView.
GtkListItemFactory instance maps items in the list to GListView.
![List](../image/list.png){width=10cm height=7.5cm}
@ -79,8 +79,8 @@ GtkSelectionModel is an interface to support for selections.
Thanks to this model, user can select items by clicking on them.
It is implemented by GtkMultiSelection, GtkNoSelection and GtkSingleSelection objects.
These three objects are usually enough to build an application.
They are created with GListModel.
You can also create them alone and add GListModel later.
They are created with another GListModel.
You can also create them alone and add a GListModel later.
- GtkMultiSelection supports multiple selection.
- GtkNoSelection supports no selection. This is a wrapper to GListModel when GtkSelectionModel is needed.
@ -102,7 +102,7 @@ This is very effective to restrain the growth of memory consumption so that GLis
## GtkListItemFactory
GtkListItemFactory creates or recycles GtkListItem and connects it with an item of the list model.
There are two child objects of this factory, GtkSignalListItemFactory and GtkBuilderListItemFactory.
There are two child classes of this factory, GtkSignalListItemFactory and GtkBuilderListItemFactory.
### GtkSignalListItemFactory
@ -111,7 +111,7 @@ There are four signals.
1. "setup" is emitted to set up GtkListItem object.
A user sets its child widget in the handler.
For example, creates a GtkLabel widget and sets the child property of GtkListItem with it.
For example, creates a GtkLabel widget and sets the child property of the GtkListItem to it.
This setting is kept even the GtkListItem instance is recycled (to bind to another item of GListModel).
2. "bind" is emitted to bind an item in the list model to the widget.
For example, a user gets the item from "item" property of the GtkListItem instance.
@ -193,18 +193,18 @@ And its child property is GtkLabel object.
The factory sees this template and creates GtkLabel and sets the child property of GtkListItem.
This is the same as what setup handler of GtkSignalListItemFactory did.
Then, bind the label property of GtkLabel to string property of GtkStringObject.
The string object is referred to by item property of GtkListItem.
Then, bind the label property of the GtkLabel to the string property of a GtkStringObject.
The string object refers to the item property of the GtkListItem.
So, the lookup tag is like this:
~~~
string <- GtkStringObject <- item <- GtkListItem
label <- string <- GtkStringObject <- item <- GtkListItem
~~~
The last lookup tag has a content `GtkListItem`.
Usually, C type like `GtkListItem` doesn't appear in the content of tags.
This is a special case.
There is an explanation about it in the [GTK Development Blog](https://blog.gtk.org/2020/09/05/a-primer-on-gtklistview/) by Matthias Clasen.
There is an explanation in the [GTK Development Blog](https://blog.gtk.org/2020/09/05/a-primer-on-gtklistview/) by Matthias Clasen.
> Remember that the classname (GtkListItem) in a ui template is used as the “this” pointer referring to the object that is being instantiated.
@ -267,12 +267,8 @@ Closure tag specifies a function and the type of the return value of the functio
~~~C
const char *
get_file_name (GtkListItem *item, GFileInfo *info) {
if (! G_IS_FILE_INFO (info))
return NULL;
else
return g_strdup (g_file_info_get_name (info));
return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
}
... ...
... ...
@ -291,8 +287,8 @@ get_file_name (GtkListItem *item, GFileInfo *info) {
"</interface>"
~~~
- The string "gchararray" is the type name of strings.
The type "gchar" is the same as "char".
- The string "gchararray" is a type name.
The type "gchar" is a type name and it is the same as C type "char".
Therefore, "gchararray" is "an array of char type", which is the same as string type.
It is used to get the type of GValue object.
GValue is a generic value and it can contain various type of values.
@ -304,13 +300,15 @@ Function attribute specifies the function name and type attribute specifies the
The contents of closure tag (it is between \<closure...\> and\</closure\>) is parameters of the function.
`<lookup name="item">GtkListItem</lookup>` gives the value of the item property of the GtkListItem.
This will be the second argument of the function.
The first parameter is always the GListItem instance.
- `gtk_file_name` function first checks the `info` parameter.
The first parameter is always the GListItem instance, which is a 'this' object.
The 'this' object is explained in section 28.
- `gtk_file_name` function is the callback function for the closure tag.
It first checks the `info` parameter.
Because it can be NULL when GListItem `item` is unbounded.
If it's GFileInfo, it returns the filename.
The filename is owned by GFileInfo object.
So, the function `get_file_name` duplicates the string to own the newly created one.
Closure tag binds the property of the outer tag (GtkLabel) to the filename.
If it's GFileInfo, it returns the copied filename.
Because the return value (filename) of `g_file_info_get_name` is owned by GFileInfo object.
So, the the string needs to be duplicated to give the ownership to the caller.
Binding tag binds the "label" property of the GtkLabel to the closure tag.
The whole program (`list3.c`) is as follows.
The program is located in [src/misc](misc) directory.

View file

@ -159,8 +159,7 @@ list4/list4.c get_icon get_file_name
@@@
One important thing is the ownership of the return values.
When GtkExpression (closure tag creates a GtkCClosureExpression -- a child class of GtkExpression) is evaluated,
the value is owned by the caller.
The return value is owned by the caller.
So, `g_obect_ref` or `g_strdup` is necessary.
## An activate signal handler of the button action