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> 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 <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 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 6 9 153 tfe5/tfe.gresource.xml
145 387 3667 tfe5/tfenotebook.c 145 387 3667 tfe5/tfenotebook.c
15 21 241 tfe5/tfenotebook.h 15 21 241 tfe5/tfenotebook.h
239 863 9264 tfetextview/tfetextview.c 239 863 9264 tfetextview/tfetextview.c
35 60 701 tfetextview/tfetextview.h 35 60 701 tfetextview/tfetextview.h
61 100 2073 tfe5/tfe.ui 61 100 2073 tfe5/tfe.ui
612 1765 19667 total</code></pre> 621 1793 20024 total</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> <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> </body>

View file

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

View file

@ -5,7 +5,7 @@
<meta name="generator" content="pandoc" /> <meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <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"> <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> <style>
code{white-space: pre-wrap;} code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;} span.smallcaps{font-variant: small-caps;}
@ -112,352 +112,390 @@
</div> </div>
</nav> </nav>
<h1 id="periodic-events">Periodic Events</h1> <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> <p>This chapter was written by Paul Schulz <a
<h2 id="how-do-we-create-an-animation">How do we create an animation?</h2> href="mailto:paul@mawsonlakes.org"
<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> class="email">paul@mawsonlakes.org</a>.</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> <h2 id="how-do-we-create-an-animation">How do we create an
<p>The program also makes use of some standard mathematical and time handling functions.</p> animation?</h2>
<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>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> <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> <h2 id="drawing-the-clock-face-hour-minute-and-second-hands">Drawing the
<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> clock face, hour, minute and second hands</h2>
<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> <p>The <code>draw_clock()</code> function does all the work. See the
<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> in-file comments for an explanation of how the Cairo drawing works.</p>
<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> <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-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-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-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-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(cr, <span class="fl">0.5</span>, <span class="fl">0.5</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-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-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-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(cr);</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-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-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-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(cr);</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-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-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-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-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-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(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-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(cr);</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-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-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-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(cr);</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-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-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(cr);</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-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-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-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-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> <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-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-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-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-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-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(cr, CAIRO_LINE_CAP_ROUND);</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-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-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-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> <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="fl">0.8</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(cr, <span class="fl">0.03</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> <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-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-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-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> <span id="cb1-53"><a href="#cb1-53"></a> cr<span class="op">,</span></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-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> (m_radius - inset) * sin (i * M_PI / <span class="fl">6.0</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> <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> <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 * cos (i * M_PI / <span class="fl">6.0</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 * sin (i * M_PI / <span class="fl">6.0</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(cr);</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(cr); <span class="co">/* stack-pen-size */</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> <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-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-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-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-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-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-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(&amp;rawtime);</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 * timeinfo = localtime (&amp;rawtime);</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-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-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-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 = timeinfo-&gt;tm_min * M_PI / <span class="fl">30.0</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 = timeinfo-&gt;tm_sec * M_PI / <span class="fl">30.0</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-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-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-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(cr, CAIRO_LINE_CAP_ROUND);</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-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-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-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-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(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-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(cr, <span class="fl">0.0</span>, <span class="fl">0.0</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(cr,</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(seconds) * (m_radius * <span class="fl">0.9</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> -cos(seconds) * (m_radius * <span class="fl">0.9</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(cr);</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(cr);</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-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-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-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(cr, <span class="dv">0</span>, <span class="dv">0</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(cr,</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(minutes + seconds / <span class="dv">60</span>) * (m_radius * <span class="fl">0.8</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> -cos(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> <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(cr);</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-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-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-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(cr, <span class="fl">0.0</span>, <span class="fl">0.0</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(cr,</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(hours + minutes / <span class="fl">12.0</span>) * (m_radius * <span class="fl">0.5</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> -cos(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> <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(cr);</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(cr);</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-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-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-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(cr);</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></code></pre></div> <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>In order for the clock to be drawn, the drawing function
<p>Whenever the application needs to redraw the GtkDrawingArea, it will now call <code>draw_clock()</code>.</p> <code>draw_clock()</code> needs to be registered with GTK4. This is done
<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> in the <code>app_activate()</code> function (on line 24).</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> <p>Whenever the application needs to redraw the GtkDrawingArea, it will
<span id="cb2-2"><a href="#cb2-2"></a>app_activate (GApplication *app, gpointer user_data) {</span> now call <code>draw_clock()</code>.</p>
<span id="cb2-3"><a href="#cb2-3"></a> GtkWidget *win;</span> <p>There is still a problem though. In order to animate the clock we
<span id="cb2-4"><a href="#cb2-4"></a> GtkWidget *clock;</span> need to also tell the application that the clock needs to be redrawn
<span id="cb2-5"><a href="#cb2-5"></a> GtkBuilder *build;</span> 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-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-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 = GTK_WIDGET (gtk_builder_get_object (build, <span class="st">&quot;win&quot;</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 (GTK_WINDOW (win), GTK_APPLICATION (app));</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-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-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(build);</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-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-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="dv">1000</span>, (GSourceFunc) time_handler, (gpointer) clock);</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(win);</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-17"><a href="#cb2-17"></a></span>
<span id="cb2-18"><a href="#cb2-18"></a>}</span></code></pre></div> <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> <p>Our <code>time_handler()</code> function is very simple, as it just
<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> calls <code>gtk_widget_queue_draw()</code> which schedules a redraw of
<span id="cb3-2"><a href="#cb3-2"></a>time_handler(GtkWidget* widget) {</span> the widget.</p>
<span id="cb3-3"><a href="#cb3-3"></a> gtk_widget_queue_draw(widget);</span> <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-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-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></code></pre></div> <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>.. and that is all there is to it. If you compile and run the example
<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> 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> <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> <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-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-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-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-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="fl">0.05</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-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-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-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-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-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-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(cr, <span class="fl">0.5</span>, <span class="fl">0.5</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-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-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-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(cr);</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-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-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-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(cr);</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-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-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-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-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-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(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-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(cr);</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-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-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-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(cr);</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-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-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(cr);</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-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-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-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-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> <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-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-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-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-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-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(cr, CAIRO_LINE_CAP_ROUND);</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-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-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-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> <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="fl">0.8</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(cr, <span class="fl">0.03</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> <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-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-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-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> <span id="cb4-60"><a href="#cb4-60"></a> cr<span class="op">,</span></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-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> (m_radius - inset) * sin (i * M_PI / <span class="fl">6.0</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> <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> <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 * cos (i * M_PI / <span class="fl">6.0</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 * sin (i * M_PI / <span class="fl">6.0</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(cr);</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(cr); <span class="co">/* stack-pen-size */</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> <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-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-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-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-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-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-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(&amp;rawtime);</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 * timeinfo = localtime (&amp;rawtime);</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-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-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-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 = timeinfo-&gt;tm_min * M_PI / <span class="fl">30.0</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 = timeinfo-&gt;tm_sec * M_PI / <span class="fl">30.0</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-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-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-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(cr, CAIRO_LINE_CAP_ROUND);</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-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-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-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-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(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-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(cr, <span class="fl">0.0</span>, <span class="fl">0.0</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(cr,</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(seconds) * (m_radius * <span class="fl">0.9</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> -cos(seconds) * (m_radius * <span class="fl">0.9</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(cr);</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(cr);</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-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-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-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(cr, <span class="dv">0</span>, <span class="dv">0</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(cr,</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(minutes + seconds / <span class="dv">60</span>) * (m_radius * <span class="fl">0.8</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> -cos(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> <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(cr);</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-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-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-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(cr, <span class="fl">0.0</span>, <span class="fl">0.0</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(cr,</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(hours + minutes / <span class="fl">12.0</span>) * (m_radius * <span class="fl">0.5</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> -cos(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> <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(cr);</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(cr);</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-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-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-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(cr);</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> <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-121"><a href="#cb4-121"></a></span>
<span id="cb4-122"><a href="#cb4-122"></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-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-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(widget);</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-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-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> <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-129"><a href="#cb4-129"></a></span>
<span id="cb4-130"><a href="#cb4-130"></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-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-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 *win;</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 *clock;</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 *build;</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-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-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 = GTK_WIDGET (gtk_builder_get_object (build, <span class="st">&quot;win&quot;</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 (GTK_WINDOW (win), GTK_APPLICATION (app));</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-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-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(build);</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-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-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="dv">1000</span>, (GSourceFunc) time_handler, (gpointer) clock);</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(win);</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-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-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-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-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(app,user_data);</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> <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-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-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-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 *app;</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> <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-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-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 (app, <span class="st">&quot;activate&quot;</span>, G_CALLBACK (app_activate), NULL);</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 (app, <span class="st">&quot;open&quot;</span>, G_CALLBACK (app_open), NULL);</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 = g_application_run (G_APPLICATION (app), argc, argv);</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 (app);</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> <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></code></pre></div> <span id="cb4-166"><a href="#cb4-166"></a><span class="op">}</span></span></code></pre></div>
<p><code>tfc.ui</code></p> <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> <div class="sourceCode" id="cb5"><pre
<span id="cb5-2"><a href="#cb5-2"></a><span class="kw">&lt;interface&gt;</span></span> 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-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-2"><a href="#cb5-2"></a>&lt;<span class="kw">interface</span>&gt;</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-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-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-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-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-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-7"><a href="#cb5-7"></a> <span class="kw">&lt;child&gt;</span></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-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-7"><a href="#cb5-7"></a> &lt;<span class="kw">child</span>&gt;</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-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-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-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-11"><a href="#cb5-11"></a> <span class="kw">&lt;/object&gt;</span></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-12"><a href="#cb5-12"></a> <span class="kw">&lt;/child&gt;</span></span> <span id="cb5-11"><a href="#cb5-11"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb5-13"><a href="#cb5-13"></a> <span class="kw">&lt;/object&gt;</span></span> <span id="cb5-12"><a href="#cb5-12"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb5-14"><a href="#cb5-14"></a><span class="kw">&lt;/interface&gt;</span></span></code></pre></div> <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> <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> <div class="sourceCode" id="cb6"><pre
<span id="cb6-2"><a href="#cb6-2"></a><span class="kw">&lt;gresources&gt;</span></span> 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-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-2"><a href="#cb6-2"></a>&lt;<span class="kw">gresources</span>&gt;</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-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-5"><a href="#cb6-5"></a> <span class="kw">&lt;/gresource&gt;</span></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-6"><a href="#cb6-6"></a><span class="kw">&lt;/gresources&gt;</span></span></code></pre></div> <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> <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> <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> </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> <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 item, second item, …, nth item, …). There are two cases. One is the
index starts from one (one-based) and the other is from zero index starts from one (one-based) and the other is from zero
(zero-based).</p> (zero-based).</p>
<p>Gio provides GListModel interface. It is a zero-based list of the <p>Gio provides GListModel interface. It is a zero-based list and its
same type of GObject descendants, or objects that implement the same items are the same type of GObject descendants, or objects that
interface. An object implements GListModel is not a widget. So, the list implement the same interface. An object implements GListModel is not a
is not displayed on the screen directly. Theres another object widget. So, the list is not displayed on the screen directly. Theres
GtkListView which is a widget to display the list. The items in the list another object GtkListView which is a widget to display the list. The
need to be connected to the items in GtkListView. GtkListItemFactory items in the list need to be connected to the items in GtkListView.
object maps items in the list to GListView.</p> GtkListItemFactory instance maps items in the list to GListView.</p>
<figure> <figure>
<img src="image/list.png" alt="List" /> <img src="image/list.png" alt="List" />
<figcaption aria-hidden="true">List</figcaption> <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 to this model, user can select items by clicking on them. It is
implemented by GtkMultiSelection, GtkNoSelection and GtkSingleSelection implemented by GtkMultiSelection, GtkNoSelection and GtkSingleSelection
objects. These three objects are usually enough to build an application. objects. These three objects are usually enough to build an application.
They are created with GListModel. You can also create them alone and add They are created with another GListModel. You can also create them alone
GListModel later.</p> and add a GListModel later.</p>
<ul> <ul>
<li>GtkMultiSelection supports multiple selection.</li> <li>GtkMultiSelection supports multiple selection.</li>
<li>GtkNoSelection supports no selection. This is a wrapper to <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> items, for example, more than a million items.</p>
<h2 id="gtklistitemfactory">GtkListItemFactory</h2> <h2 id="gtklistitemfactory">GtkListItemFactory</h2>
<p>GtkListItemFactory creates or recycles GtkListItem and connects it <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> factory, GtkSignalListItemFactory and GtkBuilderListItemFactory.</p>
<h3 id="gtksignallistitemfactory">GtkSignalListItemFactory</h3> <h3 id="gtksignallistitemfactory">GtkSignalListItemFactory</h3>
<p>GtkSignalListItemFactory provides signals for users to configure a <p>GtkSignalListItemFactory provides signals for users to configure a
@ -207,7 +207,7 @@ GtkListItem object. There are four signals.</p>
<ol type="1"> <ol type="1">
<li>“setup” is emitted to set up GtkListItem object. A user sets its <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 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 even the GtkListItem instance is recycled (to bind to another item of
GListModel).</li> GListModel).</li>
<li>“bind” is emitted to bind an item in the list model to the widget. <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-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-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-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-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> <span id="cb2-8"><a href="#cb2-8"></a><span class="op">}</span></span>
<span id="cb2-9"><a href="#cb2-9"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb2-9"><a href="#cb2-9"></a></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-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> 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-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> <span class="co">/* Strobj is owned by the instance. Caller mustn&#39;t change or destroy it. */</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> 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-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> <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-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> <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> text<span class="op">);</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-17"><a href="#cb2-17"></a><span class="op">}</span></span>
<span id="cb2-18"><a href="#cb2-18"></a></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> <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-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-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-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-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">/* The previous child is destroyed automatically. */</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-28"><a href="#cb2-28"></a><span class="op">}</span></span>
<span id="cb2-29"><a href="#cb2-29"></a></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> <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-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-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-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-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;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-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></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> 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-53"><a href="#cb2-53"></a></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-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_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<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><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> <span id="cb2-57"><a href="#cb2-57"></a><span class="op">}</span></span>
<span id="cb2-58"><a href="#cb2-58"></a><span class="co">/* ----- main ----- */</span></span> <span id="cb2-58"><a href="#cb2-58"></a></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-59"><a href="#cb2-59"></a><span class="co">/* ----- main ----- */</span></span>
<span id="cb2-60"><a href="#cb2-60"></a></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 class="dt">int</span></span> <span id="cb2-61"><a href="#cb2-61"></a></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-62"><a href="#cb2-62"></a><span class="dt">int</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-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> <span class="dt">int</span> stat<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> <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> 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-66"><a href="#cb2-66"></a></span>
<span id="cb2-67"><a href="#cb2-67"></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> 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-68"><a href="#cb2-68"></a></span>
<span id="cb2-69"><a href="#cb2-69"></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> 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-70"><a href="#cb2-70"></a></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-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> <span class="cf">return</span> stat<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="op">}</span></span></code></pre></div> <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 <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, src/misc. Make a shell script below and save it to your bin directory,
for example <code>$HOME/bin</code>.</p> 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 GtkLabel object. The factory sees this template and creates GtkLabel and
sets the child property of GtkListItem. This is the same as what setup sets the child property of GtkListItem. This is the same as what setup
handler of GtkSignalListItemFactory did.</p> handler of GtkSignalListItemFactory did.</p>
<p>Then, bind the label property of GtkLabel to string property of <p>Then, bind the label property of the GtkLabel to the string property
GtkStringObject. The string object is referred to by item property of of a GtkStringObject. The string object refers to the item property of
GtkListItem. So, the lookup tag is like this:</p> the GtkListItem. So, the lookup tag is like this:</p>
<pre><code>string &lt;- GtkStringObject &lt;- item &lt;- GtkListItem</code></pre> <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, <p>The last lookup tag has a content <code>GtkListItem</code>. Usually,
C type like <code>GtkListItem</code> doesnt appear in the content of 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 href="https://blog.gtk.org/2020/09/05/a-primer-on-gtklistview/">GTK
Development Blog</a> by Matthias Clasen.</p> Development Blog</a> by Matthias Clasen.</p>
<blockquote> <blockquote>
@ -361,60 +362,65 @@ located under src/misc directory.</p>
<div class="sourceCode" id="cb7"><pre <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> 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-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-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><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>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> 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> 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-7"><a href="#cb7-7"></a><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-8"><a href="#cb7-8"></a></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-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> 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-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></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> <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-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> <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-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> <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> 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-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> 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-16"><a href="#cb7-16"></a></span>
<span id="cb7-17"><a href="#cb7-17"></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="dt">const</span> <span class="dt">char</span> <span class="op">*</span>ui_string <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="st">&quot;&lt;interface&gt;&quot;</span></span> <span id="cb7-19"><a href="#cb7-19"></a> <span class="op">};</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-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> <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-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 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-22"><a href="#cb7-22"></a></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-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;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-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;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-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;/lookup&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;/binding&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;/object&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;/property&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;/template&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;/interface&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="op">;</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> 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-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> 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-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> <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> 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-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> 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-37"><a href="#cb7-37"></a><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-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><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-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-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><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.list2&quot;</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> <span id="cb7-43"><a href="#cb7-43"></a><span class="op">}</span></span>
<span id="cb7-44"><a href="#cb7-44"></a><span class="dt">int</span></span> <span id="cb7-44"><a href="#cb7-44"></a></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-45"><a href="#cb7-45"></a><span class="co">/* ----- main ----- */</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-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 class="dt">int</span> stat<span class="op">;</span></span> <span id="cb7-47"><a href="#cb7-47"></a></span>
<span id="cb7-48"><a href="#cb7-48"></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> 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-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></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> 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-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-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-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> g_object_unref <span class="op">(</span>app<span class="op">);</span></span> <span id="cb7-54"><a href="#cb7-54"></a></span>
<span id="cb7-55"><a href="#cb7-55"></a> <span class="cf">return</span> stat<span class="op">;</span></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><span class="op">}</span></span></code></pre></div> <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. <p>No signal handler is needed for GtkBulderListItemFactory.
GtkSingleSelection is used, so user can select one item at a time.</p> 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 <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> 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> <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-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-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="cf">return</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="cf">else</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="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-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 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> <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="op">...</span> <span class="op">...</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="op">...</span> <span class="op">...</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> <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;interface&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;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-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;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-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;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-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 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-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;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-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;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-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;/closure&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;/binding&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>
<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>
<ul> <ul>
<li>The string “gchararray” is the type name of strings. The type <li>The string “gchararray” is a type name. The type “gchar” is a type
“gchar” is the same as “char”. Therefore, “gchararray” is “an array of name and it is the same as C type “char”. Therefore, “gchararray” is “an
char type”, which is the same as string type. It is used to get the type array of char type”, which is the same as string type. It is used to get
of GValue object. GValue is a generic value and it can contain various the type of GValue object. GValue is a generic value and it can contain
type of values. For example, the type name can be gboolean, gchar various type of values. For example, the type name can be gboolean,
(char), gint (int), gfloat (float), gdouble (double), gchararray (char gchar (char), gint (int), gfloat (float), gdouble (double), gchararray
*) and so on. These type names are the names of the fundamental types (char *) and so on. These type names are the names of the fundamental
that are registered to the type system. See <a types that are registered to the type system. See <a
href="https://github.com/ToshioCP/Gobject-tutorial/blob/main/gfm/sec5.md#gvalue">GObject href="https://github.com/ToshioCP/Gobject-tutorial/blob/main/gfm/sec5.md#gvalue">GObject
tutorial</a>.</li> tutorial</a>.</li>
<li>Closure tag has type attribute and function attribute. Function <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 <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 the value of the item property of the GtkListItem. This will be the
second argument of the function. The first parameter is always the second argument of the function. The first parameter is always the
GListItem instance.</li> GListItem instance, which is a this object. The this object is
<li><code>gtk_file_name</code> function first checks the explained in section 28.</li>
<code>info</code> parameter. Because it can be NULL when GListItem <li><code>gtk_file_name</code> function is the callback function for the
<code>item</code> is unbounded. If its GFileInfo, it returns the closure tag. It first checks the <code>info</code> parameter. Because it
filename. The filename is owned by GFileInfo object. So, the function can be NULL when GListItem <code>item</code> is unbounded. If its
<code>get_file_name</code> duplicates the string to own the newly GFileInfo, it returns the copied filename. Because the return value
created one. Closure tag binds the property of the outer tag (GtkLabel) (filename) of <code>g_file_info_get_name</code> is owned by GFileInfo
to the filename.</li> 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> </ul>
<p>The whole program (<code>list3.c</code>) is as follows. The program <p>The whole program (<code>list3.c</code>) is as follows. The program
is located in src/misc directory.</p> 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-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-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-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-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="cf">return</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 class="cf">else</span></span> <span id="cb11-7"><a href="#cb11-7"></a></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-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><span class="op">}</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></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><span class="co">/* ----- activate, open, startup handlers ----- */</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="dt">static</span> <span class="dt">void</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>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-13"><a href="#cb11-13"></a></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-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> 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-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> 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-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>scr <span class="op">=</span> gtk_scrolled_window_new <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_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-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></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> 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-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> 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-21"><a href="#cb11-21"></a></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-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> 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-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></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> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>ui_string <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 class="st">&quot;&lt;interface&gt;&quot;</span></span> <span id="cb11-26"><a href="#cb11-26"></a></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-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;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-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;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-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;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-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;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-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;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-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&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;/binding&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;/object&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;/property&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;/template&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;/interface&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="op">;</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> 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-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> 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-41"><a href="#cb11-41"></a><span class="op">;</span></span>
<span id="cb11-42"><a href="#cb11-42"></a></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> 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-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> 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-44"><a href="#cb11-44"></a></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-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><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> <span id="cb11-47"><a href="#cb11-47"></a><span class="op">}</span></span>
<span id="cb11-48"><a href="#cb11-48"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb11-48"><a href="#cb11-48"></a></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-49"><a href="#cb11-49"></a><span class="co">/* ----- main ----- */</span></span>
<span id="cb11-50"><a href="#cb11-50"></a><span class="op">}</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-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-52"><a href="#cb11-52"></a><span class="dt">int</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-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></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></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>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-56"><a href="#cb11-56"></a></span>
<span id="cb11-57"><a href="#cb11-57"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></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 class="dt">int</span> stat<span class="op">;</span></span> <span id="cb11-58"><a href="#cb11-58"></a></span>
<span id="cb11-59"><a href="#cb11-59"></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> 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-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-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-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_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-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> <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> 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-65"><a href="#cb11-65"></a><span class="op">}</span></span></code></pre></div>
<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>
<p>The ui data (xml data above) is used to build the GListItem template <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 at runtime. GtkBuilder refers to the symbol table to find the function
<code>get_file_name</code>.</p> <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-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-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-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-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> <span class="cf">return</span> NULL<span class="op">;</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">else</span> <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> icon <span class="op">=</span> g_file_info_get_icon <span class="op">(</span>info<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> g_object_ref <span class="op">(</span>icon<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="cf">return</span> icon<span class="op">;</span></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> <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="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> <span id="cb8-13"><a href="#cb8-13"></a><span class="op">}</span></span></code></pre></div>
<span id="cb8-14"><a href="#cb8-14"></a><span class="dt">char</span> <span class="op">*</span></span> <p>One important thing is the ownership of the return values. The return
<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> value is owned by the caller. So, <code>g_obect_ref</code> or
<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> <code>g_strdup</code> is necessary.</p>
<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>
<h2 id="an-activate-signal-handler-of-the-button-action">An activate <h2 id="an-activate-signal-handler-of-the-button-action">An activate
signal handler of the button action</h2> signal handler of the button action</h2>
<p>An activate signal handler <code>view_activate</code> switches the <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). One is the index starts from one (one-based) and the other is from zero (zero-based).
Gio provides GListModel interface. 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. An object implements GListModel is not a widget.
So, the list is not displayed on the screen directly. So, the list is not displayed on the screen directly.
There's another object GtkListView which is a widget to display the list. 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. 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) ![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. Thanks to this model, user can select items by clicking on them.
It is implemented by GtkMultiSelection, GtkNoSelection and GtkSingleSelection objects. It is implemented by GtkMultiSelection, GtkNoSelection and GtkSingleSelection objects.
These three objects are usually enough to build an application. These three objects are usually enough to build an application.
They are created with GListModel. They are created with another GListModel.
You can also create them alone and add GListModel later. You can also create them alone and add a GListModel later.
- GtkMultiSelection supports multiple selection. - GtkMultiSelection supports multiple selection.
- GtkNoSelection supports no selection. This is a wrapper to GListModel when GtkSelectionModel is needed. - 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
GtkListItemFactory creates or recycles GtkListItem and connects it with an item of the list model. 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 ### GtkSignalListItemFactory
@ -96,7 +96,7 @@ There are four signals.
1. "setup" is emitted to set up GtkListItem object. 1. "setup" is emitted to set up GtkListItem object.
A user sets its child widget in the handler. 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). 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. 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. 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) { 4 setup_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
5 GtkWidget *lb = gtk_label_new (NULL); 5 GtkWidget *lb = gtk_label_new (NULL);
6 gtk_list_item_set_child (listitem, lb); 6 gtk_list_item_set_child (listitem, lb);
7 } 7 /* Because gtk_list_item_set_child sunk the floating reference of lb, releasing (unref) isn't necessary for lb. */
8 8 }
9 static void 9
10 bind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) { 10 static void
11 GtkWidget *lb = gtk_list_item_get_child (listitem); 11 bind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
12 /* Strobj is owned by the instance. Caller mustn't change or destroy it. */ 12 GtkWidget *lb = gtk_list_item_get_child (listitem);
13 GtkStringObject *strobj = gtk_list_item_get_item (listitem); 13 /* Strobj is owned by the instance. Caller mustn't change or destroy it. */
14 const char *text = gtk_string_object_get_string (strobj); 14 GtkStringObject *strobj = gtk_list_item_get_item (listitem);
15 15 /* The string returned by gtk_string_object_get_string is owned by the instance. */
16 gtk_label_set_text (GTK_LABEL (lb), text); 16 gtk_label_set_text (GTK_LABEL (lb), gtk_string_object_get_string (strobj));
17 } 17 }
18 18
19 static void 19 static void
@ -138,8 +138,8 @@ GtkNoSelection is used, so user can't select any item.
23 23
24 static void 24 static void
25 teardown_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) { 25 teardown_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
26 gtk_list_item_set_child (listitem, NULL); 26 /* There's nothing to do here. */
27 /* The previous child is destroyed automatically. */ 27 /* GtkListItem instance will be destroyed soon. You don't need to set the child to NULL. */
28 } 28 }
29 29
30 static void 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 (); 47 GtkListItemFactory *factory = gtk_signal_list_item_factory_new ();
48 g_signal_connect (factory, "setup", G_CALLBACK (setup_cb), NULL); 48 g_signal_connect (factory, "setup", G_CALLBACK (setup_cb), NULL);
49 g_signal_connect (factory, "bind", G_CALLBACK (bind_cb), NULL); 49 g_signal_connect (factory, "bind", G_CALLBACK (bind_cb), NULL);
50 g_signal_connect (factory, "unbind", G_CALLBACK (unbind_cb), NULL); 50 /* The following two lines can be left out. The handlers do nothing. */
51 g_signal_connect (factory, "teardown", G_CALLBACK (teardown_cb), NULL); 51 g_signal_connect (factory, "unbind", G_CALLBACK (unbind_cb), NULL);
52 52 g_signal_connect (factory, "teardown", G_CALLBACK (teardown_cb), NULL);
53 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory); 53
54 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv); 54 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
55 gtk_window_present (GTK_WINDOW (win)); 55 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
56 } 56 gtk_window_present (GTK_WINDOW (win));
57 57 }
58 /* ----- main ----- */ 58
59 #define APPLICATION_ID "com.github.ToshioCP.list1" 59 /* ----- main ----- */
60 60 #define APPLICATION_ID "com.github.ToshioCP.list1"
61 int 61
62 main (int argc, char **argv) { 62 int
63 GtkApplication *app; 63 main (int argc, char **argv) {
64 int stat; 64 GtkApplication *app;
65 65 int stat;
66 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS); 66
67 67 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
68 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL); 68
69 69 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
70 stat =g_application_run (G_APPLICATION (app), argc, argv); 70
71 g_object_unref (app); 71 stat =g_application_run (G_APPLICATION (app), argc, argv);
72 return stat; 72 g_object_unref (app);
73 } 73 return stat;
74 }
~~~ ~~~
The file `list1.c` is located under the directory [src/misc](../src/misc). 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. 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. This is the same as what setup handler of GtkSignalListItemFactory did.
Then, bind the label property of GtkLabel to string property of GtkStringObject. Then, bind the label property of the GtkLabel to the string property of a GtkStringObject.
The string object is referred to by item property of GtkListItem. The string object refers to the item property of the GtkListItem.
So, the lookup tag is like this: So, the lookup tag is like this:
~~~ ~~~
string <- GtkStringObject <- item <- GtkListItem label <- string <- GtkStringObject <- item <- GtkListItem
~~~ ~~~
The last lookup tag has a content `GtkListItem`. The last lookup tag has a content `GtkListItem`.
Usually, C type like `GtkListItem` doesn't appear in the content of tags. Usually, C type like `GtkListItem` doesn't appear in the content of tags.
This is a special case. 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. > 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 ~~~C
1 #include <gtk/gtk.h> 1 #include <gtk/gtk.h>
2 2
3 /* ----- activate, open, startup handlers ----- */ 3 static void
4 static void 4 app_activate (GApplication *application) {
5 app_activate (GApplication *application) { 5 GtkApplication *app = GTK_APPLICATION (application);
6 GtkApplication *app = GTK_APPLICATION (application); 6 gtk_window_present (gtk_application_get_active_window(app));
7 GtkWidget *win = gtk_application_window_new (app); 7 }
8 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400); 8
9 GtkWidget *scr = gtk_scrolled_window_new (); 9 static void
10 gtk_window_set_child (GTK_WINDOW (win), scr); 10 app_startup (GApplication *application) {
11 11 GtkApplication *app = GTK_APPLICATION (application);
12 char *array[] = { 12 GtkWidget *win = gtk_application_window_new (app);
13 "one", "two", "three", "four", NULL 13 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
14 }; 14 GtkWidget *scr = gtk_scrolled_window_new ();
15 GtkStringList *sl = gtk_string_list_new ((const char * const *) array); 15 gtk_window_set_child (GTK_WINDOW (win), scr);
16 GtkSingleSelection *ss = gtk_single_selection_new (G_LIST_MODEL (sl)); 16
17 17 char *array[] = {
18 const char *ui_string = 18 "one", "two", "three", "four", NULL
19 "<interface>" 19 };
20 "<template class=\"GtkListItem\">" 20 GtkStringList *sl = gtk_string_list_new ((const char * const *) array);
21 "<property name=\"child\">" 21 GtkSingleSelection *ss = gtk_single_selection_new (G_LIST_MODEL (sl));
22 "<object class=\"GtkLabel\">" 22
23 "<binding name=\"label\">" 23 const char *ui_string =
24 "<lookup name=\"string\" type=\"GtkStringObject\">" 24 "<interface>"
25 "<lookup name=\"item\">GtkListItem</lookup>" 25 "<template class=\"GtkListItem\">"
26 "</lookup>" 26 "<property name=\"child\">"
27 "</binding>" 27 "<object class=\"GtkLabel\">"
28 "</object>" 28 "<binding name=\"label\">"
29 "</property>" 29 "<lookup name=\"string\" type=\"GtkStringObject\">"
30 "</template>" 30 "<lookup name=\"item\">GtkListItem</lookup>"
31 "</interface>" 31 "</lookup>"
32 ; 32 "</binding>"
33 GBytes *gbytes = g_bytes_new_static (ui_string, strlen (ui_string)); 33 "</object>"
34 GtkListItemFactory *factory = gtk_builder_list_item_factory_new_from_bytes (NULL, gbytes); 34 "</property>"
35 35 "</template>"
36 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ss), factory); 36 "</interface>"
37 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv); 37 ;
38 gtk_window_present (GTK_WINDOW (win)); 38 GBytes *gbytes = g_bytes_new_static (ui_string, strlen (ui_string));
39 } 39 GtkListItemFactory *factory = gtk_builder_list_item_factory_new_from_bytes (NULL, gbytes);
40 40
41 /* ----- main ----- */ 41 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ss), factory);
42 #define APPLICATION_ID "com.github.ToshioCP.list2" 42 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
43 43 }
44 int 44
45 main (int argc, char **argv) { 45 /* ----- main ----- */
46 GtkApplication *app; 46 #define APPLICATION_ID "com.github.ToshioCP.list2"
47 int stat; 47
48 48 int
49 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS); 49 main (int argc, char **argv) {
50 50 GtkApplication *app;
51 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL); 51 int stat;
52 52
53 stat =g_application_run (G_APPLICATION (app), argc, argv); 53 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
54 g_object_unref (app); 54
55 return stat; 55 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
56 } 56 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
57 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. 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 ~~~C
const char * const char *
get_file_name (GtkListItem *item, GFileInfo *info) { get_file_name (GtkListItem *item, GFileInfo *info) {
if (! G_IS_FILE_INFO (info)) return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
return NULL;
else
return g_strdup (g_file_info_get_name (info));
} }
... ... ... ...
... ... ... ...
@ -390,8 +392,8 @@ get_file_name (GtkListItem *item, GFileInfo *info) {
"</interface>" "</interface>"
~~~ ~~~
- The string "gchararray" is the type name of strings. - The string "gchararray" is a type name.
The type "gchar" is the same as "char". 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. 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. It is used to get the type of GValue object.
GValue is a generic value and it can contain various type of values. 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. 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. `<lookup name="item">GtkListItem</lookup>` gives the value of the item property of the GtkListItem.
This will be the second argument of the function. This will be the second argument of the function.
The first parameter is always the GListItem instance. The first parameter is always the GListItem instance, which is a 'this' object.
- `gtk_file_name` function first checks the `info` parameter. 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. Because it can be NULL when GListItem `item` is unbounded.
If it's GFileInfo, it returns the filename. If it's GFileInfo, it returns the copied filename.
The filename is owned by GFileInfo object. Because the return value (filename) of `g_file_info_get_name` is owned by GFileInfo object.
So, the function `get_file_name` duplicates the string to own the newly created one. So, the the string needs to be duplicated to give the ownership to the caller.
Closure tag binds the property of the outer tag (GtkLabel) to the filename. Binding tag binds the "label" property of the GtkLabel to the closure tag.
The whole program (`list3.c`) is as follows. The whole program (`list3.c`) is as follows.
The program is located in [src/misc](../src/misc) directory. 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 2
3 char * 3 char *
4 get_file_name (GtkListItem *item, GFileInfo *info) { 4 get_file_name (GtkListItem *item, GFileInfo *info) {
5 if (! G_IS_FILE_INFO (info)) 5 return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
6 return NULL; 6 }
7 else 7
8 return g_strdup (g_file_info_get_name (info)); 8 static void
9 } 9 app_activate (GApplication *application) {
10 10 GtkApplication *app = GTK_APPLICATION (application);
11 /* ----- activate, open, startup handlers ----- */ 11 gtk_window_present (gtk_application_get_active_window(app));
12 static void 12 }
13 app_activate (GApplication *application) { 13
14 GtkApplication *app = GTK_APPLICATION (application); 14 static void
15 GtkWidget *win = gtk_application_window_new (app); 15 app_startup (GApplication *application) {
16 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400); 16 GtkApplication *app = GTK_APPLICATION (application);
17 GtkWidget *scr = gtk_scrolled_window_new (); 17 GtkWidget *win = gtk_application_window_new (app);
18 gtk_window_set_child (GTK_WINDOW (win), scr); 18 gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
19 19 GtkWidget *scr = gtk_scrolled_window_new ();
20 GFile *file = g_file_new_for_path ("."); 20 gtk_window_set_child (GTK_WINDOW (win), scr);
21 GtkDirectoryList *dl = gtk_directory_list_new ("standard::name", file); 21
22 g_object_unref (file); 22 GFile *file = g_file_new_for_path (".");
23 GtkNoSelection *ns = gtk_no_selection_new (G_LIST_MODEL (dl)); 23 GtkDirectoryList *dl = gtk_directory_list_new ("standard::name", file);
24 24 g_object_unref (file);
25 const char *ui_string = 25 GtkNoSelection *ns = gtk_no_selection_new (G_LIST_MODEL (dl));
26 "<interface>" 26
27 "<template class=\"GtkListItem\">" 27 const char *ui_string =
28 "<property name=\"child\">" 28 "<interface>"
29 "<object class=\"GtkLabel\">" 29 "<template class=\"GtkListItem\">"
30 "<binding name=\"label\">" 30 "<property name=\"child\">"
31 "<closure type=\"gchararray\" function=\"get_file_name\">" 31 "<object class=\"GtkLabel\">"
32 "<lookup name=\"item\">GtkListItem</lookup>" 32 "<binding name=\"label\">"
33 "</closure>" 33 "<closure type=\"gchararray\" function=\"get_file_name\">"
34 "</binding>" 34 "<lookup name=\"item\">GtkListItem</lookup>"
35 "</object>" 35 "</closure>"
36 "</property>" 36 "</binding>"
37 "</template>" 37 "</object>"
38 "</interface>" 38 "</property>"
39 ; 39 "</template>"
40 GBytes *gbytes = g_bytes_new_static (ui_string, strlen (ui_string)); 40 "</interface>"
41 GtkListItemFactory *factory = gtk_builder_list_item_factory_new_from_bytes (NULL, gbytes); 41 ;
42 42 GBytes *gbytes = g_bytes_new_static (ui_string, strlen (ui_string));
43 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory); 43 GtkListItemFactory *factory = gtk_builder_list_item_factory_new_from_bytes (NULL, gbytes);
44 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv); 44
45 gtk_window_present (GTK_WINDOW (win)); 45 GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
46 } 46 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
47 47 }
48 static void 48
49 app_startup (GApplication *application) { 49 /* ----- main ----- */
50 } 50 #define APPLICATION_ID "com.github.ToshioCP.list3"
51 51
52 /* ----- main ----- */ 52 int
53 #define APPLICATION_ID "com.github.ToshioCP.list3" 53 main (int argc, char **argv) {
54 54 GtkApplication *app;
55 int 55 int stat;
56 main (int argc, char **argv) { 56
57 GtkApplication *app; 57 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
58 int stat; 58
59 59 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
60 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS); 60 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
61 61
62 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL); 62 stat =g_application_run (G_APPLICATION (app), argc, argv);
63 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL); 63 g_object_unref (app);
64 64 return stat;
65 stat =g_application_run (G_APPLICATION (app), argc, argv); 65 }
66 g_object_unref (app);
67 return stat;
68 }
~~~ ~~~
The ui data (xml data above) is used to build the GListItem template at runtime. 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) { 2 get_icon (GtkListItem *item, GFileInfo *info) {
3 GIcon *icon; 3 GIcon *icon;
4 4
5 if (! G_IS_FILE_INFO (info)) 5 /* g_file_info_get_icon can return NULL */
6 return NULL; 6 icon = G_IS_FILE_INFO (info) ? g_file_info_get_icon (info) : NULL;
7 else { 7 return icon ? g_object_ref (icon) : NULL;
8 icon = g_file_info_get_icon (info); 8 }
9 g_object_ref (icon); 9
10 return icon; 10 char *
11 } 11 get_file_name (GtkListItem *item, GFileInfo *info) {
12 } 12 return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
13 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 }
~~~ ~~~
One important thing is the ownership of the return values. 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 return value is owned by the caller.
the value is owned by the caller.
So, `g_obect_ref` or `g_strdup` is necessary. So, `g_obect_ref` or `g_strdup` is necessary.
## An activate signal handler of the button action ## An activate signal handler of the button action

View file

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

View file

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

View file

@ -4,6 +4,7 @@ static void
setup_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) { setup_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
GtkWidget *lb = gtk_label_new (NULL); GtkWidget *lb = gtk_label_new (NULL);
gtk_list_item_set_child (listitem, lb); 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 static void
@ -11,9 +12,8 @@ bind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_da
GtkWidget *lb = gtk_list_item_get_child (listitem); GtkWidget *lb = gtk_list_item_get_child (listitem);
/* Strobj is owned by the instance. Caller mustn't change or destroy it. */ /* Strobj is owned by the instance. Caller mustn't change or destroy it. */
GtkStringObject *strobj = gtk_list_item_get_item (listitem); GtkStringObject *strobj = gtk_list_item_get_item (listitem);
const char *text = gtk_string_object_get_string (strobj); /* 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));
gtk_label_set_text (GTK_LABEL (lb), text);
} }
static void static void
@ -23,8 +23,8 @@ unbind_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_
static void static void
teardown_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) { teardown_cb (GtkSignalListItemFactory *self, GtkListItem *listitem, gpointer user_data) {
gtk_list_item_set_child (listitem, NULL); /* There's nothing to do here. */
/* The previous child is destroyed automatically. */ /* GtkListItem instance will be destroyed soon. You don't need to set the child to NULL. */
} }
static void static void
@ -47,6 +47,7 @@ app_activate (GApplication *application) {
GtkListItemFactory *factory = gtk_signal_list_item_factory_new (); GtkListItemFactory *factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_cb), NULL); g_signal_connect (factory, "setup", G_CALLBACK (setup_cb), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (bind_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, "unbind", G_CALLBACK (unbind_cb), NULL);
g_signal_connect (factory, "teardown", G_CALLBACK (teardown_cb), NULL); g_signal_connect (factory, "teardown", G_CALLBACK (teardown_cb), NULL);

View file

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

View file

@ -2,15 +2,17 @@
char * char *
get_file_name (GtkListItem *item, GFileInfo *info) { get_file_name (GtkListItem *item, GFileInfo *info) {
if (! G_IS_FILE_INFO (info)) return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
return NULL;
else
return g_strdup (g_file_info_get_name (info));
} }
/* ----- activate, open, startup handlers ----- */
static void static void
app_activate (GApplication *application) { 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); GtkApplication *app = GTK_APPLICATION (application);
GtkWidget *win = gtk_application_window_new (app); GtkWidget *win = gtk_application_window_new (app);
gtk_window_set_default_size (GTK_WINDOW (win), 600, 400); 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); GtkWidget *lv = gtk_list_view_new (GTK_SELECTION_MODEL (ns), factory);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv); gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), lv);
gtk_window_present (GTK_WINDOW (win));
}
static void
app_startup (GApplication *application) {
} }
/* ----- main ----- */ /* ----- 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). One is the index starts from one (one-based) and the other is from zero (zero-based).
Gio provides GListModel interface. 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. An object implements GListModel is not a widget.
So, the list is not displayed on the screen directly. So, the list is not displayed on the screen directly.
There's another object GtkListView which is a widget to display the list. 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. 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} ![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. Thanks to this model, user can select items by clicking on them.
It is implemented by GtkMultiSelection, GtkNoSelection and GtkSingleSelection objects. It is implemented by GtkMultiSelection, GtkNoSelection and GtkSingleSelection objects.
These three objects are usually enough to build an application. These three objects are usually enough to build an application.
They are created with GListModel. They are created with another GListModel.
You can also create them alone and add GListModel later. You can also create them alone and add a GListModel later.
- GtkMultiSelection supports multiple selection. - GtkMultiSelection supports multiple selection.
- GtkNoSelection supports no selection. This is a wrapper to GListModel when GtkSelectionModel is needed. - 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
GtkListItemFactory creates or recycles GtkListItem and connects it with an item of the list model. 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 ### GtkSignalListItemFactory
@ -111,7 +111,7 @@ There are four signals.
1. "setup" is emitted to set up GtkListItem object. 1. "setup" is emitted to set up GtkListItem object.
A user sets its child widget in the handler. 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). 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. 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. 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. 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. This is the same as what setup handler of GtkSignalListItemFactory did.
Then, bind the label property of GtkLabel to string property of GtkStringObject. Then, bind the label property of the GtkLabel to the string property of a GtkStringObject.
The string object is referred to by item property of GtkListItem. The string object refers to the item property of the GtkListItem.
So, the lookup tag is like this: So, the lookup tag is like this:
~~~ ~~~
string <- GtkStringObject <- item <- GtkListItem label <- string <- GtkStringObject <- item <- GtkListItem
~~~ ~~~
The last lookup tag has a content `GtkListItem`. The last lookup tag has a content `GtkListItem`.
Usually, C type like `GtkListItem` doesn't appear in the content of tags. Usually, C type like `GtkListItem` doesn't appear in the content of tags.
This is a special case. 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. > 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 ~~~C
const char * const char *
get_file_name (GtkListItem *item, GFileInfo *info) { get_file_name (GtkListItem *item, GFileInfo *info) {
if (! G_IS_FILE_INFO (info)) return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
return NULL;
else
return g_strdup (g_file_info_get_name (info));
} }
... ... ... ...
... ... ... ...
@ -291,8 +287,8 @@ get_file_name (GtkListItem *item, GFileInfo *info) {
"</interface>" "</interface>"
~~~ ~~~
- The string "gchararray" is the type name of strings. - The string "gchararray" is a type name.
The type "gchar" is the same as "char". 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. 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. It is used to get the type of GValue object.
GValue is a generic value and it can contain various type of values. 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. 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. `<lookup name="item">GtkListItem</lookup>` gives the value of the item property of the GtkListItem.
This will be the second argument of the function. This will be the second argument of the function.
The first parameter is always the GListItem instance. The first parameter is always the GListItem instance, which is a 'this' object.
- `gtk_file_name` function first checks the `info` parameter. 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. Because it can be NULL when GListItem `item` is unbounded.
If it's GFileInfo, it returns the filename. If it's GFileInfo, it returns the copied filename.
The filename is owned by GFileInfo object. Because the return value (filename) of `g_file_info_get_name` is owned by GFileInfo object.
So, the function `get_file_name` duplicates the string to own the newly created one. So, the the string needs to be duplicated to give the ownership to the caller.
Closure tag binds the property of the outer tag (GtkLabel) to the filename. Binding tag binds the "label" property of the GtkLabel to the closure tag.
The whole program (`list3.c`) is as follows. The whole program (`list3.c`) is as follows.
The program is located in [src/misc](misc) directory. 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. 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 return value is owned by the caller.
the value is owned by the caller.
So, `g_obect_ref` or `g_strdup` is necessary. So, `g_obect_ref` or `g_strdup` is necessary.
## An activate signal handler of the button action ## An activate signal handler of the button action