Update section 29-33.

This commit is contained in:
Toshio Sekiya 2023-08-01 18:05:16 +09:00
parent bda0f28ad3
commit 3ada90257e
26 changed files with 1323 additions and 1604 deletions

View file

@ -10,7 +10,8 @@ The table of contents is at the end of this abstract.
- Section 3 to 23 describes the basics, with the example of a simple editor `tfe` (Text File Editor). - Section 3 to 23 describes the basics, with the example of a simple editor `tfe` (Text File Editor).
- Section 24 to 27 describes GtkDrawingArea. - Section 24 to 27 describes GtkDrawingArea.
- Section 28 to 32 describes the list model and the list view (GtkListView, GtkGridView and GtkColumnView). - Section 28 describes Drag and Drop.
- Section 29 to 33 describes the list model and the list view (GtkListView, GtkGridView and GtkColumnView).
It also describes GtkExpression. It also describes GtkExpression.
The latest version of the tutorial is located at [GTK4-tutorial GitHub repository](https://github.com/ToshioCP/Gtk4-tutorial). The latest version of the tutorial is located at [GTK4-tutorial GitHub repository](https://github.com/ToshioCP/Gtk4-tutorial).

View file

@ -111,7 +111,8 @@ basics. The table of contents is at the end of this abstract.</p>
<li>Section 3 to 23 describes the basics, with the example of a simple <li>Section 3 to 23 describes the basics, with the example of a simple
editor <code>tfe</code> (Text File Editor).</li> editor <code>tfe</code> (Text File Editor).</li>
<li>Section 24 to 27 describes GtkDrawingArea.</li> <li>Section 24 to 27 describes GtkDrawingArea.</li>
<li>Section 28 to 32 describes the list model and the list view <li>Section 28 describes Drag and Drop.</li>
<li>Section 29 to 33 describes the list model and the list view
(GtkListView, GtkGridView and GtkColumnView). It also describes (GtkListView, GtkGridView and GtkColumnView). It also describes
GtkExpression.</li> GtkExpression.</li>
</ul> </ul>

View file

@ -120,16 +120,17 @@ Reference List Widget Overview</a>.</p>
GtkTreeView which are took over from GTK 3. Theres an article in <a GtkTreeView which are took over from GTK 3. Theres an article in <a
href="https://blog.gtk.org/2020/06/07/scalable-lists-in-gtk-4/">Gtk href="https://blog.gtk.org/2020/06/07/scalable-lists-in-gtk-4/">Gtk
Development blog</a> about list widgets by Matthias Clasen. He described Development blog</a> about list widgets by Matthias Clasen. He described
why GtkListView are developed to replace GtkListBox and GtkTreeView.</p> why GtkListView are developed to replace GtkTreeView. GtkTreeView is
deprecated since version 4.10.</p>
<p>GtkListView, GtkGridView, GtkColumnView and related objects are <p>GtkListView, GtkGridView, GtkColumnView and related objects are
described in Section 26 to 29.</p> described in Section 29 to 33.</p>
<h2 id="outline">Outline</h2> <h2 id="outline">Outline</h2>
<p>A list is a sequential data structure. For example, an ordered string <p>A list is a sequential data structure. For example, an ordered string
sequence “one”, “two”, “three”, “four” is a list. Each element is called sequence “one”, “two”, “three”, “four” is a list. Each element is called
item. A list is like an array, but in many cases it is implemented with item. A list is like an array, but in many cases it is implemented with
pointers which point to the next items of the list. And it has a start pointers which point to the next items of the list. And it has a start
point. So, each item can be referred by the index of the item (first 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. The 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 and its <p>Gio provides GListModel interface. It is a zero-based list and its
@ -138,12 +139,12 @@ implement the same interface. An object implements GListModel is not a
widget. So, the list is not displayed on the screen directly. Theres widget. So, the list is not displayed on the screen directly. Theres
another object GtkListView which is a widget to display the list. The 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. items in the list need to be connected to the items in GtkListView.
GtkListItemFactory instance maps items in the list to GListView.</p> GtkListItemFactory instance maps items in the list to GtkListView.</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>
</figure> </figure>
<h2 id="glistmodel">GListModel</h2> <h2 id="glistmodel-and-gtkstringlist">GListModel and GtkStringList</h2>
<p>If you want to make a list of strings with GListModel, for example, <p>If you want to make a list of strings with GListModel, for example,
“one”, “two”, “three”, “four”, note that strings cant be items of the “one”, “two”, “three”, “four”, note that strings cant be items of the
list. Because GListModel is a list of GObject objects and strings arent list. Because GListModel is a list of GObject objects and strings arent
@ -356,7 +357,7 @@ instantiated.</p>
</blockquote> </blockquote>
<p>Therefore, GtkListItem instance is used as the <code>this</code> <p>Therefore, GtkListItem instance is used as the <code>this</code>
object of the lookup tag when it is evaluated. <code>this</code> object object of the lookup tag when it is evaluated. <code>this</code> object
will be explained in section 30.</p> will be explained in section 31.</p>
<p>The C source code is as follows. Its name is <code>list2.c</code> and <p>The C source code is as follows. Its name is <code>list2.c</code> and
located under src/misc directory.</p> located under src/misc directory.</p>
<div class="sourceCode" id="cb7"><pre <div class="sourceCode" id="cb7"><pre
@ -431,7 +432,7 @@ are information of files under a certain directory. It uses
<code>g_file_enumerate_children_async()</code> to get the GFileInfo <code>g_file_enumerate_children_async()</code> to get the GFileInfo
objects. The list model is created by objects. The list model is created by
<code>gtk_directory_list_new</code> function.</p> <code>gtk_directory_list_new</code> function.</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>GtkDirectoryList <span class="op">*</span>gtk_directory_list_new <span class="op">(</span><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>attributes<span class="op">,</span> GFile <span class="op">*</span>file<span class="op">);</span></span></code></pre></div> <div class="sourceCode" id="cb8"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>GtkDirectoryList <span class="op">*</span>gtk_directory_list_new <span class="op">(</span><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>attributes<span class="op">,</span> GFile <span class="op">*</span>file<span class="op">);</span></span></code></pre></div>
<p><code>attributes</code> is a comma separated list of file attributes. <p><code>attributes</code> is a comma separated list of file attributes.
File attributes are key-value pairs. A key consists of a namespace and a File attributes are key-value pairs. A key consists of a namespace and a
name. For example, “standard::name” key is the name of a file. name. For example, “standard::name” key is the name of a file.
@ -477,7 +478,7 @@ seconds since the UNIX epoch</td>
<p>The current directory is “.”. The following program makes <p>The current directory is “.”. The following program makes
GtkDirectoryList <code>dl</code> and its contents are GFileInfo objects GtkDirectoryList <code>dl</code> and its contents are GFileInfo objects
under the current directory.</p> under the current directory.</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>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> <div class="sourceCode" id="cb9"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>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="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></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="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></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="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>g_object_unref <span class="op">(</span>file<span class="op">);</span></span></code></pre></div> <span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>g_object_unref <span class="op">(</span>file<span class="op">);</span></span></code></pre></div>
<p>It is not so difficult to make file listing program by changing <p>It is not so difficult to make file listing program by changing
@ -486,7 +487,7 @@ GInfoFile doesnt have properties. Lookup tag look for a property, so it
is useless for looking for a filename from a GFileInfo object. Instead, is useless for looking for a filename from a GFileInfo object. Instead,
closure tag is appropriate in this case. Closure tag specifies a 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">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">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-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> G_IS_FILE_INFO <span class="op">(</span>info<span class="op">)</span> <span class="op">?</span> g_strdup <span class="op">(</span>g_file_info_get_name <span class="op">(</span>info<span class="op">))</span> <span class="op">:</span> NULL<span class="op">;</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> <span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
@ -526,7 +527,7 @@ the function.
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, which is a this object. The this object is GListItem instance, which is a this object. The this object is
explained in section 28.</li> explained in section 31.</li>
<li><code>gtk_file_name</code> function is the callback function for the <li><code>gtk_file_name</code> function is the callback function for the
closure tag. It first checks the <code>info</code> parameter. Because it closure tag. It first checks the <code>info</code> parameter. Because it
can be NULL when GListItem <code>item</code> is unbounded. If its can be NULL when GListItem <code>item</code> is unbounded. If its

View file

@ -173,8 +173,7 @@ registered to IANA media types. Such “x-” subtype is not a standard mime
type.) Content type is also used by desktop systems.</li> type.) Content type is also used by desktop systems.</li>
</ul> </ul>
<p>GtkGridView uses the same GtkSingleSelection instance <p>GtkGridView uses the same GtkSingleSelection instance
(<code>singleselection</code>). So, its model property is set with (<code>singleselection</code>). So, its model property is set to it.</p>
it.</p>
<h2 id="ui-file-of-the-window">Ui file of the window</h2> <h2 id="ui-file-of-the-window">Ui file of the window</h2>
<p>The window is built with the following ui file. (See the screenshot <p>The window is built with the following ui file. (See the screenshot
at the beginning of this section).</p> at the beginning of this section).</p>
@ -291,7 +290,7 @@ GtkListView or GtkGridView.</li>
</ul> </ul>
<p>The action <code>view</code> is created, connected to the “activate” <p>The action <code>view</code> is created, connected to the “activate”
signal handler and inserted to the window (action map) as follows.</p> signal handler and inserted to the window (action map) as follows.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>act_view <span class="op">=</span> g_simple_action_new_stateful <span class="op">(</span><span class="st">&quot;view&quot;</span><span class="op">,</span> g_variant_type_new<span class="op">(</span><span class="st">&quot;s&quot;</span><span class="op">),</span> g_variant_new_string <span class="op">(</span><span class="st">&quot;list&quot;</span><span class="op">));</span></span> <div class="sourceCode" id="cb4"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>act_view <span class="op">=</span> g_simple_action_new_stateful <span class="op">(</span><span class="st">&quot;view&quot;</span><span class="op">,</span> g_variant_type_new<span class="op">(</span><span class="st">&quot;s&quot;</span><span class="op">),</span> g_variant_new_string <span class="op">(</span><span class="st">&quot;list&quot;</span><span class="op">));</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>g_signal_connect <span class="op">(</span>act_view<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>view_activated<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>g_signal_connect <span class="op">(</span>act_view<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>view_activated<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>g_action_map_add_action <span class="op">(</span>G_ACTION_MAP <span class="op">(</span>win<span class="op">),</span> G_ACTION <span class="op">(</span>act_view<span class="op">));</span></span></code></pre></div> <span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>g_action_map_add_action <span class="op">(</span>G_ACTION_MAP <span class="op">(</span>win<span class="op">),</span> G_ACTION <span class="op">(</span>act_view<span class="op">));</span></span></code></pre></div>
<p>The signal handler <code>view_activated</code> will be explained <p>The signal handler <code>view_activated</code> will be explained
@ -464,7 +463,7 @@ pressed. You can do anything you like by connecting the “activate”
signal to the handler.</p> signal to the handler.</p>
<p>The example <code>list4</code> launches <code>tfe</code> text file <p>The example <code>list4</code> launches <code>tfe</code> text file
editor if the item of the list is a text file.</p> editor if the item of the list is a text file.</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">static</span> <span class="dt">void</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">static</span> <span class="dt">void</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>list_activate <span class="op">(</span>GtkListView <span class="op">*</span>list<span class="op">,</span> <span class="dt">int</span> position<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>list_activate <span class="op">(</span>GtkListView <span class="op">*</span>list<span class="op">,</span> <span class="dt">int</span> position<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> GFileInfo <span class="op">*</span>info <span class="op">=</span> G_FILE_INFO <span class="op">(</span>g_list_model_get_item <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>gtk_list_view_get_model <span class="op">(</span>list<span class="op">)),</span> position<span class="op">));</span></span> <span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> GFileInfo <span class="op">*</span>info <span class="op">=</span> G_FILE_INFO <span class="op">(</span>g_list_model_get_item <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>gtk_list_view_get_model <span class="op">(</span>list<span class="op">)),</span> position<span class="op">));</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a> launch_tfe_with_file <span class="op">(</span>info<span class="op">);</span></span> <span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a> launch_tfe_with_file <span class="op">(</span>info<span class="op">);</span></span>
@ -558,12 +557,12 @@ list and items.</li>
<code>g_app_info_launch_default_for_uri</code> is convenient. The <code>g_app_info_launch_default_for_uri</code> is convenient. The
function automatically determines the default application from the file function automatically determines the default application from the file
and launches it. For example, if the file is text, then it launches and launches it. For example, if the file is text, then it launches
gedit with the file. Such feature comes from desktop.</p> GNOME text editor with the file. Such feature comes from desktop.</p>
<h2 id="compilation-and-execution">Compilation and execution</h2> <h2 id="compilation-and-execution">Compilation and execution</h2>
<p>The source files are located in src/list4 directory. To compile and <p>The source files are located in src/list4 directory. To compile and
execute list4, type as follows.</p> execute list4, type as follows.</p>
<pre><code>$ cd list4 # or cd src/list4. It depends your current directory. <pre><code>$ cd list4 # or cd src/list4. It depends your current directory.
$ meson _build $ meson setup _build
$ ninja -C _build $ ninja -C _build
$ _build/list4</code></pre> $ _build/list4</code></pre>
<p>Then a file list appears as a list style. Click on a button on the <p>Then a file list appears as a list style. Click on a button on the

View file

@ -191,13 +191,13 @@ value of the expression. The type of the value is int.</li>
</tr> </tr>
<tr class="even"> <tr class="even">
<td style="text-align: left;">G_TYPE_POINTER</td> <td style="text-align: left;">G_TYPE_POINTER</td>
<td style="text-align: left;"></td> <td style="text-align: left;">void *</td>
<td style="text-align: left;">gpointer</td> <td style="text-align: left;">gpointer</td>
<td style="text-align: left;"></td> <td style="text-align: left;">general pointer</td>
</tr> </tr>
<tr class="odd"> <tr class="odd">
<td style="text-align: left;">G_TYPE_STRING</td> <td style="text-align: left;">G_TYPE_STRING</td>
<td style="text-align: left;"></td> <td style="text-align: left;">char *</td>
<td style="text-align: left;">gchararray</td> <td style="text-align: left;">gchararray</td>
<td style="text-align: left;">null-terminated Cstring</td> <td style="text-align: left;">null-terminated Cstring</td>
</tr> </tr>
@ -250,7 +250,7 @@ instance to another expression.</p>
<p>A property expression (GtkPropertyExpression) looks up a property in <p>A property expression (GtkPropertyExpression) looks up a property in
a GObject instance. For example, a property expression that refers a GObject instance. For example, a property expression that refers
“label” property in a GtkLabel object is created like this.</p> “label” property in a GtkLabel object is created like this.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>expression <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_LABEL<span class="op">,</span> another_expression<span class="op">,</span> <span class="st">&quot;label&quot;</span><span class="op">);</span></span></code></pre></div> <div class="sourceCode" id="cb4"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>expression <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_LABEL<span class="op">,</span> another_expression<span class="op">,</span> <span class="st">&quot;label&quot;</span><span class="op">);</span></span></code></pre></div>
<p>The second parameter <code>another_expression</code> is one of:</p> <p>The second parameter <code>another_expression</code> is one of:</p>
<ul> <ul>
<li>An expression that gives a GtkLabel instance when it is <li>An expression that gives a GtkLabel instance when it is
@ -259,14 +259,14 @@ evaluated.</li>
is evaluated. The instance is called <code>this</code> object.</li> is evaluated. The instance is called <code>this</code> object.</li>
</ul> </ul>
<p>For example,</p> <p>For example,</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>label <span class="op">=</span> gtk_label_new <span class="op">(</span><span class="st">&quot;Hello&quot;</span><span class="op">);</span></span> <div class="sourceCode" id="cb5"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>label <span class="op">=</span> gtk_label_new <span class="op">(</span><span class="st">&quot;Hello&quot;</span><span class="op">);</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>another_expression <span class="op">=</span> gtk_constant_expression_new <span class="op">(</span>GTK_TYPE_LABEL<span class="op">,</span> label<span class="op">);</span></span> <span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>another_expression <span class="op">=</span> gtk_constant_expression_new <span class="op">(</span>GTK_TYPE_LABEL<span class="op">,</span> label<span class="op">);</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>expression <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_LABEL<span class="op">,</span> another_expression<span class="op">,</span> <span class="st">&quot;label&quot;</span><span class="op">);</span></span></code></pre></div> <span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>expression <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_LABEL<span class="op">,</span> another_expression<span class="op">,</span> <span class="st">&quot;label&quot;</span><span class="op">);</span></span></code></pre></div>
<p>If <code>expression</code> is evaluated, the second parameter <p>If <code>expression</code> is evaluated, the second parameter
<code>another_expression</code> is evaluated in advance. The value of <code>another_expression</code> is evaluated in advance. The value of
<code>another_expression</code> is the <code>label</code> (GtkLabel <code>another_expression</code> is the <code>label</code> (GtkLabel
instance). Then, <code>expression</code> looks up “label” property of instance). Then, <code>expression</code> looks up “label” property of
the label and the evaluation results “Hello”.</p> the label and the evaluation results in “Hello”.</p>
<p>In the example above, the second argument of <p>In the example above, the second argument of
<code>gtk_property_expression_new</code> is another expression. But the <code>gtk_property_expression_new</code> is another expression. But the
second argument can be NULL. If it is NULL, <code>this</code> instance second argument can be NULL. If it is NULL, <code>this</code> instance
@ -291,7 +291,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
<span id="cb6-14"><a href="#cb6-14"></a> <span class="cf">if</span> <span class="op">(</span>gtk_expression_evaluate <span class="op">(</span>expression<span class="op">,</span> label<span class="op">,</span> <span class="op">&amp;</span>value<span class="op">))</span></span> <span id="cb6-14"><a href="#cb6-14"></a> <span class="cf">if</span> <span class="op">(</span>gtk_expression_evaluate <span class="op">(</span>expression<span class="op">,</span> label<span class="op">,</span> <span class="op">&amp;</span>value<span class="op">))</span></span>
<span id="cb6-15"><a href="#cb6-15"></a> g_print <span class="op">(</span><span class="st">&quot;The value is %s.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">,</span> g_value_get_string <span class="op">(&amp;</span>value<span class="op">));</span></span> <span id="cb6-15"><a href="#cb6-15"></a> g_print <span class="op">(</span><span class="st">&quot;The value is %s.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">,</span> g_value_get_string <span class="op">(&amp;</span>value<span class="op">));</span></span>
<span id="cb6-16"><a href="#cb6-16"></a> <span class="cf">else</span></span> <span id="cb6-16"><a href="#cb6-16"></a> <span class="cf">else</span></span>
<span id="cb6-17"><a href="#cb6-17"></a> g_print <span class="op">(</span><span class="st">&quot;The constant expression wasn&#39;t evaluated correctly.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span> <span id="cb6-17"><a href="#cb6-17"></a> g_print <span class="op">(</span><span class="st">&quot;The property expression wasn&#39;t evaluated correctly.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span>
<span id="cb6-18"><a href="#cb6-18"></a> gtk_expression_unref <span class="op">(</span>expression<span class="op">);</span></span> <span id="cb6-18"><a href="#cb6-18"></a> gtk_expression_unref <span class="op">(</span>expression<span class="op">);</span></span>
<span id="cb6-19"><a href="#cb6-19"></a> g_value_unset <span class="op">(&amp;</span>value<span class="op">);</span></span> <span id="cb6-19"><a href="#cb6-19"></a> g_value_unset <span class="op">(&amp;</span>value<span class="op">);</span></span>
<span id="cb6-20"><a href="#cb6-20"></a></span> <span id="cb6-20"><a href="#cb6-20"></a></span>
@ -311,8 +311,8 @@ the expression with a this instance <code>label</code>. The result is
stored in the GValue <code>value</code>. The function stored in the GValue <code>value</code>. The function
<code>g_value_get_string</code> gets a string from the GValue. But the <code>g_value_get_string</code> gets a string from the GValue. But the
string is owned by the GValue so you must not free the string.</li> string is owned by the GValue so you must not free the string.</li>
<li>18-19: Release the expression and unset the GValue. At the same time <li>18-19: Releases the expression and unset the GValue. At the same
the string in the GValue is freed.</li> time the string in the GValue is freed.</li>
</ul> </ul>
<p>If the second argument of <code>gtk_property_expression_new</code> <p>If the second argument of <code>gtk_property_expression_new</code>
isnt NULL, it is another expression. The expression is owned by a newly isnt NULL, it is another expression. The expression is owned by a newly
@ -334,79 +334,44 @@ respectively. When you program in C language, GtkCClosureExpression and
GCClosure are appropriate.</p> GCClosure are appropriate.</p>
<p>A closure expression is created with <p>A closure expression is created with
<code>gtk_cclosure_expression_new</code> function.</p> <code>gtk_cclosure_expression_new</code> function.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>GtkExpression <span class="op">*</span></span> <div class="sourceCode" id="cb7"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>gtk_cclosure_expression_new <span class="op">(</span>GType value_type<span class="op">,</span></span> <span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>callback <span class="op">(</span>GObject <span class="op">*</span>object<span class="op">,</span> <span class="dt">int</span> x<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>s<span class="op">)</span></span></code></pre></div>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> GClosureMarshal marshal<span class="op">,</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> guint n_params<span class="op">,</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> GtkExpression <span class="op">**</span>params<span class="op">,</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> GCallback callback_func<span class="op">,</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> gpointer user_data<span class="op">,</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> GClosureNotify user_destroy<span class="op">);</span></span></code></pre></div>
<ul>
<li><code>value_type</code> is the type of the value when it is
evaluated.</li>
<li><code>marshal</code> is a marshaller. You can assign NULL. If it is
NULL, then <code>g_cclosure_marshal_generic ()</code> is used as a
marshaller. It is a generic marshaller function implemented via
libffi.</li>
<li><code>n_params</code> is the number of parameters.</li>
<li><code>params</code> points expressions for each parameter of the
call back function.</li>
<li><code>callback_func</code> is a callback function. It is given
arguments <code>this</code> and parameters above. So, if
<code>n_params</code> is 3, the number of arguments of the function is
4. (<code>this</code> and <code>params</code>. See below.)</li>
<li><code>user_data</code> is user data. You can add it for the closure.
It is like <code>user_data</code> in <code>g_signal_connect</code>. If
it is not necessary, assign NULL.</li>
<li><code>user_destroy</code> is a destroy notify for
<code>user_data</code>. It is called to destroy <code>user_data</code>
when it is no longer needed. If NULL is assigned to
<code>user_data</code>, assign NULL to <code>user_destroy</code>,
too.</li>
</ul>
<p>Call back functions have the following format.</p>
<pre><code>C-type
callback (this, param1, param2, ...)</code></pre>
<p>For example,</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>callback <span class="op">(</span>GObject <span class="op">*</span>object<span class="op">,</span> <span class="dt">int</span> x<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>s<span class="op">)</span></span></code></pre></div>
<p>The following is <code>exp_closure_simple.c</code> in <p>The following is <code>exp_closure_simple.c</code> in
<code>src/expression</code>.</p> <code>src/expression</code>.</p>
<div class="sourceCode" id="cb10"><pre <div class="sourceCode" id="cb8"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span> class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb10-2"><a href="#cb10-2"></a></span> <span id="cb8-2"><a href="#cb8-2"></a></span>
<span id="cb10-3"><a href="#cb10-3"></a><span class="dt">static</span> <span class="dt">int</span></span> <span id="cb8-3"><a href="#cb8-3"></a><span class="dt">static</span> <span class="dt">int</span></span>
<span id="cb10-4"><a href="#cb10-4"></a>calc <span class="op">(</span>GtkLabel <span class="op">*</span>label<span class="op">)</span> <span class="op">{</span> <span class="co">/* this object */</span></span> <span id="cb8-4"><a href="#cb8-4"></a>calc <span class="op">(</span>GtkLabel <span class="op">*</span>label<span class="op">)</span> <span class="op">{</span> <span class="co">/* this object */</span></span>
<span id="cb10-5"><a href="#cb10-5"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span> s<span class="op">;</span></span> <span id="cb8-5"><a href="#cb8-5"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span> s<span class="op">;</span></span>
<span id="cb10-6"><a href="#cb10-6"></a> <span class="dt">int</span> i<span class="op">,</span> j<span class="op">;</span></span> <span id="cb8-6"><a href="#cb8-6"></a> <span class="dt">int</span> i<span class="op">,</span> j<span class="op">;</span></span>
<span id="cb10-7"><a href="#cb10-7"></a></span> <span id="cb8-7"><a href="#cb8-7"></a></span>
<span id="cb10-8"><a href="#cb10-8"></a> s <span class="op">=</span> gtk_label_get_text <span class="op">(</span>label<span class="op">);</span> <span class="co">/* s is owned by the label. */</span></span> <span id="cb8-8"><a href="#cb8-8"></a> s <span class="op">=</span> gtk_label_get_text <span class="op">(</span>label<span class="op">);</span> <span class="co">/* s is owned by the label. */</span></span>
<span id="cb10-9"><a href="#cb10-9"></a> sscanf <span class="op">(</span>s<span class="op">,</span> <span class="st">&quot;%d+%d&quot;</span><span class="op">,</span> <span class="op">&amp;</span>i<span class="op">,</span> <span class="op">&amp;</span>j<span class="op">);</span></span> <span id="cb8-9"><a href="#cb8-9"></a> sscanf <span class="op">(</span>s<span class="op">,</span> <span class="st">&quot;%d+%d&quot;</span><span class="op">,</span> <span class="op">&amp;</span>i<span class="op">,</span> <span class="op">&amp;</span>j<span class="op">);</span></span>
<span id="cb10-10"><a href="#cb10-10"></a> <span class="cf">return</span> i<span class="op">+</span>j<span class="op">;</span></span> <span id="cb8-10"><a href="#cb8-10"></a> <span class="cf">return</span> i<span class="op">+</span>j<span class="op">;</span></span>
<span id="cb10-11"><a href="#cb10-11"></a><span class="op">}</span></span> <span id="cb8-11"><a href="#cb8-11"></a><span class="op">}</span></span>
<span id="cb10-12"><a href="#cb10-12"></a></span> <span id="cb8-12"><a href="#cb8-12"></a></span>
<span id="cb10-13"><a href="#cb10-13"></a><span class="dt">int</span></span> <span id="cb8-13"><a href="#cb8-13"></a><span class="dt">int</span></span>
<span id="cb10-14"><a href="#cb10-14"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span> <span id="cb8-14"><a href="#cb8-14"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-15"><a href="#cb10-15"></a> GtkExpression <span class="op">*</span>expression<span class="op">;</span></span> <span id="cb8-15"><a href="#cb8-15"></a> GtkExpression <span class="op">*</span>expression<span class="op">;</span></span>
<span id="cb10-16"><a href="#cb10-16"></a> GValue value <span class="op">=</span> G_VALUE_INIT<span class="op">;</span></span> <span id="cb8-16"><a href="#cb8-16"></a> GValue value <span class="op">=</span> G_VALUE_INIT<span class="op">;</span></span>
<span id="cb10-17"><a href="#cb10-17"></a> GtkLabel <span class="op">*</span>label<span class="op">;</span></span> <span id="cb8-17"><a href="#cb8-17"></a> GtkLabel <span class="op">*</span>label<span class="op">;</span></span>
<span id="cb10-18"><a href="#cb10-18"></a></span> <span id="cb8-18"><a href="#cb8-18"></a></span>
<span id="cb10-19"><a href="#cb10-19"></a> gtk_init <span class="op">();</span></span> <span id="cb8-19"><a href="#cb8-19"></a> gtk_init <span class="op">();</span></span>
<span id="cb10-20"><a href="#cb10-20"></a> label <span class="op">=</span> GTK_LABEL <span class="op">(</span>gtk_label_new <span class="op">(</span><span class="st">&quot;123+456&quot;</span><span class="op">));</span></span> <span id="cb8-20"><a href="#cb8-20"></a> label <span class="op">=</span> GTK_LABEL <span class="op">(</span>gtk_label_new <span class="op">(</span><span class="st">&quot;123+456&quot;</span><span class="op">));</span></span>
<span id="cb10-21"><a href="#cb10-21"></a> g_object_ref_sink <span class="op">(</span>label<span class="op">);</span></span> <span id="cb8-21"><a href="#cb8-21"></a> g_object_ref_sink <span class="op">(</span>label<span class="op">);</span></span>
<span id="cb10-22"><a href="#cb10-22"></a> expression <span class="op">=</span> gtk_cclosure_expression_new <span class="op">(</span>G_TYPE_INT<span class="op">,</span> NULL<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> NULL<span class="op">,</span></span> <span id="cb8-22"><a href="#cb8-22"></a> expression <span class="op">=</span> gtk_cclosure_expression_new <span class="op">(</span>G_TYPE_INT<span class="op">,</span> NULL<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> NULL<span class="op">,</span></span>
<span id="cb10-23"><a href="#cb10-23"></a> G_CALLBACK <span class="op">(</span>calc<span class="op">),</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span> <span id="cb8-23"><a href="#cb8-23"></a> G_CALLBACK <span class="op">(</span>calc<span class="op">),</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb10-24"><a href="#cb10-24"></a> <span class="cf">if</span> <span class="op">(</span>gtk_expression_evaluate <span class="op">(</span>expression<span class="op">,</span> label<span class="op">,</span> <span class="op">&amp;</span>value<span class="op">))</span> <span class="co">/* &#39;this&#39; object is the label. */</span></span> <span id="cb8-24"><a href="#cb8-24"></a> <span class="cf">if</span> <span class="op">(</span>gtk_expression_evaluate <span class="op">(</span>expression<span class="op">,</span> label<span class="op">,</span> <span class="op">&amp;</span>value<span class="op">))</span> <span class="co">/* &#39;this&#39; object is the label. */</span></span>
<span id="cb10-25"><a href="#cb10-25"></a> g_print <span class="op">(</span><span class="st">&quot;%d</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">,</span> g_value_get_int <span class="op">(&amp;</span>value<span class="op">));</span></span> <span id="cb8-25"><a href="#cb8-25"></a> g_print <span class="op">(</span><span class="st">&quot;%d</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">,</span> g_value_get_int <span class="op">(&amp;</span>value<span class="op">));</span></span>
<span id="cb10-26"><a href="#cb10-26"></a> <span class="cf">else</span></span> <span id="cb8-26"><a href="#cb8-26"></a> <span class="cf">else</span></span>
<span id="cb10-27"><a href="#cb10-27"></a> g_print <span class="op">(</span><span class="st">&quot;The closure expression wasn&#39;t evaluated correctly.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span> <span id="cb8-27"><a href="#cb8-27"></a> g_print <span class="op">(</span><span class="st">&quot;The closure expression wasn&#39;t evaluated correctly.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span>
<span id="cb10-28"><a href="#cb10-28"></a> gtk_expression_unref <span class="op">(</span>expression<span class="op">);</span></span> <span id="cb8-28"><a href="#cb8-28"></a> gtk_expression_unref <span class="op">(</span>expression<span class="op">);</span></span>
<span id="cb10-29"><a href="#cb10-29"></a> g_value_unset <span class="op">(&amp;</span>value<span class="op">);</span></span> <span id="cb8-29"><a href="#cb8-29"></a> g_value_unset <span class="op">(&amp;</span>value<span class="op">);</span></span>
<span id="cb10-30"><a href="#cb10-30"></a> g_object_unref <span class="op">(</span>label<span class="op">);</span></span> <span id="cb8-30"><a href="#cb8-30"></a> g_object_unref <span class="op">(</span>label<span class="op">);</span></span>
<span id="cb10-31"><a href="#cb10-31"></a> </span> <span id="cb8-31"><a href="#cb8-31"></a> </span>
<span id="cb10-32"><a href="#cb10-32"></a> <span class="cf">return</span> <span class="dv">0</span><span class="op">;</span></span> <span id="cb8-32"><a href="#cb8-32"></a> <span class="cf">return</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb10-33"><a href="#cb10-33"></a><span class="op">}</span></span></code></pre></div> <span id="cb8-33"><a href="#cb8-33"></a><span class="op">}</span></span></code></pre></div>
<ul> <ul>
<li>3-11: A call back function. The parameter is only one and it is a <li>3-11: A call back function. The parameter is only one and it is a
this object. It is a GtkLabel and its label is assumed to be this object. It is a GtkLabel and its label is assumed to be
@ -419,16 +384,17 @@ argument of <code>gtk_cclosure_expression_new</code> is
<code>G_TYPE_POINTER</code>. There is a sample program <code>G_TYPE_POINTER</code>. There is a sample program
<code>exp_closure_with_error_report</code> in <code>exp_closure_with_error_report</code> in
<code>src/expression</code> directory.</li> <code>src/expression</code> directory.</li>
<li>19: gtk_init initializes GTK. It is necessary for GtkLabel.</li> <li>19: The function `gtk_init`` initializes GTK. It is necessary for
GtkLabel.</li>
<li>20: A GtkLabel instance is created with “123+456”.</li> <li>20: A GtkLabel instance is created with “123+456”.</li>
<li>21: The instance has floating reference. It is changed to an <li>21: The instance has floating reference. It is changed to an
ordinary reference count.</li> ordinary reference count.</li>
<li>22-23: Create a closure expression. Its return value type is <li>22-23: Creates a closure expression. Its return value type is
<code>G_TYPE_INT</code> and no parameters or this object.</li> <code>G_TYPE_INT</code> and no parameters or this object.</li>
<li>24: Evaluates the expression with the label as a this object.</li> <li>24: Evaluates the expression with the label as a this object.</li>
<li>25: If the evaluation successes, show the sum of “123+456”. Its <li>25: If the evaluation successes, the sum of “123+456”, which is 579,
579.</li> is shown.</li>
<li>27: If it fails, show an error message.</li> <li>27: If it fails, an error message appears.</li>
<li>28-30: Releases the expression and the label. Unsets the value.</li> <li>28-30: Releases the expression and the label. Unsets the value.</li>
</ul> </ul>
<p>Closure expression is flexible than other type of expression because <p>Closure expression is flexible than other type of expression because
@ -436,18 +402,19 @@ you can specify your own callback function.</p>
<h2 id="gtkexpressionwatch">GtkExpressionWatch</h2> <h2 id="gtkexpressionwatch">GtkExpressionWatch</h2>
<p>GtkExpressionWatch is a structure, not an object. It represents a <p>GtkExpressionWatch is a structure, not an object. It represents a
watched GtkExpression. Two functions create GtkExpressionWatch watched GtkExpression. Two functions create GtkExpressionWatch
structure.</p> structure. They are <code>gtk_expression_bind</code> and
<code>gtk_expression_watch</code>.</p>
<h3 id="gtk_expression_bind-function">gtk_expression_bind function</h3> <h3 id="gtk_expression_bind-function">gtk_expression_bind function</h3>
<p>This function binds the target objects property to the expression. <p>This function binds the target objects property to the expression.
If the value of the expression changes, the property reflects the value If the value of the expression changes, the property reflects the value
immediately.</p> immediately.</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>GtkExpressionWatch<span class="op">*</span></span> <div class="sourceCode" id="cb9"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>GtkExpressionWatch<span class="op">*</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>gtk_expression_bind <span class="op">(</span></span> <span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>gtk_expression_bind <span class="op">(</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> GtkExpression<span class="op">*</span> self<span class="op">,</span></span> <span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> GtkExpression<span class="op">*</span> self<span class="op">,</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> target<span class="op">,</span></span> <span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> target<span class="op">,</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">const</span> <span class="dt">char</span><span class="op">*</span> property<span class="op">,</span></span> <span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">const</span> <span class="dt">char</span><span class="op">*</span> property<span class="op">,</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> this_</span> <span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> this_</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div> <span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div>
<p>This function takes the ownership of the expression. So, if you want <p>This function takes the ownership of the expression. So, if you want
to own the expression, call <code>gtk_expression_ref ()</code> to to own the expression, call <code>gtk_expression_ref ()</code> to
increase the reference count of the expression. And you should unref it increase the reference count of the expression. And you should unref it
@ -463,41 +430,41 @@ about releasing the expression.</p>
the scale value increases and the number on the label also increases. In the scale value increases and the number on the label also increases. In
the same way, if you move it to the left, the number on the label the same way, if you move it to the left, the number on the label
decreases. The label is bound to the scale value via an adjustment.</p> decreases. The label is bound to the scale value via an adjustment.</p>
<div class="sourceCode" id="cb12"><pre <div class="sourceCode" id="cb10"><pre
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb12-1"><a href="#cb12-1"></a><span class="fu">&lt;?xml</span><span class="ot"> version=</span><span class="st">&#39;1.0&#39;</span><span class="ot"> encoding=</span><span class="st">&#39;UTF-8&#39;</span><span class="fu">?&gt;</span></span> class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb10-1"><a href="#cb10-1"></a><span class="fu">&lt;?xml</span><span class="ot"> version=</span><span class="st">&#39;1.0&#39;</span><span class="ot"> encoding=</span><span class="st">&#39;UTF-8&#39;</span><span class="fu">?&gt;</span></span>
<span id="cb12-2"><a href="#cb12-2"></a>&lt;<span class="kw">interface</span>&gt;</span> <span id="cb10-2"><a href="#cb10-2"></a>&lt;<span class="kw">interface</span>&gt;</span>
<span id="cb12-3"><a href="#cb12-3"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&#39;GtkApplicationWindow&#39;</span><span class="ot"> id=</span><span class="st">&#39;win&#39;</span>&gt;</span> <span id="cb10-3"><a href="#cb10-3"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&#39;GtkApplicationWindow&#39;</span><span class="ot"> id=</span><span class="st">&#39;win&#39;</span>&gt;</span>
<span id="cb12-4"><a href="#cb12-4"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;default-width&#39;</span>&gt;600&lt;/<span class="kw">property</span>&gt;</span> <span id="cb10-4"><a href="#cb10-4"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;default-width&#39;</span>&gt;600&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-5"><a href="#cb12-5"></a> &lt;<span class="kw">child</span>&gt;</span> <span id="cb10-5"><a href="#cb10-5"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb12-6"><a href="#cb12-6"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&#39;GtkBox&#39;</span>&gt;</span> <span id="cb10-6"><a href="#cb10-6"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&#39;GtkBox&#39;</span>&gt;</span>
<span id="cb12-7"><a href="#cb12-7"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;orientation&#39;</span>&gt;GTK_ORIENTATION_VERTICAL&lt;/<span class="kw">property</span>&gt;</span> <span id="cb10-7"><a href="#cb10-7"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;orientation&#39;</span>&gt;GTK_ORIENTATION_VERTICAL&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-8"><a href="#cb12-8"></a> &lt;<span class="kw">child</span>&gt;</span> <span id="cb10-8"><a href="#cb10-8"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb12-9"><a href="#cb12-9"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&#39;GtkLabel&#39;</span><span class="ot"> id=</span><span class="st">&#39;label&#39;</span>&gt;</span> <span id="cb10-9"><a href="#cb10-9"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&#39;GtkLabel&#39;</span><span class="ot"> id=</span><span class="st">&#39;label&#39;</span>&gt;</span>
<span id="cb12-10"><a href="#cb12-10"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;10&lt;/<span class="kw">property</span>&gt;</span> <span id="cb10-10"><a href="#cb10-10"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;10&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-11"><a href="#cb12-11"></a> &lt;/<span class="kw">object</span>&gt;</span> <span id="cb10-11"><a href="#cb10-11"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb12-12"><a href="#cb12-12"></a> &lt;/<span class="kw">child</span>&gt;</span> <span id="cb10-12"><a href="#cb10-12"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb12-13"><a href="#cb12-13"></a> &lt;<span class="kw">child</span>&gt;</span> <span id="cb10-13"><a href="#cb10-13"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb12-14"><a href="#cb12-14"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&#39;GtkScale&#39;</span>&gt;</span> <span id="cb10-14"><a href="#cb10-14"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&#39;GtkScale&#39;</span>&gt;</span>
<span id="cb12-15"><a href="#cb12-15"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;adjustment&#39;</span>&gt;</span> <span id="cb10-15"><a href="#cb10-15"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;adjustment&#39;</span>&gt;</span>
<span id="cb12-16"><a href="#cb12-16"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&#39;GtkAdjustment&#39;</span><span class="ot"> id=</span><span class="st">&#39;adjustment&#39;</span>&gt;</span> <span id="cb10-16"><a href="#cb10-16"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&#39;GtkAdjustment&#39;</span><span class="ot"> id=</span><span class="st">&#39;adjustment&#39;</span>&gt;</span>
<span id="cb12-17"><a href="#cb12-17"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;upper&#39;</span>&gt;20.0&lt;/<span class="kw">property</span>&gt;</span> <span id="cb10-17"><a href="#cb10-17"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;upper&#39;</span>&gt;20.0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-18"><a href="#cb12-18"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;lower&#39;</span>&gt;0.0&lt;/<span class="kw">property</span>&gt;</span> <span id="cb10-18"><a href="#cb10-18"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;lower&#39;</span>&gt;0.0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-19"><a href="#cb12-19"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;value&#39;</span>&gt;10.0&lt;/<span class="kw">property</span>&gt;</span> <span id="cb10-19"><a href="#cb10-19"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;value&#39;</span>&gt;10.0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-20"><a href="#cb12-20"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;step-increment&#39;</span>&gt;1.0&lt;/<span class="kw">property</span>&gt;</span> <span id="cb10-20"><a href="#cb10-20"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;step-increment&#39;</span>&gt;1.0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-21"><a href="#cb12-21"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;page-increment&#39;</span>&gt;5.0&lt;/<span class="kw">property</span>&gt;</span> <span id="cb10-21"><a href="#cb10-21"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;page-increment&#39;</span>&gt;5.0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-22"><a href="#cb12-22"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;page-size&#39;</span>&gt;0.0&lt;/<span class="kw">property</span>&gt;</span> <span id="cb10-22"><a href="#cb10-22"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;page-size&#39;</span>&gt;0.0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-23"><a href="#cb12-23"></a> &lt;/<span class="kw">object</span>&gt;</span> <span id="cb10-23"><a href="#cb10-23"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb12-24"><a href="#cb12-24"></a> &lt;/<span class="kw">property</span>&gt;</span> <span id="cb10-24"><a href="#cb10-24"></a> &lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-25"><a href="#cb12-25"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;digits&#39;</span>&gt;0&lt;/<span class="kw">property</span>&gt;</span> <span id="cb10-25"><a href="#cb10-25"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;digits&#39;</span>&gt;0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-26"><a href="#cb12-26"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;draw-value&#39;</span>&gt;true&lt;/<span class="kw">property</span>&gt;</span> <span id="cb10-26"><a href="#cb10-26"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;draw-value&#39;</span>&gt;true&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-27"><a href="#cb12-27"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;has-origin&#39;</span>&gt;true&lt;/<span class="kw">property</span>&gt;</span> <span id="cb10-27"><a href="#cb10-27"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;has-origin&#39;</span>&gt;true&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-28"><a href="#cb12-28"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;round-digits&#39;</span>&gt;0&lt;/<span class="kw">property</span>&gt;</span> <span id="cb10-28"><a href="#cb10-28"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&#39;round-digits&#39;</span>&gt;0&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb12-29"><a href="#cb12-29"></a> &lt;/<span class="kw">object</span>&gt;</span> <span id="cb10-29"><a href="#cb10-29"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb12-30"><a href="#cb12-30"></a> &lt;/<span class="kw">child</span>&gt;</span> <span id="cb10-30"><a href="#cb10-30"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb12-31"><a href="#cb12-31"></a> &lt;/<span class="kw">object</span>&gt;</span> <span id="cb10-31"><a href="#cb10-31"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb12-32"><a href="#cb12-32"></a> &lt;/<span class="kw">child</span>&gt;</span> <span id="cb10-32"><a href="#cb10-32"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb12-33"><a href="#cb12-33"></a> &lt;/<span class="kw">object</span>&gt;</span> <span id="cb10-33"><a href="#cb10-33"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb12-34"><a href="#cb12-34"></a>&lt;/<span class="kw">interface</span>&gt;</span></code></pre></div> <span id="cb10-34"><a href="#cb10-34"></a>&lt;/<span class="kw">interface</span>&gt;</span></code></pre></div>
<p>The ui file describes the following parent-child relationship.</p> <p>The ui file describes the following parent-child relationship.</p>
<pre><code>GtkApplicationWindow (win) -- GtkBox -+- GtkLabel (label) <pre><code>GtkApplicationWindow (win) -- GtkBox -+- GtkLabel (label)
+- GtkScale</code></pre> +- GtkScale</code></pre>
@ -523,73 +490,73 @@ orange bar appears between the origin and the current point.</li>
changes. For example, if it is zero, the slider moves to an integer changes. For example, if it is zero, the slider moves to an integer
point.</li> point.</li>
</ul> </ul>
<div class="sourceCode" id="cb14"><pre <div class="sourceCode" id="cb12"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb14-1"><a href="#cb14-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span> class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb12-1"><a href="#cb12-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb14-2"><a href="#cb14-2"></a></span> <span id="cb12-2"><a href="#cb12-2"></a></span>
<span id="cb14-3"><a href="#cb14-3"></a>GtkExpressionWatch <span class="op">*</span>watch<span class="op">;</span></span> <span id="cb12-3"><a href="#cb12-3"></a>GtkExpressionWatch <span class="op">*</span>watch<span class="op">;</span></span>
<span id="cb14-4"><a href="#cb14-4"></a></span> <span id="cb12-4"><a href="#cb12-4"></a></span>
<span id="cb14-5"><a href="#cb14-5"></a><span class="dt">static</span> <span class="dt">int</span></span> <span id="cb12-5"><a href="#cb12-5"></a><span class="dt">static</span> <span class="dt">int</span></span>
<span id="cb14-6"><a href="#cb14-6"></a>f2i <span class="op">(</span>GObject <span class="op">*</span>object<span class="op">,</span> <span class="dt">double</span> d<span class="op">)</span> <span class="op">{</span></span> <span id="cb12-6"><a href="#cb12-6"></a>f2i <span class="op">(</span>GObject <span class="op">*</span>object<span class="op">,</span> <span class="dt">double</span> d<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-7"><a href="#cb14-7"></a> <span class="cf">return</span> <span class="op">(</span><span class="dt">int</span><span class="op">)</span> d<span class="op">;</span></span> <span id="cb12-7"><a href="#cb12-7"></a> <span class="cf">return</span> <span class="op">(</span><span class="dt">int</span><span class="op">)</span> d<span class="op">;</span></span>
<span id="cb14-8"><a href="#cb14-8"></a><span class="op">}</span></span> <span id="cb12-8"><a href="#cb12-8"></a><span class="op">}</span></span>
<span id="cb14-9"><a href="#cb14-9"></a></span> <span id="cb12-9"><a href="#cb12-9"></a></span>
<span id="cb14-10"><a href="#cb14-10"></a><span class="dt">static</span> <span class="dt">int</span></span> <span id="cb12-10"><a href="#cb12-10"></a><span class="dt">static</span> <span class="dt">int</span></span>
<span id="cb14-11"><a href="#cb14-11"></a>close_request_cb <span class="op">(</span>GtkWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span> <span id="cb12-11"><a href="#cb12-11"></a>close_request_cb <span class="op">(</span>GtkWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-12"><a href="#cb14-12"></a> gtk_expression_watch_unwatch <span class="op">(</span>watch<span class="op">);</span></span> <span id="cb12-12"><a href="#cb12-12"></a> gtk_expression_watch_unwatch <span class="op">(</span>watch<span class="op">);</span></span>
<span id="cb14-13"><a href="#cb14-13"></a> <span class="cf">return</span> false<span class="op">;</span></span> <span id="cb12-13"><a href="#cb12-13"></a> <span class="cf">return</span> false<span class="op">;</span></span>
<span id="cb14-14"><a href="#cb14-14"></a><span class="op">}</span></span> <span id="cb12-14"><a href="#cb12-14"></a><span class="op">}</span></span>
<span id="cb14-15"><a href="#cb14-15"></a></span> <span id="cb12-15"><a href="#cb12-15"></a></span>
<span id="cb14-16"><a href="#cb14-16"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb12-16"><a href="#cb12-16"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb14-17"><a href="#cb14-17"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span> <span id="cb12-17"><a href="#cb12-17"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-18"><a href="#cb14-18"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span> <span id="cb12-18"><a href="#cb12-18"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
<span id="cb14-19"><a href="#cb14-19"></a> gtk_window_present <span class="op">(</span>gtk_application_get_active_window<span class="op">(</span>app<span class="op">));</span></span> <span id="cb12-19"><a href="#cb12-19"></a> gtk_window_present <span class="op">(</span>gtk_application_get_active_window<span class="op">(</span>app<span class="op">));</span></span>
<span id="cb14-20"><a href="#cb14-20"></a><span class="op">}</span></span> <span id="cb12-20"><a href="#cb12-20"></a><span class="op">}</span></span>
<span id="cb14-21"><a href="#cb14-21"></a></span> <span id="cb12-21"><a href="#cb12-21"></a></span>
<span id="cb14-22"><a href="#cb14-22"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb12-22"><a href="#cb12-22"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb14-23"><a href="#cb14-23"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span> <span id="cb12-23"><a href="#cb12-23"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-24"><a href="#cb14-24"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span> <span id="cb12-24"><a href="#cb12-24"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
<span id="cb14-25"><a href="#cb14-25"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span> <span id="cb12-25"><a href="#cb12-25"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
<span id="cb14-26"><a href="#cb14-26"></a> GtkWidget <span class="op">*</span>win<span class="op">,</span> <span class="op">*</span>label<span class="op">;</span></span> <span id="cb12-26"><a href="#cb12-26"></a> GtkWidget <span class="op">*</span>win<span class="op">,</span> <span class="op">*</span>label<span class="op">;</span></span>
<span id="cb14-27"><a href="#cb14-27"></a> GtkAdjustment <span class="op">*</span>adjustment<span class="op">;</span></span> <span id="cb12-27"><a href="#cb12-27"></a> GtkAdjustment <span class="op">*</span>adjustment<span class="op">;</span></span>
<span id="cb14-28"><a href="#cb14-28"></a> GtkExpression <span class="op">*</span>expression<span class="op">,</span> <span class="op">*</span>params<span class="op">[</span><span class="dv">1</span><span class="op">];</span></span> <span id="cb12-28"><a href="#cb12-28"></a> GtkExpression <span class="op">*</span>expression<span class="op">,</span> <span class="op">*</span>params<span class="op">[</span><span class="dv">1</span><span class="op">];</span></span>
<span id="cb14-29"><a href="#cb14-29"></a></span> <span id="cb12-29"><a href="#cb12-29"></a></span>
<span id="cb14-30"><a href="#cb14-30"></a> <span class="co">/* Builds a window with exp.ui resource */</span></span> <span id="cb12-30"><a href="#cb12-30"></a> <span class="co">/* Builds a window with exp.ui resource */</span></span>
<span id="cb14-31"><a href="#cb14-31"></a> build <span class="op">=</span> gtk_builder_new_from_file <span class="op">(</span><span class="st">&quot;exp_bind.ui&quot;</span><span class="op">);</span></span> <span id="cb12-31"><a href="#cb12-31"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">&quot;/com/github/ToshioCP/exp/exp_bind.ui&quot;</span><span class="op">);</span></span>
<span id="cb14-32"><a href="#cb14-32"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;win&quot;</span><span class="op">));</span></span> <span id="cb12-32"><a href="#cb12-32"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;win&quot;</span><span class="op">));</span></span>
<span id="cb14-33"><a href="#cb14-33"></a> label <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;label&quot;</span><span class="op">));</span></span> <span id="cb12-33"><a href="#cb12-33"></a> label <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;label&quot;</span><span class="op">));</span></span>
<span id="cb14-34"><a href="#cb14-34"></a> <span class="co">// scale = GTK_WIDGET (gtk_builder_get_object (build, &quot;scale&quot;));</span></span> <span id="cb12-34"><a href="#cb12-34"></a> <span class="co">// scale = GTK_WIDGET (gtk_builder_get_object (build, &quot;scale&quot;));</span></span>
<span id="cb14-35"><a href="#cb14-35"></a> adjustment <span class="op">=</span> GTK_ADJUSTMENT <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;adjustment&quot;</span><span class="op">));</span></span> <span id="cb12-35"><a href="#cb12-35"></a> adjustment <span class="op">=</span> GTK_ADJUSTMENT <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;adjustment&quot;</span><span class="op">));</span></span>
<span id="cb14-36"><a href="#cb14-36"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> app<span class="op">);</span></span> <span id="cb12-36"><a href="#cb12-36"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> app<span class="op">);</span></span>
<span id="cb14-37"><a href="#cb14-37"></a> g_signal_connect <span class="op">(</span>win<span class="op">,</span> <span class="st">&quot;close-request&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>close_request_cb<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb12-37"><a href="#cb12-37"></a> g_signal_connect <span class="op">(</span>win<span class="op">,</span> <span class="st">&quot;close-request&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>close_request_cb<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb14-38"><a href="#cb14-38"></a> g_object_unref <span class="op">(</span>build<span class="op">);</span></span> <span id="cb12-38"><a href="#cb12-38"></a> g_object_unref <span class="op">(</span>build<span class="op">);</span></span>
<span id="cb14-39"><a href="#cb14-39"></a></span> <span id="cb12-39"><a href="#cb12-39"></a></span>
<span id="cb14-40"><a href="#cb14-40"></a> <span class="co">/* GtkExpressionWatch */</span></span> <span id="cb12-40"><a href="#cb12-40"></a> <span class="co">/* GtkExpressionWatch */</span></span>
<span id="cb14-41"><a href="#cb14-41"></a> params<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_ADJUSTMENT<span class="op">,</span> NULL<span class="op">,</span> <span class="st">&quot;value&quot;</span><span class="op">);</span></span> <span id="cb12-41"><a href="#cb12-41"></a> params<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_ADJUSTMENT<span class="op">,</span> NULL<span class="op">,</span> <span class="st">&quot;value&quot;</span><span class="op">);</span></span>
<span id="cb14-42"><a href="#cb14-42"></a> expression <span class="op">=</span> gtk_cclosure_expression_new <span class="op">(</span>G_TYPE_INT<span class="op">,</span> NULL<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> params<span class="op">,</span> G_CALLBACK <span class="op">(</span>f2i<span class="op">),</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span> <span id="cb12-42"><a href="#cb12-42"></a> expression <span class="op">=</span> gtk_cclosure_expression_new <span class="op">(</span>G_TYPE_INT<span class="op">,</span> NULL<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> params<span class="op">,</span> G_CALLBACK <span class="op">(</span>f2i<span class="op">),</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb14-43"><a href="#cb14-43"></a> watch <span class="op">=</span> gtk_expression_bind <span class="op">(</span>expression<span class="op">,</span> label<span class="op">,</span> <span class="st">&quot;label&quot;</span><span class="op">,</span> adjustment<span class="op">);</span> <span class="co">/* watch takes the ownership of the expression. */</span></span> <span id="cb12-43"><a href="#cb12-43"></a> watch <span class="op">=</span> gtk_expression_bind <span class="op">(</span>expression<span class="op">,</span> label<span class="op">,</span> <span class="st">&quot;label&quot;</span><span class="op">,</span> adjustment<span class="op">);</span> <span class="co">/* watch takes the ownership of the expression. */</span></span>
<span id="cb14-44"><a href="#cb14-44"></a><span class="op">}</span></span> <span id="cb12-44"><a href="#cb12-44"></a><span class="op">}</span></span>
<span id="cb14-45"><a href="#cb14-45"></a></span> <span id="cb12-45"><a href="#cb12-45"></a></span>
<span id="cb14-46"><a href="#cb14-46"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.exp_watch&quot;</span></span> <span id="cb12-46"><a href="#cb12-46"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.exp_watch&quot;</span></span>
<span id="cb14-47"><a href="#cb14-47"></a></span> <span id="cb12-47"><a href="#cb12-47"></a></span>
<span id="cb14-48"><a href="#cb14-48"></a><span class="dt">int</span></span> <span id="cb12-48"><a href="#cb12-48"></a><span class="dt">int</span></span>
<span id="cb14-49"><a href="#cb14-49"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span> <span id="cb12-49"><a href="#cb12-49"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-50"><a href="#cb14-50"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span> <span id="cb12-50"><a href="#cb12-50"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb14-51"><a href="#cb14-51"></a> <span class="dt">int</span> stat<span class="op">;</span></span> <span id="cb12-51"><a href="#cb12-51"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb14-52"><a href="#cb14-52"></a></span> <span id="cb12-52"><a href="#cb12-52"></a></span>
<span id="cb14-53"><a href="#cb14-53"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_DEFAULT_FLAGS<span class="op">);</span></span> <span id="cb12-53"><a href="#cb12-53"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_DEFAULT_FLAGS<span class="op">);</span></span>
<span id="cb14-54"><a href="#cb14-54"></a></span> <span id="cb12-54"><a href="#cb12-54"></a></span>
<span id="cb14-55"><a href="#cb14-55"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;startup&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb12-55"><a href="#cb12-55"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;startup&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb14-56"><a href="#cb14-56"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb12-56"><a href="#cb12-56"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb14-57"><a href="#cb14-57"></a></span> <span id="cb12-57"><a href="#cb12-57"></a></span>
<span id="cb14-58"><a href="#cb14-58"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span> <span id="cb12-58"><a href="#cb12-58"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span>
<span id="cb14-59"><a href="#cb14-59"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span> <span id="cb12-59"><a href="#cb12-59"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb14-60"><a href="#cb14-60"></a> <span class="cf">return</span> stat<span class="op">;</span></span> <span id="cb12-60"><a href="#cb12-60"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb14-61"><a href="#cb14-61"></a><span class="op">}</span></span></code></pre></div> <span id="cb12-61"><a href="#cb12-61"></a><span class="op">}</span></span></code></pre></div>
<p>The point of the program is:</p> <p>The point of the program is:</p>
<ul> <ul>
<li>41-42: Two expressions are defined. One is a property expression and <li>41-42: Two expressions are defined. One is a property expression and
the other is a closure expression. The property expression look up the the other is a closure expression. The property expression looks up the
“value”property of the adjustment instance. The closure expression just “value” property of the adjustment instance. The closure expression just
converts the double into an integer.</li> converts the double into an integer.</li>
<li>43: <code>gtk_expression_bind</code> binds the label property of the <li>43: <code>gtk_expression_bind</code> binds the label property of the
GtkLabel instance to the integer returned by the closure expression. It GtkLabel instance to the integer returned by the closure expression. It
@ -603,24 +570,23 @@ is destroyed.</li>
<code>close_request_cb</code>. This signal is emitted when the close <code>close_request_cb</code>. This signal is emitted when the close
button is clicked. The handler is called just before the window closes. button is clicked. The handler is called just before the window closes.
It is the right moment to make the GtkExpressionWatch unwatched.</li> It is the right moment to make the GtkExpressionWatch unwatched.</li>
<li>10-14: “close-request” signal handler. <li>10-14: “close-request” signal handler. The function
<code>gtk_expression_watch_unwatch (watch)</code> makes the watch stop <code>gtk_expression_watch_unwatch (watch)</code> makes the watch stop
watching the expression. It releases the expression and calls watching the expression. It also releases the expression.</li>
<code>gtk_expression_watch_unref (watch)</code> in it.</li>
</ul> </ul>
<p>If you want to bind a property to an expression, <p>If you want to bind a property to an expression,
<code>gtk_expression_bind</code> is the best choice. You can do it with <code>gtk_expression_bind</code> is the best choice. You can do it with
<code>gtk_expression_watch</code> function, but it is less suitable.</p> <code>gtk_expression_watch</code> function, but it is less suitable.</p>
<h3 id="gtk_expression_watch-function">gtk_expression_watch <h3 id="gtk_expression_watch-function">gtk_expression_watch
function</h3> function</h3>
<div class="sourceCode" id="cb15"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>GtkExpressionWatch<span class="op">*</span></span> <div class="sourceCode" id="cb13"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>GtkExpressionWatch<span class="op">*</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>gtk_expression_watch <span class="op">(</span></span> <span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>gtk_expression_watch <span class="op">(</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a> GtkExpression<span class="op">*</span> self<span class="op">,</span></span> <span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a> GtkExpression<span class="op">*</span> self<span class="op">,</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> this_<span class="op">,</span></span> <span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> this_<span class="op">,</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a> GtkExpressionNotify notify<span class="op">,</span></span> <span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a> GtkExpressionNotify notify<span class="op">,</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a> gpointer user_data<span class="op">,</span></span> <span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a> gpointer user_data<span class="op">,</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a> GDestroyNotify user_destroy</span> <span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a> GDestroyNotify user_destroy</span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div> <span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div>
<p>The function doesnt take the ownership of the expression. It differs <p>The function doesnt take the ownership of the expression. It differs
from <code>gtk_expression_bind</code>. So, you need to release the from <code>gtk_expression_bind</code>. So, you need to release the
expression when it is useless. It creates a GtkExpressionWatch expression when it is useless. It creates a GtkExpressionWatch
@ -630,10 +596,10 @@ to give it to the callback. The last parameter is a function to destroy
the <code>user_data</code> when the watch is unwatched. Put NULL if you the <code>user_data</code> when the watch is unwatched. Put NULL if you
dont need them.</p> dont need them.</p>
<p>Notify callback has the following format.</p> <p>Notify callback has the following format.</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span> <div class="sourceCode" id="cb14"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>notify <span class="op">(</span></span> <span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>notify <span class="op">(</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a> gpointer user_data</span> <span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> gpointer user_data</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div> <span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div>
<p>This function is used to do something when the value of the <p>This function is used to do something when the value of the
expression changes. But if you want to bind a property to the value, use expression changes. But if you want to bind a property to the value, use
<code>gtk_expression_bind</code> instead.</p> <code>gtk_expression_bind</code> instead.</p>
@ -646,63 +612,63 @@ window to the standard output.</p>
</figure> </figure>
<p>When you resize the window, the width is displayed in the <p>When you resize the window, the width is displayed in the
terminal.</p> terminal.</p>
<div class="sourceCode" id="cb17"><pre <div class="sourceCode" id="cb15"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb17-1"><a href="#cb17-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span> class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb15-1"><a href="#cb15-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb17-2"><a href="#cb17-2"></a></span> <span id="cb15-2"><a href="#cb15-2"></a></span>
<span id="cb17-3"><a href="#cb17-3"></a>GtkExpression <span class="op">*</span>expression<span class="op">;</span></span> <span id="cb15-3"><a href="#cb15-3"></a>GtkExpression <span class="op">*</span>expression<span class="op">;</span></span>
<span id="cb17-4"><a href="#cb17-4"></a>GtkExpressionWatch <span class="op">*</span>watch<span class="op">;</span></span> <span id="cb15-4"><a href="#cb15-4"></a>GtkExpressionWatch <span class="op">*</span>watch<span class="op">;</span></span>
<span id="cb17-5"><a href="#cb17-5"></a></span> <span id="cb15-5"><a href="#cb15-5"></a></span>
<span id="cb17-6"><a href="#cb17-6"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb15-6"><a href="#cb15-6"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb17-7"><a href="#cb17-7"></a>notify <span class="op">(</span>gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb15-7"><a href="#cb15-7"></a>notify <span class="op">(</span>gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-8"><a href="#cb17-8"></a> GValue value <span class="op">=</span> G_VALUE_INIT<span class="op">;</span></span> <span id="cb15-8"><a href="#cb15-8"></a> GValue value <span class="op">=</span> G_VALUE_INIT<span class="op">;</span></span>
<span id="cb17-9"><a href="#cb17-9"></a></span> <span id="cb15-9"><a href="#cb15-9"></a></span>
<span id="cb17-10"><a href="#cb17-10"></a> <span class="cf">if</span> <span class="op">(</span>gtk_expression_watch_evaluate <span class="op">(</span>watch<span class="op">,</span> <span class="op">&amp;</span>value<span class="op">))</span></span> <span id="cb15-10"><a href="#cb15-10"></a> <span class="cf">if</span> <span class="op">(</span>gtk_expression_watch_evaluate <span class="op">(</span>watch<span class="op">,</span> <span class="op">&amp;</span>value<span class="op">))</span></span>
<span id="cb17-11"><a href="#cb17-11"></a> g_print <span class="op">(</span><span class="st">&quot;width = %d</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">,</span> g_value_get_int <span class="op">(&amp;</span>value<span class="op">));</span></span> <span id="cb15-11"><a href="#cb15-11"></a> g_print <span class="op">(</span><span class="st">&quot;width = %d</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">,</span> g_value_get_int <span class="op">(&amp;</span>value<span class="op">));</span></span>
<span id="cb17-12"><a href="#cb17-12"></a> <span class="cf">else</span></span> <span id="cb15-12"><a href="#cb15-12"></a> <span class="cf">else</span></span>
<span id="cb17-13"><a href="#cb17-13"></a> g_print <span class="op">(</span><span class="st">&quot;evaluation failed.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span> <span id="cb15-13"><a href="#cb15-13"></a> g_print <span class="op">(</span><span class="st">&quot;evaluation failed.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span>
<span id="cb17-14"><a href="#cb17-14"></a><span class="op">}</span></span> <span id="cb15-14"><a href="#cb15-14"></a><span class="op">}</span></span>
<span id="cb17-15"><a href="#cb17-15"></a></span> <span id="cb15-15"><a href="#cb15-15"></a></span>
<span id="cb17-16"><a href="#cb17-16"></a><span class="dt">static</span> <span class="dt">int</span></span> <span id="cb15-16"><a href="#cb15-16"></a><span class="dt">static</span> <span class="dt">int</span></span>
<span id="cb17-17"><a href="#cb17-17"></a>close_request_cb <span class="op">(</span>GtkWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span> <span id="cb15-17"><a href="#cb15-17"></a>close_request_cb <span class="op">(</span>GtkWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-18"><a href="#cb17-18"></a> gtk_expression_watch_unwatch <span class="op">(</span>watch<span class="op">);</span></span> <span id="cb15-18"><a href="#cb15-18"></a> gtk_expression_watch_unwatch <span class="op">(</span>watch<span class="op">);</span></span>
<span id="cb17-19"><a href="#cb17-19"></a> gtk_expression_unref <span class="op">(</span>expression<span class="op">);</span></span> <span id="cb15-19"><a href="#cb15-19"></a> gtk_expression_unref <span class="op">(</span>expression<span class="op">);</span></span>
<span id="cb17-20"><a href="#cb17-20"></a> <span class="cf">return</span> false<span class="op">;</span></span> <span id="cb15-20"><a href="#cb15-20"></a> <span class="cf">return</span> false<span class="op">;</span></span>
<span id="cb17-21"><a href="#cb17-21"></a><span class="op">}</span></span> <span id="cb15-21"><a href="#cb15-21"></a><span class="op">}</span></span>
<span id="cb17-22"><a href="#cb17-22"></a></span> <span id="cb15-22"><a href="#cb15-22"></a></span>
<span id="cb17-23"><a href="#cb17-23"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb15-23"><a href="#cb15-23"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb17-24"><a href="#cb17-24"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span> <span id="cb15-24"><a href="#cb15-24"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-25"><a href="#cb17-25"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span> <span id="cb15-25"><a href="#cb15-25"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
<span id="cb17-26"><a href="#cb17-26"></a> gtk_window_present <span class="op">(</span>gtk_application_get_active_window<span class="op">(</span>app<span class="op">));</span></span> <span id="cb15-26"><a href="#cb15-26"></a> gtk_window_present <span class="op">(</span>gtk_application_get_active_window<span class="op">(</span>app<span class="op">));</span></span>
<span id="cb17-27"><a href="#cb17-27"></a><span class="op">}</span></span> <span id="cb15-27"><a href="#cb15-27"></a><span class="op">}</span></span>
<span id="cb17-28"><a href="#cb17-28"></a></span> <span id="cb15-28"><a href="#cb15-28"></a></span>
<span id="cb17-29"><a href="#cb17-29"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb15-29"><a href="#cb15-29"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb17-30"><a href="#cb17-30"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span> <span id="cb15-30"><a href="#cb15-30"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-31"><a href="#cb17-31"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span> <span id="cb15-31"><a href="#cb15-31"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
<span id="cb17-32"><a href="#cb17-32"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span> <span id="cb15-32"><a href="#cb15-32"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
<span id="cb17-33"><a href="#cb17-33"></a></span> <span id="cb15-33"><a href="#cb15-33"></a></span>
<span id="cb17-34"><a href="#cb17-34"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_application_window_new <span class="op">(</span>app<span class="op">));</span></span> <span id="cb15-34"><a href="#cb15-34"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_application_window_new <span class="op">(</span>app<span class="op">));</span></span>
<span id="cb17-35"><a href="#cb17-35"></a> g_signal_connect <span class="op">(</span>win<span class="op">,</span> <span class="st">&quot;close-request&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>close_request_cb<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb15-35"><a href="#cb15-35"></a> g_signal_connect <span class="op">(</span>win<span class="op">,</span> <span class="st">&quot;close-request&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>close_request_cb<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb17-36"><a href="#cb17-36"></a></span> <span id="cb15-36"><a href="#cb15-36"></a></span>
<span id="cb17-37"><a href="#cb17-37"></a> expression <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_WINDOW<span class="op">,</span> NULL<span class="op">,</span> <span class="st">&quot;default-width&quot;</span><span class="op">);</span></span> <span id="cb15-37"><a href="#cb15-37"></a> expression <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_WINDOW<span class="op">,</span> NULL<span class="op">,</span> <span class="st">&quot;default-width&quot;</span><span class="op">);</span></span>
<span id="cb17-38"><a href="#cb17-38"></a> watch <span class="op">=</span> gtk_expression_watch <span class="op">(</span>expression<span class="op">,</span> win<span class="op">,</span> notify<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span> <span id="cb15-38"><a href="#cb15-38"></a> watch <span class="op">=</span> gtk_expression_watch <span class="op">(</span>expression<span class="op">,</span> win<span class="op">,</span> notify<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb17-39"><a href="#cb17-39"></a><span class="op">}</span></span> <span id="cb15-39"><a href="#cb15-39"></a><span class="op">}</span></span>
<span id="cb17-40"><a href="#cb17-40"></a></span> <span id="cb15-40"><a href="#cb15-40"></a></span>
<span id="cb17-41"><a href="#cb17-41"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.exp_watch&quot;</span></span> <span id="cb15-41"><a href="#cb15-41"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.exp_watch&quot;</span></span>
<span id="cb17-42"><a href="#cb17-42"></a></span> <span id="cb15-42"><a href="#cb15-42"></a></span>
<span id="cb17-43"><a href="#cb17-43"></a><span class="dt">int</span></span> <span id="cb15-43"><a href="#cb15-43"></a><span class="dt">int</span></span>
<span id="cb17-44"><a href="#cb17-44"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span> <span id="cb15-44"><a href="#cb15-44"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-45"><a href="#cb17-45"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span> <span id="cb15-45"><a href="#cb15-45"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb17-46"><a href="#cb17-46"></a> <span class="dt">int</span> stat<span class="op">;</span></span> <span id="cb15-46"><a href="#cb15-46"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb17-47"><a href="#cb17-47"></a></span> <span id="cb15-47"><a href="#cb15-47"></a></span>
<span id="cb17-48"><a href="#cb17-48"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_DEFAULT_FLAGS<span class="op">);</span></span> <span id="cb15-48"><a href="#cb15-48"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_DEFAULT_FLAGS<span class="op">);</span></span>
<span id="cb17-49"><a href="#cb17-49"></a></span> <span id="cb15-49"><a href="#cb15-49"></a></span>
<span id="cb17-50"><a href="#cb17-50"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;startup&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb15-50"><a href="#cb15-50"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;startup&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb17-51"><a href="#cb17-51"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb15-51"><a href="#cb15-51"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb17-52"><a href="#cb17-52"></a></span> <span id="cb15-52"><a href="#cb15-52"></a></span>
<span id="cb17-53"><a href="#cb17-53"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span> <span id="cb15-53"><a href="#cb15-53"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span>
<span id="cb17-54"><a href="#cb17-54"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span> <span id="cb15-54"><a href="#cb15-54"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb17-55"><a href="#cb17-55"></a> <span class="cf">return</span> stat<span class="op">;</span></span> <span id="cb15-55"><a href="#cb15-55"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb17-56"><a href="#cb17-56"></a><span class="op">}</span></span></code></pre></div> <span id="cb15-56"><a href="#cb15-56"></a><span class="op">}</span></span></code></pre></div>
<ul> <ul>
<li>37: A property expression looks up the “default-width” property of <li>37: A property expression looks up the “default-width” property of
the window.</li> the window.</li>
@ -738,37 +704,36 @@ expressions.</li>
content of an object tag. Name attribute specifies the property name of content of an object tag. Name attribute specifies the property name of
the object. The content is an expression.</li> the object. The content is an expression.</li>
</ul> </ul>
<div class="sourceCode" id="cb18"><pre <div class="sourceCode" id="cb16"><pre
class="sourceCode xml"><code class="sourceCode xml"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">constant</span><span class="ot"> type=</span><span class="st">&quot;gchararray&quot;</span>&gt;Hello world&lt;/<span class="kw">constant</span>&gt;</span> class="sourceCode xml"><code class="sourceCode xml"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">constant</span><span class="ot"> type=</span><span class="st">&quot;gchararray&quot;</span>&gt;Hello world&lt;/<span class="kw">constant</span>&gt;</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span><span class="ot"> type=</span><span class="st">&quot;GtkLabel&quot;</span>&gt;label&lt;/<span class="kw">lookup</span>&gt;</span> <span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span><span class="ot"> type=</span><span class="st">&quot;GtkLabel&quot;</span>&gt;label&lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">closure</span><span class="ot"> type=</span><span class="st">&quot;gint&quot;</span><span class="ot"> function=</span><span class="st">&quot;callback_function&quot;</span>&gt;&lt;/<span class="kw">closure</span>&gt;</span> <span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">closure</span><span class="ot"> type=</span><span class="st">&quot;gint&quot;</span><span class="ot"> function=</span><span class="st">&quot;callback_function&quot;</span>&gt;&lt;/<span class="kw">closure</span>&gt;</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">bind</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;</span> <span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">bind</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span>&gt;win&lt;/<span class="kw">lookup</span>&gt;</span> <span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span>&gt;win&lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>&lt;/<span class="kw">bind</span>&gt;</span></code></pre></div> <span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>&lt;/<span class="kw">bind</span>&gt;</span></code></pre></div>
<p>These tags are usually used for GtkBuilderListItemFactory.</p> <p>These tags are usually used for GtkBuilderListItemFactory.</p>
<div class="sourceCode" id="cb19"><pre <div class="sourceCode" id="cb17"><pre
class="sourceCode xml"><code class="sourceCode xml"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">interface</span>&gt;</span> class="sourceCode xml"><code class="sourceCode xml"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">interface</span>&gt;</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">template</span><span class="ot"> class=</span><span class="st">&quot;GtkListItem&quot;</span>&gt;</span> <span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">template</span><span class="ot"> class=</span><span class="st">&quot;GtkListItem&quot;</span>&gt;</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;child&quot;</span>&gt;</span> <span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;child&quot;</span>&gt;</span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span>&gt;</span> <span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span>&gt;</span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">binding</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;</span> <span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">binding</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;</span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;name&quot;</span><span class="ot"> type=</span><span class="st">&quot;string&quot;</span>&gt;</span> <span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;string&quot;</span><span class="ot"> type=</span><span class="st">&quot;GtkStringObject&quot;</span>&gt;</span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;item&quot;</span>&gt;GtkListItem&lt;/<span class="kw">lookup</span>&gt;</span> <span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;item&quot;</span>&gt;GtkListItem&lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">lookup</span>&gt;</span> <span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">binding</span>&gt;</span> <span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">binding</span>&gt;</span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">object</span>&gt;</span> <span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">property</span>&gt;</span> <span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">property</span>&gt;</span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">template</span>&gt;</span> <span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">template</span>&gt;</span>
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a>&lt;/<span class="kw">interface</span>&gt;</span></code></pre></div> <span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a>&lt;/<span class="kw">interface</span>&gt;</span></code></pre></div>
<p>GtkBuilderListItemFactory uses GtkBuilder to extends the GtkListItem
with the XML data.</p>
<p>In the xml file above, “GtkListItem” is an instance of the <p>In the xml file above, “GtkListItem” is an instance of the
GtkListItem template. It is the this object given to the expressions. GtkListItem template. It is the this object given to the expressions.
(The information is in the <a href="https://blog.gtk.org/2020/09/">GTK (The information is in the <a href="https://blog.gtk.org/2020/09/">GTK
Development Blog</a>).</p> Development Blog</a>).</p>
<p>GtkBuilderListItemFactory uses GtkBuilder to build the XML data. It <p>GtkBuilder calls <code>gtk_expression_bind</code> function when it
sets the current object of the GtkBuilder to the GtkListItem finds a binding tag. The function sets the this object like this:</p>
instance.</p>
<p>GtkBuilder calls <code>gtk_expression_bind</code> function in the
binding tag analysis. The function sets the this object like this:</p>
<ol type="1"> <ol type="1">
<li>If the binding tag has object attribute, the object will be the <li>If the binding tag has object attribute, the object will be the
this object.</li> this object.</li>
@ -794,41 +759,41 @@ constant tags are not used so often.</p>
window. If you type characters in the entry, the same characters appear window. If you type characters in the entry, the same characters appear
on the label.</p> on the label.</p>
<p>The ui file is as follows.</p> <p>The ui file is as follows.</p>
<div class="sourceCode" id="cb20"><pre <div class="sourceCode" id="cb18"><pre
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb20-1"><a href="#cb20-1"></a><span class="fu">&lt;?xml</span><span class="ot"> version=</span><span class="st">&quot;1.0&quot;</span><span class="ot"> encoding=</span><span class="st">&quot;UTF-8&quot;</span><span class="fu">?&gt;</span></span> class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb18-1"><a href="#cb18-1"></a><span class="fu">&lt;?xml</span><span class="ot"> version=</span><span class="st">&quot;1.0&quot;</span><span class="ot"> encoding=</span><span class="st">&quot;UTF-8&quot;</span><span class="fu">?&gt;</span></span>
<span id="cb20-2"><a href="#cb20-2"></a>&lt;<span class="kw">interface</span>&gt;</span> <span id="cb18-2"><a href="#cb18-2"></a>&lt;<span class="kw">interface</span>&gt;</span>
<span id="cb20-3"><a href="#cb20-3"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkApplicationWindow&quot;</span><span class="ot"> id=</span><span class="st">&quot;win&quot;</span>&gt;</span> <span id="cb18-3"><a href="#cb18-3"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkApplicationWindow&quot;</span><span class="ot"> id=</span><span class="st">&quot;win&quot;</span>&gt;</span>
<span id="cb20-4"><a href="#cb20-4"></a> &lt;<span class="kw">binding</span><span class="ot"> name=</span><span class="st">&quot;title&quot;</span>&gt;</span> <span id="cb18-4"><a href="#cb18-4"></a> &lt;<span class="kw">binding</span><span class="ot"> name=</span><span class="st">&quot;title&quot;</span>&gt;</span>
<span id="cb20-5"><a href="#cb20-5"></a> &lt;<span class="kw">closure</span><span class="ot"> type=</span><span class="st">&quot;gchararray&quot;</span><span class="ot"> function=</span><span class="st">&quot;set_title&quot;</span>&gt;</span> <span id="cb18-5"><a href="#cb18-5"></a> &lt;<span class="kw">closure</span><span class="ot"> type=</span><span class="st">&quot;gchararray&quot;</span><span class="ot"> function=</span><span class="st">&quot;set_title&quot;</span>&gt;</span>
<span id="cb20-6"><a href="#cb20-6"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span><span class="ot"> type=</span><span class="st">&quot;GtkWindow&quot;</span>&gt;&lt;/<span class="kw">lookup</span>&gt;</span> <span id="cb18-6"><a href="#cb18-6"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span><span class="ot"> type=</span><span class="st">&quot;GtkWindow&quot;</span>&gt;&lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb20-7"><a href="#cb20-7"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;default-height&quot;</span><span class="ot"> type=</span><span class="st">&quot;GtkWindow&quot;</span>&gt;&lt;/<span class="kw">lookup</span>&gt;</span> <span id="cb18-7"><a href="#cb18-7"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;default-height&quot;</span><span class="ot"> type=</span><span class="st">&quot;GtkWindow&quot;</span>&gt;&lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb20-8"><a href="#cb20-8"></a> &lt;/<span class="kw">closure</span>&gt;</span> <span id="cb18-8"><a href="#cb18-8"></a> &lt;/<span class="kw">closure</span>&gt;</span>
<span id="cb20-9"><a href="#cb20-9"></a> &lt;/<span class="kw">binding</span>&gt;</span> <span id="cb18-9"><a href="#cb18-9"></a> &lt;/<span class="kw">binding</span>&gt;</span>
<span id="cb20-10"><a href="#cb20-10"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span>&gt;600&lt;/<span class="kw">property</span>&gt;</span> <span id="cb18-10"><a href="#cb18-10"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span>&gt;600&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb20-11"><a href="#cb20-11"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;default-height&quot;</span>&gt;400&lt;/<span class="kw">property</span>&gt;</span> <span id="cb18-11"><a href="#cb18-11"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;default-height&quot;</span>&gt;400&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb20-12"><a href="#cb20-12"></a> &lt;<span class="kw">child</span>&gt;</span> <span id="cb18-12"><a href="#cb18-12"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb20-13"><a href="#cb20-13"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkBox&quot;</span>&gt;</span> <span id="cb18-13"><a href="#cb18-13"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkBox&quot;</span>&gt;</span>
<span id="cb20-14"><a href="#cb20-14"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;orientation&quot;</span>&gt;GTK_ORIENTATION_VERTICAL&lt;/<span class="kw">property</span>&gt;</span> <span id="cb18-14"><a href="#cb18-14"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;orientation&quot;</span>&gt;GTK_ORIENTATION_VERTICAL&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb20-15"><a href="#cb20-15"></a> &lt;<span class="kw">child</span>&gt;</span> <span id="cb18-15"><a href="#cb18-15"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb20-16"><a href="#cb20-16"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span>&gt;</span> <span id="cb18-16"><a href="#cb18-16"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span>&gt;</span>
<span id="cb20-17"><a href="#cb20-17"></a> &lt;<span class="kw">binding</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;</span> <span id="cb18-17"><a href="#cb18-17"></a> &lt;<span class="kw">binding</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;</span>
<span id="cb20-18"><a href="#cb20-18"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;text&quot;</span>&gt;</span> <span id="cb18-18"><a href="#cb18-18"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;text&quot;</span>&gt;</span>
<span id="cb20-19"><a href="#cb20-19"></a> buffer</span> <span id="cb18-19"><a href="#cb18-19"></a> buffer</span>
<span id="cb20-20"><a href="#cb20-20"></a> &lt;/<span class="kw">lookup</span>&gt;</span> <span id="cb18-20"><a href="#cb18-20"></a> &lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb20-21"><a href="#cb20-21"></a> &lt;/<span class="kw">binding</span>&gt;</span> <span id="cb18-21"><a href="#cb18-21"></a> &lt;/<span class="kw">binding</span>&gt;</span>
<span id="cb20-22"><a href="#cb20-22"></a> &lt;/<span class="kw">object</span>&gt;</span> <span id="cb18-22"><a href="#cb18-22"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb20-23"><a href="#cb20-23"></a> &lt;/<span class="kw">child</span>&gt;</span> <span id="cb18-23"><a href="#cb18-23"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb20-24"><a href="#cb20-24"></a> &lt;<span class="kw">child</span>&gt;</span> <span id="cb18-24"><a href="#cb18-24"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb20-25"><a href="#cb20-25"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkEntry&quot;</span>&gt;</span> <span id="cb18-25"><a href="#cb18-25"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkEntry&quot;</span>&gt;</span>
<span id="cb20-26"><a href="#cb20-26"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;buffer&quot;</span>&gt;</span> <span id="cb18-26"><a href="#cb18-26"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;buffer&quot;</span>&gt;</span>
<span id="cb20-27"><a href="#cb20-27"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkEntryBuffer&quot;</span><span class="ot"> id=</span><span class="st">&quot;buffer&quot;</span>&gt;&lt;/<span class="kw">object</span>&gt;</span> <span id="cb18-27"><a href="#cb18-27"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkEntryBuffer&quot;</span><span class="ot"> id=</span><span class="st">&quot;buffer&quot;</span>&gt;&lt;/<span class="kw">object</span>&gt;</span>
<span id="cb20-28"><a href="#cb20-28"></a> &lt;/<span class="kw">property</span>&gt;</span> <span id="cb18-28"><a href="#cb18-28"></a> &lt;/<span class="kw">property</span>&gt;</span>
<span id="cb20-29"><a href="#cb20-29"></a> &lt;/<span class="kw">object</span>&gt;</span> <span id="cb18-29"><a href="#cb18-29"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb20-30"><a href="#cb20-30"></a> &lt;/<span class="kw">child</span>&gt;</span> <span id="cb18-30"><a href="#cb18-30"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb20-31"><a href="#cb20-31"></a> &lt;/<span class="kw">object</span>&gt;</span> <span id="cb18-31"><a href="#cb18-31"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb20-32"><a href="#cb20-32"></a> &lt;/<span class="kw">child</span>&gt;</span> <span id="cb18-32"><a href="#cb18-32"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb20-33"><a href="#cb20-33"></a> &lt;/<span class="kw">object</span>&gt;</span> <span id="cb18-33"><a href="#cb18-33"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb20-34"><a href="#cb20-34"></a>&lt;/<span class="kw">interface</span>&gt;</span></code></pre></div> <span id="cb18-34"><a href="#cb18-34"></a>&lt;/<span class="kw">interface</span>&gt;</span></code></pre></div>
<ul> <ul>
<li>4-9: The title property of the main window is bound to a closure <li>4-9: The title property of the main window is bound to a closure
expression. Its callback function <code>set_title</code> is defined in expression. Its callback function <code>set_title</code> is defined in
@ -844,48 +809,48 @@ defined in line 25. If a user types characters in the entry, the same
characters appear on the label.</li> characters appear on the label.</li>
</ul> </ul>
<p>The C source file is as follows.</p> <p>The C source file is as follows.</p>
<div class="sourceCode" id="cb21"><pre <div class="sourceCode" id="cb19"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb21-1"><a href="#cb21-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span> class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb19-1"><a href="#cb19-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb21-2"><a href="#cb21-2"></a></span> <span id="cb19-2"><a href="#cb19-2"></a></span>
<span id="cb21-3"><a href="#cb21-3"></a><span class="dt">char</span> <span class="op">*</span></span> <span id="cb19-3"><a href="#cb19-3"></a><span class="dt">char</span> <span class="op">*</span></span>
<span id="cb21-4"><a href="#cb21-4"></a>set_title <span class="op">(</span>GtkWidget <span class="op">*</span>win<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">)</span> <span class="op">{</span></span> <span id="cb19-4"><a href="#cb19-4"></a>set_title <span class="op">(</span>GtkWidget <span class="op">*</span>win<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">)</span> <span class="op">{</span></span>
<span id="cb21-5"><a href="#cb21-5"></a> <span class="cf">return</span> g_strdup_printf <span class="op">(</span><span class="st">&quot;%d x %d&quot;</span><span class="op">,</span> width<span class="op">,</span> height<span class="op">);</span></span> <span id="cb19-5"><a href="#cb19-5"></a> <span class="cf">return</span> g_strdup_printf <span class="op">(</span><span class="st">&quot;%d x %d&quot;</span><span class="op">,</span> width<span class="op">,</span> height<span class="op">);</span></span>
<span id="cb21-6"><a href="#cb21-6"></a><span class="op">}</span></span> <span id="cb19-6"><a href="#cb19-6"></a><span class="op">}</span></span>
<span id="cb21-7"><a href="#cb21-7"></a></span> <span id="cb19-7"><a href="#cb19-7"></a></span>
<span id="cb21-8"><a href="#cb21-8"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb19-8"><a href="#cb19-8"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb21-9"><a href="#cb21-9"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span> <span id="cb19-9"><a href="#cb19-9"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb21-10"><a href="#cb21-10"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span> <span id="cb19-10"><a href="#cb19-10"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
<span id="cb21-11"><a href="#cb21-11"></a> gtk_window_present <span class="op">(</span>gtk_application_get_active_window<span class="op">(</span>app<span class="op">));</span></span> <span id="cb19-11"><a href="#cb19-11"></a> gtk_window_present <span class="op">(</span>gtk_application_get_active_window<span class="op">(</span>app<span class="op">));</span></span>
<span id="cb21-12"><a href="#cb21-12"></a><span class="op">}</span></span> <span id="cb19-12"><a href="#cb19-12"></a><span class="op">}</span></span>
<span id="cb21-13"><a href="#cb21-13"></a></span> <span id="cb19-13"><a href="#cb19-13"></a></span>
<span id="cb21-14"><a href="#cb21-14"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb19-14"><a href="#cb19-14"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb21-15"><a href="#cb21-15"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span> <span id="cb19-15"><a href="#cb19-15"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb21-16"><a href="#cb21-16"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span> <span id="cb19-16"><a href="#cb19-16"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
<span id="cb21-17"><a href="#cb21-17"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span> <span id="cb19-17"><a href="#cb19-17"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
<span id="cb21-18"><a href="#cb21-18"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span> <span id="cb19-18"><a href="#cb19-18"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
<span id="cb21-19"><a href="#cb21-19"></a></span> <span id="cb19-19"><a href="#cb19-19"></a></span>
<span id="cb21-20"><a href="#cb21-20"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">&quot;/com/github/ToshioCP/exp/exp.ui&quot;</span><span class="op">);</span></span> <span id="cb19-20"><a href="#cb19-20"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">&quot;/com/github/ToshioCP/exp/exp.ui&quot;</span><span class="op">);</span></span>
<span id="cb21-21"><a href="#cb21-21"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;win&quot;</span><span class="op">));</span></span> <span id="cb19-21"><a href="#cb19-21"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;win&quot;</span><span class="op">));</span></span>
<span id="cb21-22"><a href="#cb21-22"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> app<span class="op">);</span></span> <span id="cb19-22"><a href="#cb19-22"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> app<span class="op">);</span></span>
<span id="cb21-23"><a href="#cb21-23"></a> g_object_unref <span class="op">(</span>build<span class="op">);</span></span> <span id="cb19-23"><a href="#cb19-23"></a> g_object_unref <span class="op">(</span>build<span class="op">);</span></span>
<span id="cb21-24"><a href="#cb21-24"></a><span class="op">}</span></span> <span id="cb19-24"><a href="#cb19-24"></a><span class="op">}</span></span>
<span id="cb21-25"><a href="#cb21-25"></a></span> <span id="cb19-25"><a href="#cb19-25"></a></span>
<span id="cb21-26"><a href="#cb21-26"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.exp&quot;</span></span> <span id="cb19-26"><a href="#cb19-26"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.exp&quot;</span></span>
<span id="cb21-27"><a href="#cb21-27"></a></span> <span id="cb19-27"><a href="#cb19-27"></a></span>
<span id="cb21-28"><a href="#cb21-28"></a><span class="dt">int</span></span> <span id="cb19-28"><a href="#cb19-28"></a><span class="dt">int</span></span>
<span id="cb21-29"><a href="#cb21-29"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span> <span id="cb19-29"><a href="#cb19-29"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span>
<span id="cb21-30"><a href="#cb21-30"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span> <span id="cb19-30"><a href="#cb19-30"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb21-31"><a href="#cb21-31"></a> <span class="dt">int</span> stat<span class="op">;</span></span> <span id="cb19-31"><a href="#cb19-31"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb21-32"><a href="#cb21-32"></a></span> <span id="cb19-32"><a href="#cb19-32"></a></span>
<span id="cb21-33"><a href="#cb21-33"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_DEFAULT_FLAGS<span class="op">);</span></span> <span id="cb19-33"><a href="#cb19-33"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_DEFAULT_FLAGS<span class="op">);</span></span>
<span id="cb21-34"><a href="#cb21-34"></a></span> <span id="cb19-34"><a href="#cb19-34"></a></span>
<span id="cb21-35"><a href="#cb21-35"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;startup&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb19-35"><a href="#cb19-35"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;startup&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb21-36"><a href="#cb21-36"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb19-36"><a href="#cb19-36"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb21-37"><a href="#cb21-37"></a></span> <span id="cb19-37"><a href="#cb19-37"></a></span>
<span id="cb21-38"><a href="#cb21-38"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span> <span id="cb19-38"><a href="#cb19-38"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span>
<span id="cb21-39"><a href="#cb21-39"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span> <span id="cb19-39"><a href="#cb19-39"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb21-40"><a href="#cb21-40"></a> <span class="cf">return</span> stat<span class="op">;</span></span> <span id="cb19-40"><a href="#cb19-40"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb21-41"><a href="#cb21-41"></a><span class="op">}</span></span></code></pre></div> <span id="cb19-41"><a href="#cb19-41"></a><span class="op">}</span></span></code></pre></div>
<ul> <ul>
<li>4-6: The callback function. It returns a string (w)x(h), where the w <li>4-6: The callback function. It returns a string (w)x(h), where the w
and h are the width and height of the window. String duplication is and h are the width and height of the window. String duplication is
@ -893,18 +858,18 @@ necessary.</li>
</ul> </ul>
<p>The C source file is very simple because almost everything is done in <p>The C source file is very simple because almost everything is done in
the ui file.</p> the ui file.</p>
<h3 id="conversion-between-gvalues">Conversion between GValues</h3> <h2 id="conversion-between-gvalues">Conversion between GValues</h2>
<p>If you bind different type properties, type conversion is <p>If you bind different type properties, type conversion is
automatically done. Suppose a label property (string) is bound to automatically done. Suppose a label property (string) is bound to
default-width property (int).</p> default-width property (int).</p>
<div class="sourceCode" id="cb22"><pre <div class="sourceCode" id="cb20"><pre
class="sourceCode xml"><code class="sourceCode xml"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span>&gt;</span> class="sourceCode xml"><code class="sourceCode xml"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span>&gt;</span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">binding</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;</span> <span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">binding</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;</span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span>&gt;</span> <span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span>&gt;</span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a> win</span> <span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a> win</span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">lookup</span>&gt;</span> <span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">lookup</span>&gt;</span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">binding</span>&gt;</span> <span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">binding</span>&gt;</span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a>&lt;/<span class="kw">object</span>&gt;</span></code></pre></div> <span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a>&lt;/<span class="kw">object</span>&gt;</span></code></pre></div>
<p>The expression created by the lookup tag returns a int type GValue. <p>The expression created by the lookup tag returns a int type GValue.
On the other hand “label” property holds a string type GValue. When a On the other hand “label” property holds a string type GValue. When a
GValue is copied to another GValue, the type is automatically converted GValue is copied to another GValue, the type is automatically converted
@ -912,6 +877,37 @@ if possible. If the current width is 100, an int <code>100</code> is
converted to a string <code>"100"</code>.</p> converted to a string <code>"100"</code>.</p>
<p>If you use <code>g_object_get</code> and <code>g_object_set</code> to <p>If you use <code>g_object_get</code> and <code>g_object_set</code> to
copy properties, the value is automatically converted.</p> copy properties, the value is automatically converted.</p>
<h2 id="meson.build">Meson.build</h2>
<p>The source files are in <code>src/expression</code> directory. You
can build all the files at once.</p>
<pre><code>$ cd src/expression
$ meson setup _build
$ ninja -C _build</code></pre>
<p>For example, if you want to run “exp”, which is the executable file
from “exp.c”, type <code>_build/exp</code>. You can run other programs
as well.</p>
<p>The file <code>meson.build</code> is as follows.</p>
<div class="sourceCode" id="cb22"><pre
class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb22-1"><a href="#cb22-1"></a>project(&#39;exp&#39;, &#39;c&#39;)</span>
<span id="cb22-2"><a href="#cb22-2"></a></span>
<span id="cb22-3"><a href="#cb22-3"></a>gtkdep = dependency(&#39;gtk4&#39;)</span>
<span id="cb22-4"><a href="#cb22-4"></a></span>
<span id="cb22-5"><a href="#cb22-5"></a>gnome=import(&#39;gnome&#39;)</span>
<span id="cb22-6"><a href="#cb22-6"></a>resources = gnome.compile_resources(&#39;resources&#39;,&#39;exp.gresource.xml&#39;)</span>
<span id="cb22-7"><a href="#cb22-7"></a></span>
<span id="cb22-8"><a href="#cb22-8"></a>sourcefiles=files(&#39;exp.c&#39;)</span>
<span id="cb22-9"><a href="#cb22-9"></a></span>
<span id="cb22-10"><a href="#cb22-10"></a>executable(&#39;exp&#39;, sourcefiles, resources, dependencies: gtkdep, export_dynamic: true, install: false)</span>
<span id="cb22-11"><a href="#cb22-11"></a>executable(&#39;exp_constant&#39;, &#39;exp_constant.c&#39;, dependencies: gtkdep, export_dynamic: true, install: false)</span>
<span id="cb22-12"><a href="#cb22-12"></a>executable(&#39;exp_constant_simple&#39;, &#39;exp_constant_simple.c&#39;, dependencies: gtkdep, export_dynamic: true, install: false)</span>
<span id="cb22-13"><a href="#cb22-13"></a>executable(&#39;exp_property_simple&#39;, &#39;exp_property_simple.c&#39;, dependencies: gtkdep, export_dynamic: true, install: false)</span>
<span id="cb22-14"><a href="#cb22-14"></a>executable(&#39;closure&#39;, &#39;closure.c&#39;, dependencies: gtkdep, export_dynamic: true, install: false)</span>
<span id="cb22-15"><a href="#cb22-15"></a>executable(&#39;closure_each&#39;, &#39;closure_each.c&#39;, dependencies: gtkdep, export_dynamic: true, install: false)</span>
<span id="cb22-16"><a href="#cb22-16"></a>executable(&#39;exp_closure_simple&#39;, &#39;exp_closure_simple.c&#39;, dependencies: gtkdep, export_dynamic: true, install: false)</span>
<span id="cb22-17"><a href="#cb22-17"></a>executable(&#39;exp_closure_with_error_report&#39;, &#39;exp_closure_with_error_report.c&#39;, dependencies: gtkdep, export_dynamic: true, install: false)</span>
<span id="cb22-18"><a href="#cb22-18"></a>executable(&#39;exp_bind&#39;, &#39;exp_bind.c&#39;, resources, dependencies: gtkdep, export_dynamic: true, install: false)</span>
<span id="cb22-19"><a href="#cb22-19"></a>executable(&#39;exp_watch&#39;, &#39;exp_watch.c&#39;, dependencies: gtkdep, export_dynamic: true, install: false)</span>
<span id="cb22-20"><a href="#cb22-20"></a>executable(&#39;exp_test&#39;, &#39;exp_test.c&#39;, resources, dependencies: gtkdep, export_dynamic: true, install: false)</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>
</body> </body>

View file

@ -328,10 +328,9 @@ header of the column.</li>
as much as possible. (See the image above).</li> as much as possible. (See the image above).</li>
<li>33- 69: Sets the “factory” property to GtkBuilderListItemFactory. <li>33- 69: Sets the “factory” property to GtkBuilderListItemFactory.
The factory has “bytes” property which holds a ui string to define a The factory has “bytes” property which holds a ui string to define a
template to build GtkListItem composite widget. The CDATA section (line template to extend GtkListItem class. The CDATA section (line 36-66) is
36-66) is the ui string to put into the “bytes” property. The contents the ui string to put into the “bytes” property. The contents are the
are the same as the ui file <code>factory_list.ui</code> in the section same as the ui file <code>factory_list.ui</code> in the section 30.</li>
27.</li>
<li>70-77: Sets the “sorter” property to GtkStringSorter object. This <li>70-77: Sets the “sorter” property to GtkStringSorter object. This
object provides a sorter that compares strings. It has “expression” object provides a sorter that compares strings. It has “expression”
property. A closure tag with a string type function property. A closure tag with a string type function
@ -542,7 +541,8 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
<h2 id="compilation-and-execution.">Compilation and execution.</h2> <h2 id="compilation-and-execution.">Compilation and execution.</h2>
<p>All the source files are in <code>src/column</code> directory. Change <p>All the source files are in <code>src/column</code> directory. Change
your current directory to the directory and type the following.</p> your current directory to the directory and type the following.</p>
<pre><code>$ meson _build <pre><code>$ cd src/colomn
$ meson setup _build
$ ninja -C _build $ ninja -C _build
$ _build/column</code></pre> $ _build/column</code></pre>
<p>Then, a window appears.</p> <p>Then, a window appears.</p>

View file

@ -116,25 +116,14 @@ and GtkBulderListItemFactory</h2>
the contents of a list. Its binding direction is always from an item of the contents of a list. Its binding direction is always from an item of
a list to a child of GtkListItem.</p> a list to a child of GtkListItem.</p>
<p>When it comes to dynamic connection, its not enough. For example, <p>When it comes to dynamic connection, its not enough. For example,
you want to edit the contents of a list. You set a child of GtkListItem suppose you want to edit the contents of a list. You set a child of
to a GtkText instance so a user can edit a text with it. You need to GtkListItem to a GtkText instance so a user can edit a text with it. You
bind an item in the list with the buffer of the GtkText. The direction need to bind an item in the list with the buffer of the GtkText. The
is opposite from the one with GtkBuilderListItemFactory. It is from the direction is opposite from the one with GtkBuilderListItemFactory. It is
GtkText instance to the item in the list. You can implement this with from the GtkText instance to the item in the list. You can implement
GtkSignalListItemFactory, which is more flexible than this with GtkSignalListItemFactory, which is more flexible than
GtkBuilderListItemFactory.</p> GtkBuilderListItemFactory.</p>
<p>Two things are shown in this section.</p> <p>This section shows just some parts of the source file
<ul>
<li>Binding from a child of a GtkListItem instance to an item of a
list.</li>
<li>Access a child of GtkListItem dynamically. This direction is the
same as the one with GtkBulderListItemFactory. But
GtkBulderListItemFactory uses GtkExpression from the item property of
the GtkListItem. So, it updates its child widget only when the item
property changes. In this example the child reflects the change in the
same item in the list dynamically.</li>
</ul>
<p>This section shows just a part of the source file
<code>listeditor.c</code>. If you want to see the whole codes, see <code>listeditor.c</code>. If you want to see the whole codes, see
<code>src/listeditor</code> directory of the <a <code>src/listeditor</code> directory of the <a
href="https://github.com/ToshioCP/Gtk4-tutorial">Gtk4 tutorial href="https://github.com/ToshioCP/Gtk4-tutorial">Gtk4 tutorial
@ -143,7 +132,7 @@ repository</a>.</p>
<p>The sample program is a list editor and data of the list are strings. <p>The sample program is a list editor and data of the list are strings.
Its the same as a line editor. It reads a text file line by line. Each Its the same as a line editor. It reads a text file line by line. Each
line is an item of the list. The list is displayed with GtkColumnView. line is an item of the list. The list is displayed with GtkColumnView.
There are two columns. The one is a button, which makes the line be a There are two columns. The one is a button, which shows if the line is a
current line. If the line is the current line, the button is colored current line. If the line is the current line, the button is colored
with red. The other is a string which is the contents of the with red. The other is a string which is the contents of the
corresponding item of the list.</p> corresponding item of the list.</p>
@ -159,18 +148,19 @@ href="https://github.com/ToshioCP/Gtk4-tutorial">repository</a>.</li>
<li>Change your current directory to <code>src/listeditor</code>.</li> <li>Change your current directory to <code>src/listeditor</code>.</li>
<li>Type the following on your commandline.</li> <li>Type the following on your commandline.</li>
</ul> </ul>
<pre><code>$ meson _build <pre><code>$ meson setup _build
$ ninja -C _build $ ninja -C _build
$ _build/listeditor</code></pre> $ _build/listeditor</code></pre>
<ul> <ul>
<li>Append button: appends a line after the current line, or at the last <li>Append button: appends a line after the current line, or at the last
line if no current line exists.</li> line if no current line exists.</li>
<li>Insert button: inserts a line before the current line.</li> <li>Insert button: inserts a line before the current line, or at the top
line if no current line exists.</li>
<li>Remove button: removes a current line.</li> <li>Remove button: removes a current line.</li>
<li>Read button: reads a file.</li> <li>Read button: reads a file.</li>
<li>Write button: writes the contents to a file.</li> <li>Write button: writes the contents to a file.</li>
<li>close button: close the contents.</li> <li>close button: closes the contents.</li>
<li>quit button: quit the application.</li> <li>quit button: quits the application.</li>
<li>Button on the select column: makes the line current.</li> <li>Button on the select column: makes the line current.</li>
<li>String column: GtkText. You can edit a string in the field.</li> <li>String column: GtkText. You can edit a string in the field.</li>
</ul> </ul>
@ -180,7 +170,7 @@ bar. The file name is shown at the right of the write button.</p>
GtkText instance and an item in the list</h2> GtkText instance and an item in the list</h2>
<p>The second column (GtkColumnViewColumn) sets its factory property to <p>The second column (GtkColumnViewColumn) sets its factory property to
GtkSignalListItemFactory. It uses three signals setup, bind and unbind. GtkSignalListItemFactory. It uses three signals setup, bind and unbind.
The following is their sgnal handlers.</p> The following shows the signal handlers.</p>
<div class="sourceCode" id="cb2"><pre <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> 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>setup2_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span> <span id="cb2-2"><a href="#cb2-2"></a>setup2_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
@ -193,7 +183,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
<span id="cb2-9"><a href="#cb2-9"></a>bind2_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span> <span id="cb2-9"><a href="#cb2-9"></a>bind2_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-10"><a href="#cb2-10"></a> GtkWidget <span class="op">*</span>text <span class="op">=</span> gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">);</span></span> <span id="cb2-10"><a href="#cb2-10"></a> GtkWidget <span class="op">*</span>text <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> GtkEntryBuffer <span class="op">*</span>buffer <span class="op">=</span> gtk_text_get_buffer <span class="op">(</span>GTK_TEXT <span class="op">(</span>text<span class="op">));</span></span> <span id="cb2-11"><a href="#cb2-11"></a> GtkEntryBuffer <span class="op">*</span>buffer <span class="op">=</span> gtk_text_get_buffer <span class="op">(</span>GTK_TEXT <span class="op">(</span>text<span class="op">));</span></span>
<span id="cb2-12"><a href="#cb2-12"></a> LeData <span class="op">*</span>data <span class="op">=</span> LE_DATA <span class="op">(</span>gtk_list_item_get_item <span class="op">(</span>listitem<span class="op">));</span></span> <span id="cb2-12"><a href="#cb2-12"></a> LeData <span class="op">*</span>data <span class="op">=</span> LE_DATA <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> GBinding <span class="op">*</span>bind<span class="op">;</span></span> <span id="cb2-13"><a href="#cb2-13"></a> GBinding <span class="op">*</span>bind<span class="op">;</span></span>
<span id="cb2-14"><a href="#cb2-14"></a></span> <span id="cb2-14"><a href="#cb2-14"></a></span>
<span id="cb2-15"><a href="#cb2-15"></a> gtk_editable_set_text <span class="op">(</span>GTK_EDITABLE <span class="op">(</span>text<span class="op">),</span> le_data_look_string <span class="op">(</span>data<span class="op">));</span></span> <span id="cb2-15"><a href="#cb2-15"></a> gtk_editable_set_text <span class="op">(</span>GTK_EDITABLE <span class="op">(</span>text<span class="op">),</span> le_data_look_string <span class="op">(</span>data<span class="op">));</span></span>
@ -207,9 +197,10 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
<span id="cb2-23"><a href="#cb2-23"></a>unbind2_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span> <span id="cb2-23"><a href="#cb2-23"></a>unbind2_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-24"><a href="#cb2-24"></a> GBinding <span class="op">*</span>bind <span class="op">=</span> G_BINDING <span class="op">(</span>g_object_get_data <span class="op">(</span>G_OBJECT <span class="op">(</span>listitem<span class="op">),</span> <span class="st">&quot;bind&quot;</span><span class="op">));</span></span> <span id="cb2-24"><a href="#cb2-24"></a> GBinding <span class="op">*</span>bind <span class="op">=</span> G_BINDING <span class="op">(</span>g_object_get_data <span class="op">(</span>G_OBJECT <span class="op">(</span>listitem<span class="op">),</span> <span class="st">&quot;bind&quot;</span><span class="op">));</span></span>
<span id="cb2-25"><a href="#cb2-25"></a></span> <span id="cb2-25"><a href="#cb2-25"></a></span>
<span id="cb2-26"><a href="#cb2-26"></a> g_binding_unbind<span class="op">(</span>bind<span class="op">);</span></span> <span id="cb2-26"><a href="#cb2-26"></a> <span class="cf">if</span> <span class="op">(</span>bind<span class="op">)</span></span>
<span id="cb2-27"><a href="#cb2-27"></a> g_object_set_data <span class="op">(</span>G_OBJECT <span class="op">(</span>listitem<span class="op">),</span> <span class="st">&quot;bind&quot;</span><span class="op">,</span> NULL<span class="op">);</span></span> <span id="cb2-27"><a href="#cb2-27"></a> g_binding_unbind<span class="op">(</span>bind<span class="op">);</span></span>
<span id="cb2-28"><a href="#cb2-28"></a><span class="op">}</span></span></code></pre></div> <span id="cb2-28"><a href="#cb2-28"></a> g_object_set_data <span class="op">(</span>G_OBJECT <span class="op">(</span>listitem<span class="op">),</span> <span class="st">&quot;bind&quot;</span><span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb2-29"><a href="#cb2-29"></a><span class="op">}</span></span></code></pre></div>
<ul> <ul>
<li>1-6: <code>setup2_cb</code> is a setup signal handler on the <li>1-6: <code>setup2_cb</code> is a setup signal handler on the
GtkSignalListItemFactory. This factory is inserted to the factory GtkSignalListItemFactory. This factory is inserted to the factory
@ -221,22 +212,18 @@ is destroyed. So, teardown signal handler isnt necessary.</li>
when the <code>listitem</code> is bound to an item in the list. The list when the <code>listitem</code> is bound to an item in the list. The list
items are LeData instances. LeData is defined in the file items are LeData instances. LeData is defined in the file
<code>listeditor.c</code> (the C source file of the list editor). It is <code>listeditor.c</code> (the C source file of the list editor). It is
a child class of GObject and has two data. The one is a child class of GObject and has string data which is the content of the
<code>listitem</code> which points a first column GtkListItem instance line.
when they are connected. Be careful that the GtkListItem instance is
<em>not</em> the <code>listitem</code> in this handler. If no
GtkListItem is connected, it is NULL. The other is <code>string</code>
which is a content of the line.
<ul> <ul>
<li>10-11: <code>text</code> is a child of the <code>listitem</code> and <li>10-11: <code>text</code> is a child of the <code>listitem</code> and
it is a GtkText instance. And <code>buffer</code> is a GtkTextBuffer it is a GtkText instance. And <code>buffer</code> is a GtkEntryBuffer
instance of the <code>text</code>.</li> instance of the <code>text</code>.</li>
<li>12: The LeData instance <code>data</code> is an item pointed by the <li>12: The LeData instance <code>data</code> is an item pointed by the
<code>listitem</code>.</li> <code>listitem</code>.</li>
<li>15-16: Sets the text of <code>text</code> to <li>15-16: Sets the text of <code>text</code> to
<code>le_data_look_string (data)</code>. le_data_look_string returns the <code>le_data_look_string (data)</code>. le_data_look_string returns the
string of the <code>data</code> and the ownership of the string is still string of the <code>data</code> and the ownership of the string is still
taken by the <code>data</code>. So, the caller dont need to free the taken by the <code>data</code>. So, the caller doesnt need to free the
string.</li> string.</li>
<li>18: <code>g_object_bind_property</code> binds a property and another <li>18: <code>g_object_bind_property</code> binds a property and another
object property. This line binds the “text” property of the object property. This line binds the “text” property of the
@ -254,16 +241,22 @@ value. This line sets the association from “bind” to <code>bind</code>
instance. It makes possible for the “unbind” handler to get the instance. It makes possible for the “unbind” handler to get the
<code>bind</code> instance.</li> <code>bind</code> instance.</li>
</ul></li> </ul></li>
<li>22-28: <code>unbind2_cb</code> is a unbind signal handler. <li>22-29: <code>unbind2_cb</code> is a unbind signal handler.
<ul> <ul>
<li>24: Retrieves the <code>bind</code> instance from the table in the <li>24: Retrieves the <code>bind</code> instance from the table in the
<code>listitem</code> instance.</li> <code>listitem</code> instance.</li>
<li>26: Unbind the binding.</li> <li>26-27: Unbind the binding.</li>
<li>27: Removes the value corresponds to the “bind” key.</li> <li>28: Removes the value corresponds to the “bind” key.</li>
</ul></li> </ul></li>
</ul> </ul>
<p>This technique is not so complicated. You can use it when you make a <p>This technique is not so complicated. You can use it when you make a
cell editable application.</p> cell editable application.</p>
<p>If it is impossible to use <code>g_object_bind_property</code>, use a
notify signal on the GtkEntryBuffer instance. You can use “deleted-text”
and “inserted-text” signal instead. The handler of the signals above
copies the text in the GtkEntryBuffer instance to the LeData string.
Connect the notify signal handler in <code>bind2_cb</code> and
disconnect it in <code>unbind2_cb</code>.</p>
<h2 id="change-the-cell-of-gtkcolumnview-dynamically">Change the cell of <h2 id="change-the-cell-of-gtkcolumnview-dynamically">Change the cell of
GtkColumnView dynamically</h2> GtkColumnView dynamically</h2>
<p>Next topic is to change the GtkColumnView (or GtkListView) cells <p>Next topic is to change the GtkColumnView (or GtkListView) cells
@ -289,164 +282,148 @@ GtkSingleSelection selects a line on the display. The current line
doesnt need to be on the display. It is possible to be on the line out doesnt need to be on the display. It is possible to be on the line out
of the Window (GtkScrolledWindow). Actually, the program doesnt use of the Window (GtkScrolledWindow). Actually, the program doesnt use
GtkSingleSelection.</p> GtkSingleSelection.</p>
<p>It is necessary to know the corresponding GtkListItem instance from <p>The LeWindow instance has two instance variables for recording the
the item in the list. It is the opposite direction from current line.</p>
<code>gtk_list_item_get_item</code> function. To accomplish this, we set <ul>
a <code>listitem</code> element of LeData to point the corresponding <li><code>win-&gt;position</code>: An int type variable. It is the
GtkListItem instance. Therefore, items (LeData) in the list always know position of the current line. It is zero-based. If no current line
the GtkListItem. If theres no GtkListItem bound to the item, NULL is exists, it is -1.</li>
assigned.</p> <li><code>win-&gt;current_button</code>: A variable points the button,
located at the first column, on the current line. If no current line
exists, it is NULL.</li>
</ul>
<p>If the current line moves, the following two functions are called.
They updates the two varables.</p>
<div class="sourceCode" id="cb3"><pre <div class="sourceCode" id="cb3"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a><span class="dt">void</span></span> class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb3-2"><a href="#cb3-2"></a>select_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span> <span id="cb3-2"><a href="#cb3-2"></a>update_current_position <span class="op">(</span>LeWindow <span class="op">*</span>win<span class="op">,</span> <span class="dt">int</span> new<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-3"><a href="#cb3-3"></a> LeWindow <span class="op">*</span>win <span class="op">=</span> LE_WINDOW <span class="op">(</span>gtk_widget_get_ancestor <span class="op">(</span>GTK_WIDGET <span class="op">(</span>btn<span class="op">),</span> LE_TYPE_WINDOW<span class="op">));</span></span> <span id="cb3-3"><a href="#cb3-3"></a> <span class="dt">char</span> <span class="op">*</span>s<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> update_current <span class="op">(</span>win<span class="op">,</span> gtk_list_item_get_position <span class="op">(</span>listitem<span class="op">));</span></span> <span id="cb3-5"><a href="#cb3-5"></a> win<span class="op">-&gt;</span>position <span class="op">=</span> new<span class="op">;</span></span>
<span id="cb3-6"><a href="#cb3-6"></a><span class="op">}</span></span> <span id="cb3-6"><a href="#cb3-6"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-&gt;</span>position <span class="op">&gt;=</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb3-7"><a href="#cb3-7"></a></span> <span id="cb3-7"><a href="#cb3-7"></a> s <span class="op">=</span> g_strdup_printf <span class="op">(</span><span class="st">&quot;%d&quot;</span><span class="op">,</span> win<span class="op">-&gt;</span>position<span class="op">);</span></span>
<span id="cb3-8"><a href="#cb3-8"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb3-8"><a href="#cb3-8"></a> <span class="cf">else</span></span>
<span id="cb3-9"><a href="#cb3-9"></a>setup1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span> <span id="cb3-9"><a href="#cb3-9"></a> s <span class="op">=</span> <span class="st">&quot;&quot;</span><span class="op">;</span></span>
<span id="cb3-10"><a href="#cb3-10"></a> GtkWidget <span class="op">*</span>button <span class="op">=</span> gtk_button_new <span class="op">();</span></span> <span id="cb3-10"><a href="#cb3-10"></a> gtk_label_set_text <span class="op">(</span>GTK_LABEL <span class="op">(</span>win<span class="op">-&gt;</span>position_label<span class="op">),</span> s<span class="op">);</span></span>
<span id="cb3-11"><a href="#cb3-11"></a> gtk_list_item_set_child <span class="op">(</span>listitem<span class="op">,</span> button<span class="op">);</span></span> <span id="cb3-11"><a href="#cb3-11"></a> <span class="cf">if</span> <span class="op">(*</span>s<span class="op">)</span> <span class="co">// s isn&#39;t an empty string</span></span>
<span id="cb3-12"><a href="#cb3-12"></a> gtk_widget_set_focusable <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> FALSE<span class="op">);</span></span> <span id="cb3-12"><a href="#cb3-12"></a> g_free <span class="op">(</span>s<span class="op">);</span></span>
<span id="cb3-13"><a href="#cb3-13"></a> g_signal_connect <span class="op">(</span>button<span class="op">,</span> <span class="st">&quot;clicked&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>select_cb<span class="op">),</span> listitem<span class="op">);</span></span> <span id="cb3-13"><a href="#cb3-13"></a><span class="op">}</span></span>
<span id="cb3-14"><a href="#cb3-14"></a><span class="op">}</span></span> <span id="cb3-14"><a href="#cb3-14"></a></span>
<span id="cb3-15"><a href="#cb3-15"></a></span> <span id="cb3-15"><a href="#cb3-15"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb3-16"><a href="#cb3-16"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb3-16"><a href="#cb3-16"></a>update_current_button <span class="op">(</span>LeWindow <span class="op">*</span>win<span class="op">,</span> GtkButton <span class="op">*</span>new_button<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-17"><a href="#cb3-17"></a>bind1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<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="cb3-17"><a href="#cb3-17"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>non_current<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span>NULL<span class="op">};</span></span>
<span id="cb3-18"><a href="#cb3-18"></a> LeWindow <span class="op">*</span>win <span class="op">=</span> LE_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span> <span id="cb3-18"><a href="#cb3-18"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>current<span class="op">[</span><span class="dv">2</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="st">&quot;current&quot;</span><span class="op">,</span> NULL<span class="op">};</span></span>
<span id="cb3-19"><a href="#cb3-19"></a> GtkWidget <span class="op">*</span>button <span class="op">=</span> gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">);</span></span> <span id="cb3-19"><a href="#cb3-19"></a></span>
<span id="cb3-20"><a href="#cb3-20"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>non_current<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span>NULL<span class="op">};</span></span> <span id="cb3-20"><a href="#cb3-20"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-&gt;</span>current_button<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-21"><a href="#cb3-21"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>current<span class="op">[</span><span class="dv">2</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="st">&quot;current&quot;</span><span class="op">,</span> NULL<span class="op">};</span></span> <span id="cb3-21"><a href="#cb3-21"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>win<span class="op">-&gt;</span>current_button<span class="op">),</span> non_current<span class="op">);</span></span>
<span id="cb3-22"><a href="#cb3-22"></a> LeData <span class="op">*</span>data <span class="op">=</span> LE_DATA <span class="op">(</span>gtk_list_item_get_item <span class="op">(</span>listitem<span class="op">));</span></span> <span id="cb3-22"><a href="#cb3-22"></a> g_object_unref <span class="op">(</span>win<span class="op">-&gt;</span>current_button<span class="op">);</span></span>
<span id="cb3-23"><a href="#cb3-23"></a></span> <span id="cb3-23"><a href="#cb3-23"></a> <span class="op">}</span></span>
<span id="cb3-24"><a href="#cb3-24"></a> <span class="cf">if</span> <span class="op">(</span>data<span class="op">)</span> <span class="op">{</span></span> <span id="cb3-24"><a href="#cb3-24"></a> win<span class="op">-&gt;</span>current_button <span class="op">=</span> new_button<span class="op">;</span></span>
<span id="cb3-25"><a href="#cb3-25"></a> le_data_set_listitem <span class="op">(</span>data<span class="op">,</span> listitem<span class="op">);</span></span> <span id="cb3-25"><a href="#cb3-25"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-&gt;</span>current_button<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-26"><a href="#cb3-26"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-&gt;</span>position <span class="op">==</span> gtk_list_item_get_position <span class="op">(</span>listitem<span class="op">))</span></span> <span id="cb3-26"><a href="#cb3-26"></a> g_object_ref <span class="op">(</span>win<span class="op">-&gt;</span>current_button<span class="op">);</span></span>
<span id="cb3-27"><a href="#cb3-27"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> current<span class="op">);</span></span> <span id="cb3-27"><a href="#cb3-27"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>win<span class="op">-&gt;</span>current_button<span class="op">),</span> current<span class="op">);</span></span>
<span id="cb3-28"><a href="#cb3-28"></a> <span class="cf">else</span></span> <span id="cb3-28"><a href="#cb3-28"></a> <span class="op">}</span></span>
<span id="cb3-29"><a href="#cb3-29"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> non_current<span class="op">);</span></span> <span id="cb3-29"><a href="#cb3-29"></a><span class="op">}</span></span></code></pre></div>
<span id="cb3-30"><a href="#cb3-30"></a> <span class="op">}</span></span> <p>The varable <code>win-&gt;position_label</code> points a GtkLabel
<span id="cb3-31"><a href="#cb3-31"></a><span class="op">}</span></span> instance. The label shows the current line position.</p>
<span id="cb3-32"><a href="#cb3-32"></a></span> <p>The current button has CSS “current” class. The button is colored red
<span id="cb3-33"><a href="#cb3-33"></a><span class="dt">static</span> <span class="dt">void</span></span> through the CSS “button.current {background: red;}”.</p>
<span id="cb3-34"><a href="#cb3-34"></a>unbind1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span> <p>The order of the call for these two functions is important. The first
<span id="cb3-35"><a href="#cb3-35"></a> LeData <span class="op">*</span>data <span class="op">=</span> LE_DATA <span class="op">(</span>gtk_list_item_get_item <span class="op">(</span>listitem<span class="op">));</span></span> function, which updates the position, is usually called first. After
<span id="cb3-36"><a href="#cb3-36"></a> <span class="cf">if</span> <span class="op">(</span>data<span class="op">)</span></span> that, a new line is appended or inserted. Then, the second function is
<span id="cb3-37"><a href="#cb3-37"></a> le_data_set_listitem <span class="op">(</span>data<span class="op">,</span> NULL<span class="op">);</span></span> called.</p>
<span id="cb3-38"><a href="#cb3-38"></a><span class="op">}</span></span></code></pre></div> <p>The following functions call the two functions above. Be careful
<ul> about the order of the call.</p>
<li>8-14: <code>setup1_cb</code> is a setup signal handler on the
GtkSignalListItemFactory. This factory is inserted to the factory
property of the first GtkColumnViewColumn. It sets the child of
<code>listitem</code> to a GtkButton instance. The “clicked” signal on
the button is connected to the handler <code>select_cb</code>. When the
listitem is destroyed, the child (GtkButton) is also destroyed. At the
same time, the connection of the signal and the handler is also
destroyed. So, you dont need teardown signal handler.</li>
<li>1-6: <code>select_cb</code> is a “clicked” signal handler. LeWindow
is defined in <code>listeditor.c</code>. Its a child class of
GtkApplicationWindow. The handler just calls the
<code>update_current</code> function. The function will be explained
later.</li>
<li>16-31: <code>bind1_cb</code> is a bind signal handler. It sets the
“listitem” element of the item (LeData) to point the
<code>listitem</code> (GtkListItem instance). It makes the item possible
to find the corresponding GtkListItem instance. If the item is the
current line, the CSS class of the button includes “current” class.
Otherwise it has no CSS class. This is necessary because the button may
be recycled and it has had former CSS class. The class need to be
updated.</li>
<li>33-38: <code>unbind1_cb</code> is an unbind signal handler. It
removes the <code>listitem</code> instance from the “listitem” element
of the item. The element becomes NULL, which tells no GtkListItem is
bound. When referring GtkListItem, it needs to check the “listitem”
element whether it points a GtkListItem or not (NULL). Otherwise bad
things will happen.</li>
</ul>
<div class="sourceCode" id="cb4"><pre <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="dt">static</span> <span class="dt">void</span></span> class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1"></a><span class="dt">void</span></span>
<span id="cb4-2"><a href="#cb4-2"></a>update_current <span class="op">(</span>LeWindow <span class="op">*</span>win<span class="op">,</span> <span class="dt">int</span> new<span class="op">)</span> <span class="op">{</span></span> <span id="cb4-2"><a href="#cb4-2"></a>select_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-3"></a> <span class="dt">char</span> <span class="op">*</span>s<span class="op">;</span></span> <span id="cb4-3"><a href="#cb4-3"></a> LeWindow <span class="op">*</span>win <span class="op">=</span> LE_WINDOW <span class="op">(</span>gtk_widget_get_ancestor <span class="op">(</span>GTK_WIDGET <span class="op">(</span>btn<span class="op">),</span> LE_TYPE_WINDOW<span class="op">));</span></span>
<span id="cb4-4"><a href="#cb4-4"></a> LeData <span class="op">*</span>data<span class="op">;</span></span> <span id="cb4-4"><a href="#cb4-4"></a></span>
<span id="cb4-5"><a href="#cb4-5"></a> GtkListItem <span class="op">*</span>listitem<span class="op">;</span></span> <span id="cb4-5"><a href="#cb4-5"></a> update_current_position <span class="op">(</span>win<span class="op">,</span> gtk_list_item_get_position <span class="op">(</span>listitem<span class="op">));</span></span>
<span id="cb4-6"><a href="#cb4-6"></a> GtkButton <span class="op">*</span>button<span class="op">;</span></span> <span id="cb4-6"><a href="#cb4-6"></a> update_current_button <span class="op">(</span>win<span class="op">,</span> btn<span class="op">);</span></span>
<span id="cb4-7"><a href="#cb4-7"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>non_current<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span>NULL<span class="op">};</span></span> <span id="cb4-7"><a href="#cb4-7"></a><span class="op">}</span></span>
<span id="cb4-8"><a href="#cb4-8"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>current<span class="op">[</span><span class="dv">2</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="st">&quot;current&quot;</span><span class="op">,</span> NULL<span class="op">};</span></span> <span id="cb4-8"><a href="#cb4-8"></a></span>
<span id="cb4-9"><a href="#cb4-9"></a></span> <span id="cb4-9"><a href="#cb4-9"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-10"><a href="#cb4-10"></a> <span class="cf">if</span> <span class="op">(</span>new <span class="op">&gt;=</span> <span class="dv">0</span><span class="op">)</span></span> <span id="cb4-10"><a href="#cb4-10"></a>setup1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-11"><a href="#cb4-11"></a> s <span class="op">=</span> g_strdup_printf <span class="op">(</span><span class="st">&quot;%d&quot;</span><span class="op">,</span> new<span class="op">);</span></span> <span id="cb4-11"><a href="#cb4-11"></a> GtkWidget <span class="op">*</span>button <span class="op">=</span> gtk_button_new <span class="op">();</span></span>
<span id="cb4-12"><a href="#cb4-12"></a> <span class="cf">else</span></span> <span id="cb4-12"><a href="#cb4-12"></a> gtk_list_item_set_child <span class="op">(</span>listitem<span class="op">,</span> button<span class="op">);</span></span>
<span id="cb4-13"><a href="#cb4-13"></a> s <span class="op">=</span> <span class="st">&quot;&quot;</span><span class="op">;</span></span> <span id="cb4-13"><a href="#cb4-13"></a> gtk_widget_set_focusable <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> FALSE<span class="op">);</span></span>
<span id="cb4-14"><a href="#cb4-14"></a> gtk_label_set_text <span class="op">(</span>GTK_LABEL <span class="op">(</span>win<span class="op">-&gt;</span>position_label<span class="op">),</span> s<span class="op">);</span></span> <span id="cb4-14"><a href="#cb4-14"></a> g_signal_connect <span class="op">(</span>button<span class="op">,</span> <span class="st">&quot;clicked&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>select_cb<span class="op">),</span> listitem<span class="op">);</span></span>
<span id="cb4-15"><a href="#cb4-15"></a> <span class="cf">if</span> <span class="op">(*</span>s<span class="op">)</span> <span class="co">// s isn&#39;t an empty string</span></span> <span id="cb4-15"><a href="#cb4-15"></a><span class="op">}</span></span>
<span id="cb4-16"><a href="#cb4-16"></a> g_free <span class="op">(</span>s<span class="op">);</span></span> <span id="cb4-16"><a href="#cb4-16"></a></span>
<span id="cb4-17"><a href="#cb4-17"></a></span> <span id="cb4-17"><a href="#cb4-17"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-18"><a href="#cb4-18"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-&gt;</span>position <span class="op">&gt;=</span><span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span> <span id="cb4-18"><a href="#cb4-18"></a>bind1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<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="cb4-19"><a href="#cb4-19"></a> data <span class="op">=</span> LE_DATA <span class="op">(</span>g_list_model_get_item <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>win<span class="op">-&gt;</span>liststore<span class="op">),</span> win<span class="op">-&gt;</span>position<span class="op">));</span></span> <span id="cb4-19"><a href="#cb4-19"></a> LeWindow <span class="op">*</span>win <span class="op">=</span> LE_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span>
<span id="cb4-20"><a href="#cb4-20"></a> <span class="cf">if</span> <span class="op">((</span>listitem <span class="op">=</span> le_data_get_listitem <span class="op">(</span>data<span class="op">))</span> <span class="op">!=</span> NULL<span class="op">)</span> <span class="op">{</span></span> <span id="cb4-20"><a href="#cb4-20"></a> GtkWidget <span class="op">*</span>button <span class="op">=</span> gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">);</span></span>
<span id="cb4-21"><a href="#cb4-21"></a> button <span class="op">=</span> GTK_BUTTON <span class="op">(</span>gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">));</span></span> <span id="cb4-21"><a href="#cb4-21"></a></span>
<span id="cb4-22"><a href="#cb4-22"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> non_current<span class="op">);</span></span> <span id="cb4-22"><a href="#cb4-22"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-&gt;</span>position <span class="op">==</span> gtk_list_item_get_position <span class="op">(</span>listitem<span class="op">))</span></span>
<span id="cb4-23"><a href="#cb4-23"></a> g_object_unref <span class="op">(</span>listitem<span class="op">);</span></span> <span id="cb4-23"><a href="#cb4-23"></a> update_current_button <span class="op">(</span>win<span class="op">,</span> GTK_BUTTON <span class="op">(</span>button<span class="op">));</span></span>
<span id="cb4-24"><a href="#cb4-24"></a> <span class="op">}</span></span> <span id="cb4-24"><a href="#cb4-24"></a><span class="op">}</span></span></code></pre></div>
<span id="cb4-25"><a href="#cb4-25"></a> g_object_unref <span class="op">(</span>data<span class="op">);</span></span>
<span id="cb4-26"><a href="#cb4-26"></a> <span class="op">}</span></span>
<span id="cb4-27"><a href="#cb4-27"></a> win<span class="op">-&gt;</span>position <span class="op">=</span> new<span class="op">;</span></span>
<span id="cb4-28"><a href="#cb4-28"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-&gt;</span>position <span class="op">&gt;=</span><span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-29"><a href="#cb4-29"></a> data <span class="op">=</span> LE_DATA <span class="op">(</span>g_list_model_get_item <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>win<span class="op">-&gt;</span>liststore<span class="op">),</span> win<span class="op">-&gt;</span>position<span class="op">));</span></span>
<span id="cb4-30"><a href="#cb4-30"></a> <span class="cf">if</span> <span class="op">((</span>listitem <span class="op">=</span> le_data_get_listitem <span class="op">(</span>data<span class="op">))</span> <span class="op">!=</span> NULL<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-31"><a href="#cb4-31"></a> button <span class="op">=</span> GTK_BUTTON <span class="op">(</span>gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">));</span></span>
<span id="cb4-32"><a href="#cb4-32"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> current<span class="op">);</span></span>
<span id="cb4-33"><a href="#cb4-33"></a> g_object_unref <span class="op">(</span>listitem<span class="op">);</span></span>
<span id="cb4-34"><a href="#cb4-34"></a> <span class="op">}</span></span>
<span id="cb4-35"><a href="#cb4-35"></a> g_object_unref <span class="op">(</span>data<span class="op">);</span></span>
<span id="cb4-36"><a href="#cb4-36"></a> <span class="op">}</span></span>
<span id="cb4-37"><a href="#cb4-37"></a><span class="op">}</span></span></code></pre></div>
<p>The function <code>update_current</code> does several things.</p>
<ul> <ul>
<li>It has two parameters. The first one is <code>win</code>, which is <li>1-7: <code>select_cb</code> is a “clicked” signal handler. The
an instance of LeWindow class. It has some elements. handler just calls the two functions and update the position and
<ul>
<li>win-&gt;position: an Integer. it is the current position. If no
current line exists, it is -1.</li>
<li>win-&gt;position_label: GtkLabel. It shows the current
position.</li>
</ul></li>
<li>The second parameter is <code>new</code>, which is the new current
position. At the beginning of the function, win-&gt;position points the
old position.</li>
<li>10-16: Update the text of GtkLabel.</li>
<li>18-26: If the old position (win-&gt;position) is not negative, the
current line exists. It gets a GtkListItem instance via the item
(LeData) of the list. And it gets the GtkButton instance which is the
child of the GtkListItem. It clears the “css-classes” property of the
button.</li> button.</li>
<li>27: Updates win-&gt;position.</li> <li>9-15: <code>setup1_cb</code> is a setup signal handler on the
<li>28-36: If the new position is not negative (Its possible to be GtkSignalListItemFactory. It sets the child of <code>listitem</code> to
negative when the current line has been removed), the current line a GtkButton instance. The “clicked” signal on the button is connected to
exists. It sets the “css-classes” property of the button to the handler <code>select_cb</code>. When the listitem is destroyed, the
<code>{"current", NULL}</code>. It is a NULL-terminated array of child (GtkButton) is also destroyed. At the same time, the connection of
strings. Each string is a CSS class. Now the button has “current” style the signal and the handler is also destroyed. So, you dont need
class.</li> teardown signal handler.</li>
<li>17-24: <code>bind1_cb</code> is a bind signal handler. Usually, the
position moves before this handler is called. If the item is on the
current line, the button is updated. No unbind handler is
necessary.</li>
</ul> </ul>
<p>The color of buttons are determined by the “background” CSS style. <p>When a line is added, the current position is updated in advance.</p>
The following CSS is applied to the default GdkDisplay in advance (in
the startup handler of the application).</p>
<div class="sourceCode" id="cb5"><pre <div class="sourceCode" id="cb5"><pre
class="sourceCode css"><code class="sourceCode css"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>columnview listview row button<span class="fu">.current</span> {<span class="kw">background</span>: <span class="cn">red</span><span class="op">;</span>}</span></code></pre></div> class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<p>The selectors “columnview listview row” is needed before “button” <span id="cb5-2"><a href="#cb5-2"></a>app_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">,</span> LeWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
selector. Otherwise the buttons in the GtkColumnview wont be found. The <span id="cb5-3"><a href="#cb5-3"></a> LeData <span class="op">*</span>data <span class="op">=</span> le_data_new_with_data <span class="op">(</span><span class="st">&quot;&quot;</span><span class="op">);</span></span>
button selector has “current” class. So, the only “current” class button <span id="cb5-4"><a href="#cb5-4"></a></span>
is colored with red. Other buttons are not colored, which means they are <span id="cb5-5"><a href="#cb5-5"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-&gt;</span>position <span class="op">&gt;=</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
white.</p> <span id="cb5-6"><a href="#cb5-6"></a> update_current_position <span class="op">(</span>win<span class="op">,</span> win<span class="op">-&gt;</span>position <span class="op">+</span> <span class="dv">1</span><span class="op">);</span></span>
<h2 <span id="cb5-7"><a href="#cb5-7"></a> g_list_store_insert <span class="op">(</span>win<span class="op">-&gt;</span>liststore<span class="op">,</span> win<span class="op">-&gt;</span>position<span class="op">,</span> data<span class="op">);</span></span>
id="gtk_widget_dispose_template-function">Gtk_widget_dispose_template <span id="cb5-8"><a href="#cb5-8"></a> <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
function</h2> <span id="cb5-9"><a href="#cb5-9"></a> update_current_position <span class="op">(</span>win<span class="op">,</span> g_list_model_get_n_items <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>win<span class="op">-&gt;</span>liststore<span class="op">)));</span></span>
<p>The function <code>gtk_widget_dispose_template</code> clears the <span id="cb5-10"><a href="#cb5-10"></a> g_list_store_append <span class="op">(</span>win<span class="op">-&gt;</span>liststore<span class="op">,</span> data<span class="op">);</span></span>
template children for the given widget. This is the opposite of <span id="cb5-11"><a href="#cb5-11"></a> <span class="op">}</span></span>
<code>gtk_widget_init_template()</code>. It is a new function of GTK 4.8 <span id="cb5-12"><a href="#cb5-12"></a> g_object_unref <span class="op">(</span>data<span class="op">);</span></span>
version. If your GTK version is lower than 4.8, you need to modify the <span id="cb5-13"><a href="#cb5-13"></a><span class="op">}</span></span>
program.</p> <span id="cb5-14"><a href="#cb5-14"></a></span>
<span id="cb5-15"><a href="#cb5-15"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb5-16"><a href="#cb5-16"></a>ins_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">,</span> LeWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-17"><a href="#cb5-17"></a> LeData <span class="op">*</span>data <span class="op">=</span> le_data_new_with_data <span class="op">(</span><span class="st">&quot;&quot;</span><span class="op">);</span></span>
<span id="cb5-18"><a href="#cb5-18"></a></span>
<span id="cb5-19"><a href="#cb5-19"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-&gt;</span>position <span class="op">&gt;=</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb5-20"><a href="#cb5-20"></a> g_list_store_insert <span class="op">(</span>win<span class="op">-&gt;</span>liststore<span class="op">,</span> win<span class="op">-&gt;</span>position<span class="op">,</span> data<span class="op">);</span></span>
<span id="cb5-21"><a href="#cb5-21"></a> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb5-22"><a href="#cb5-22"></a> update_current_position <span class="op">(</span>win<span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
<span id="cb5-23"><a href="#cb5-23"></a> g_list_store_insert <span class="op">(</span>win<span class="op">-&gt;</span>liststore<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> data<span class="op">);</span></span>
<span id="cb5-24"><a href="#cb5-24"></a> <span class="op">}</span></span>
<span id="cb5-25"><a href="#cb5-25"></a> g_object_unref <span class="op">(</span>data<span class="op">);</span></span>
<span id="cb5-26"><a href="#cb5-26"></a><span class="op">}</span></span></code></pre></div>
<p>When a line is removed, the current position becomes -1 and no button
is current.</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb6-2"><a href="#cb6-2"></a>rm_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">,</span> LeWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-3"><a href="#cb6-3"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-&gt;</span>position <span class="op">&gt;=</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-4"><a href="#cb6-4"></a> g_list_store_remove <span class="op">(</span>win<span class="op">-&gt;</span>liststore<span class="op">,</span> win<span class="op">-&gt;</span>position<span class="op">);</span></span>
<span id="cb6-5"><a href="#cb6-5"></a> update_current_position <span class="op">(</span>win<span class="op">,</span> <span class="op">-</span><span class="dv">1</span><span class="op">);</span></span>
<span id="cb6-6"><a href="#cb6-6"></a> update_current_button <span class="op">(</span>win<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb6-7"><a href="#cb6-7"></a> <span class="op">}</span></span>
<span id="cb6-8"><a href="#cb6-8"></a><span class="op">}</span></span></code></pre></div>
<p>The color of buttons are determined by the “background” CSS style.
The following CSS node is a bit complicated. CSS node
<code>column view</code> has <code>listview</code> child node. It covers
the rows in the GtkColumnView. The <code>listview</code> node is the
same as the one for GtkListView. It has <code>row</code> child node,
which is for each child widget. Therefore, the following node
corresponds buttons on the GtkColumnView widget. In addition, it is
applied to the “current” class.</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode css"><code class="sourceCode css"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>columnview listview row button<span class="fu">.current</span> {<span class="kw">background</span>: <span class="cn">red</span><span class="op">;</span>}</span></code></pre></div>
<h2 id="a-waring-from-gtktext">A waring from GtkText</h2> <h2 id="a-waring-from-gtktext">A waring from GtkText</h2>
<p>If your program has the following two, a warning message can be <p>If your program has the following two, a warning message can be
issued.</p> issued.</p>
@ -462,24 +439,24 @@ probably comes from focus and scroll.</p>
window. When scroll begins, the “value-changed” signal on the vertical window. When scroll begins, the “value-changed” signal on the vertical
adjustment of the scrolled window is emitted.</p> adjustment of the scrolled window is emitted.</p>
<p>The following is extracted from the ui file and C source file.</p> <p>The following is extracted from the ui file and C source file.</p>
<div class="sourceCode" id="cb7"><pre <div class="sourceCode" id="cb9"><pre
class="sourceCode xml"><code class="sourceCode xml"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>... ... ...</span> class="sourceCode xml"><code class="sourceCode xml"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>... ... ...</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkScrolledWindow&quot;</span>&gt;</span> <span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkScrolledWindow&quot;</span>&gt;</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></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="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></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="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></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="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></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="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;vadjustment&quot;</span>&gt;</span> <span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;vadjustment&quot;</span>&gt;</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkAdjustment&quot;</span>&gt;</span> <span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkAdjustment&quot;</span>&gt;</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">signal</span><span class="ot"> name=</span><span class="st">&quot;value-changed&quot;</span><span class="ot"> handler=</span><span class="st">&quot;adjustment_value_changed_cb&quot;</span><span class="ot"> swapped=</span><span class="st">&quot;no&quot;</span><span class="ot"> object=</span><span class="st">&quot;LeWindow&quot;</span>/&gt;</span> <span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">signal</span><span class="ot"> name=</span><span class="st">&quot;value-changed&quot;</span><span class="ot"> handler=</span><span class="st">&quot;adjustment_value_changed_cb&quot;</span><span class="ot"> swapped=</span><span class="st">&quot;no&quot;</span><span class="ot"> object=</span><span class="st">&quot;LeWindow&quot;</span>/&gt;</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">object</span>&gt;</span> <span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">property</span>&gt;</span> <span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">property</span>&gt;</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>... ... ... </span></code></pre></div> <span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>... ... ... </span></code></pre></div>
<div class="sourceCode" id="cb8"><pre <div class="sourceCode" id="cb10"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1"></a><span class="dt">static</span> <span class="dt">void</span></span> class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb8-2"><a href="#cb8-2"></a>adjustment_value_changed_cb <span class="op">(</span>GtkAdjustment <span class="op">*</span>adjustment<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb10-2"><a href="#cb10-2"></a>adjustment_value_changed_cb <span class="op">(</span>GtkAdjustment <span class="op">*</span>adjustment<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-3"><a href="#cb8-3"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>user_data<span class="op">);</span></span> <span id="cb10-3"><a href="#cb10-3"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>user_data<span class="op">);</span></span>
<span id="cb8-4"><a href="#cb8-4"></a></span> <span id="cb10-4"><a href="#cb10-4"></a></span>
<span id="cb8-5"><a href="#cb8-5"></a> gtk_window_set_focus <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb10-5"><a href="#cb10-5"></a> gtk_window_set_focus <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb8-6"><a href="#cb8-6"></a><span class="op">}</span></span></code></pre></div> <span id="cb10-6"><a href="#cb10-6"></a><span class="op">}</span></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>
</body> </body>

View file

@ -1,486 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<title>GTK 4 tutorial</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre{overflow: visible;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::after
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
div.sourceCode { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
pre:not(.sourceCode) { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
table {margin-left: auto; margin-right: auto; border-collapse: collapse; border: 1px solid;}
th {padding: 2px 6px; border: 1px solid; background-color: ghostwhite;}
td {padding: 2px 6px; border: 1px solid;}
img {display: block; margin-left: auto; margin-right: auto;}
figcaption {text-align: center;}
</style>
</head>
<body style="padding-top: 70px;">
<div class="container">
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
<div class="container-fluid">
<span class="navbar-brand">Gtk4 tutorial</span>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="sec33.html">Prev: section33</a>
</li>
</ul>
</div>
</div>
</nav>
<h1 id="gtksignallistitemfactory">GtkSignalListItemFactory</h1>
<h2
id="gtksignallistitemfactory-and-gtkbulderlistitemfactory">GtkSignalListItemFactory
and GtkBulderListItemFactory</h2>
<p>GtkBuilderlistItemFactory is convenient when GtkListView just shows
the contents of a list. Its binding direction is always from an item of
a list to a child of GtkListItem.</p>
<p>When it comes to dynamic connection, its not enough. For example,
you want to edit the contents of a list. You set a child of GtkListItem
to a GtkText instance so a user can edit a text with it. You need to
bind an item in the list with the buffer of the GtkText. The direction
is opposite from the one with GtkBuilderListItemFactory. It is from the
GtkText instance to the item in the list. You can implement this with
GtkSignalListItemFactory, which is more flexible than
GtkBuilderListItemFactory.</p>
<p>Two things are shown in this section.</p>
<ul>
<li>Binding from a child of a GtkListItem instance to an item of a
list.</li>
<li>Access a child of GtkListItem dynamically. This direction is the
same as the one with GtkBulderListItemFactory. But
GtkBulderListItemFactory uses GtkExpression from the item property of
the GtkListItem. So, it updates its child widget only when the item
property changes. In this example the child reflects the change in the
same item in the list dynamically.</li>
</ul>
<p>This section shows just a part of the source file
<code>listeditor.c</code>. If you want to see the whole codes, see
<code>src/listeditor</code> directory of the <a
href="https://github.com/ToshioCP/Gtk4-tutorial">Gtk4 tutorial
repository</a>.</p>
<h2 id="a-list-editor">A list editor</h2>
<p>The sample program is a list editor and data of the list are strings.
Its the same as a line editor. It reads a text file line by line. Each
line is an item of the list. The list is displayed with GtkColumnView.
There are two columns. The one is a button, which makes the line be a
current line. If the line is the current line, the button is colored
with red. The other is a string which is the contents of the
corresponding item of the list.</p>
<figure>
<img src="image/listeditor.png" alt="List editor" />
<figcaption aria-hidden="true">List editor</figcaption>
</figure>
<p>The source files are located at <code>src/listeditor</code>
directory. You can compile end execute it as follows.</p>
<ul>
<li>Download the program from the <a
href="https://github.com/ToshioCP/Gtk4-tutorial">repository</a>.</li>
<li>Change your current directory to <code>src/listeditor</code>.</li>
<li>Type the following on your commandline.</li>
</ul>
<pre><code>$ meson _build
$ ninja -C _build
$ _build/listeditor</code></pre>
<ul>
<li>Append button: appends a line after the current line, or at the last
line if no current line exists.</li>
<li>Insert button: inserts a line before the current line.</li>
<li>Remove button: removes a current line.</li>
<li>Read button: reads a file.</li>
<li>Write button: writes the contents to a file.</li>
<li>close button: close the contents.</li>
<li>quit button: quit the application.</li>
<li>Button on the select column: makes the line current.</li>
<li>String column: GtkText. You can edit a string in the field.</li>
</ul>
<p>The current line number (zero-based) is shown at the left of the tool
bar. The file name is shown at the right of the write button.</p>
<h2 id="connect-a-gtktext-instance-and-an-item-in-the-list">Connect a
GtkText instance and an item in the list</h2>
<p>The second column (GtkColumnViewColumn) sets its factory property to
GtkSignalListItemFactory. It uses three signals setup, bind and unbind.
The following is their sgnal handlers.</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>setup2_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-3"><a href="#cb2-3"></a> GtkWidget <span class="op">*</span>text <span class="op">=</span> gtk_text_new <span class="op">();</span></span>
<span id="cb2-4"><a href="#cb2-4"></a> gtk_list_item_set_child <span class="op">(</span>listitem<span class="op">,</span> GTK_WIDGET <span class="op">(</span>text<span class="op">));</span></span>
<span id="cb2-5"><a href="#cb2-5"></a> gtk_editable_set_alignment <span class="op">(</span>GTK_EDITABLE <span class="op">(</span>text<span class="op">),</span> <span class="fl">0.0</span><span class="op">);</span></span>
<span id="cb2-6"><a href="#cb2-6"></a><span class="op">}</span></span>
<span id="cb2-7"><a href="#cb2-7"></a></span>
<span id="cb2-8"><a href="#cb2-8"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb2-9"><a href="#cb2-9"></a>bind2_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-10"><a href="#cb2-10"></a> GtkWidget <span class="op">*</span>text <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> GtkEntryBuffer <span class="op">*</span>buffer <span class="op">=</span> gtk_text_get_buffer <span class="op">(</span>GTK_TEXT <span class="op">(</span>text<span class="op">));</span></span>
<span id="cb2-12"><a href="#cb2-12"></a> LeData <span class="op">*</span>data <span class="op">=</span> LE_DATA <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> GBinding <span class="op">*</span>bind<span class="op">;</span></span>
<span id="cb2-14"><a href="#cb2-14"></a></span>
<span id="cb2-15"><a href="#cb2-15"></a> gtk_editable_set_text <span class="op">(</span>GTK_EDITABLE <span class="op">(</span>text<span class="op">),</span> le_data_look_string <span class="op">(</span>data<span class="op">));</span></span>
<span id="cb2-16"><a href="#cb2-16"></a> gtk_editable_set_position <span class="op">(</span>GTK_EDITABLE <span class="op">(</span>text<span class="op">),</span> <span class="dv">0</span><span class="op">);</span></span>
<span id="cb2-17"><a href="#cb2-17"></a></span>
<span id="cb2-18"><a href="#cb2-18"></a> bind <span class="op">=</span> g_object_bind_property <span class="op">(</span>buffer<span class="op">,</span> <span class="st">&quot;text&quot;</span><span class="op">,</span> data<span class="op">,</span> <span class="st">&quot;string&quot;</span><span class="op">,</span> G_BINDING_DEFAULT<span class="op">);</span></span>
<span id="cb2-19"><a href="#cb2-19"></a> g_object_set_data <span class="op">(</span>G_OBJECT <span class="op">(</span>listitem<span class="op">),</span> <span class="st">&quot;bind&quot;</span><span class="op">,</span> bind<span class="op">);</span></span>
<span id="cb2-20"><a href="#cb2-20"></a><span class="op">}</span></span>
<span id="cb2-21"><a href="#cb2-21"></a></span>
<span id="cb2-22"><a href="#cb2-22"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb2-23"><a href="#cb2-23"></a>unbind2_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-24"><a href="#cb2-24"></a> GBinding <span class="op">*</span>bind <span class="op">=</span> G_BINDING <span class="op">(</span>g_object_get_data <span class="op">(</span>G_OBJECT <span class="op">(</span>listitem<span class="op">),</span> <span class="st">&quot;bind&quot;</span><span class="op">));</span></span>
<span id="cb2-25"><a href="#cb2-25"></a></span>
<span id="cb2-26"><a href="#cb2-26"></a> g_binding_unbind<span class="op">(</span>bind<span class="op">);</span></span>
<span id="cb2-27"><a href="#cb2-27"></a> g_object_set_data <span class="op">(</span>G_OBJECT <span class="op">(</span>listitem<span class="op">),</span> <span class="st">&quot;bind&quot;</span><span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb2-28"><a href="#cb2-28"></a><span class="op">}</span></span></code></pre></div>
<ul>
<li>1-6: <code>setup2_cb</code> is a setup signal handler on the
GtkSignalListItemFactory. This factory is inserted to the factory
property of the second GtkColumnViewColumn. The handler just creates a
GtkText instance and sets the child of <code>listitem</code> to it. The
instance will be destroyed automatically when the <code>listitem</code>
is destroyed. So, teardown signal handler isnt necessary.</li>
<li>8-20: <code>bind2_cb</code> is a bind signal handler. It is called
when the <code>listitem</code> is bound to an item in the list. The list
items are LeData instances. LeData is defined in the file
<code>listeditor.c</code> (the C source file of the list editor). It is
a child class of GObject and has two data. The one is
<code>listitem</code> which points a first column GtkListItem instance
when they are connected. Be careful that the GtkListItem instance is
<em>not</em> the <code>listitem</code> in this handler. If no
GtkListItem is connected, it is NULL. The other is <code>string</code>
which is a content of the line.
<ul>
<li>10-11: <code>text</code> is a child of the <code>listitem</code> and
it is a GtkText instance. And <code>buffer</code> is a GtkTextBuffer
instance of the <code>text</code>.</li>
<li>12: The LeData instance <code>data</code> is an item pointed by the
<code>listitem</code>.</li>
<li>15-16: Sets the text of <code>text</code> to
<code>le_data_look_string (data)</code>. le_data_look_string returns the
string of the <code>data</code> and the ownership of the string is still
taken by the <code>data</code>. So, the caller dont need to free the
string.</li>
<li>18: <code>g_object_bind_property</code> binds a property and another
object property. This line binds the “text” property of the
<code>buffer</code> (source) and the “string” property of the
<code>data</code> (destination). It is a uni-directional binding
(<code>G_BINDING_DEFAULT</code>). When a user changes the GtkText text,
the same string is immediately put into the <code>data</code>. The
function returns a GBinding instance. This binding is different from
bindings of GtkExpression. This binding needs the existence of the two
properties.</li>
<li>19: GObjec has a table. The key is a string (or GQuark) and the
value is a gpointer (pointer to any type). The function
<code>g_object_set_data</code> sets the association from the key to the
value. This line sets the association from “bind” to <code>bind</code>
instance. It makes possible for the “unbind” handler to get the
<code>bind</code> instance.</li>
</ul></li>
<li>22-28: <code>unbind2_cb</code> is a unbind signal handler.
<ul>
<li>24: Retrieves the <code>bind</code> instance from the table in the
<code>listitem</code> instance.</li>
<li>26: Unbind the binding.</li>
<li>27: Removes the value corresponds to the “bind” key.</li>
</ul></li>
</ul>
<p>This technique is not so complicated. You can use it when you make a
cell editable application.</p>
<h2 id="change-the-cell-of-gtkcolumnview-dynamically">Change the cell of
GtkColumnView dynamically</h2>
<p>Next topic is to change the GtkColumnView (or GtkListView) cells
dynamically. The example changes the color of the buttons, which are
children of GtkListItem instances, as the current line position
moves.</p>
<p>The line editor has the current position of the list.</p>
<ul>
<li>At first, no line is current.</li>
<li>When a line is appended or inserted, the line is current.</li>
<li>When the current line is deleted, no line will be current.</li>
<li>When a button in the first column of GtkColumnView is clicked, the
line will be current.</li>
<li>It is necessary to set the line status (whether current or not) when
a GtkListItem is bound to an item in the list. It is because GtkListItem
is recycled. A GtkListItem was possibly current line before but not
current after recycled. The opposite can also be happen.</li>
</ul>
<p>The button of the current line is colored with red and otherwise
white.</p>
<p>The current line has no relationship to GtkSingleSelection object.
GtkSingleSelection selects a line on the display. The current line
doesnt need to be on the display. It is possible to be on the line out
of the Window (GtkScrolledWindow). Actually, the program doesnt use
GtkSingleSelection.</p>
<p>It is necessary to know the corresponding GtkListItem instance from
the item in the list. It is the opposite direction from
<code>gtk_list_item_get_item</code> function. To accomplish this, we set
a <code>listitem</code> element of LeData to point the corresponding
GtkListItem instance. Therefore, items (LeData) in the list always know
the GtkListItem. If theres no GtkListItem bound to the item, NULL is
assigned.</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a><span class="dt">void</span></span>
<span id="cb3-2"><a href="#cb3-2"></a>select_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-3"><a href="#cb3-3"></a> LeWindow <span class="op">*</span>win <span class="op">=</span> LE_WINDOW <span class="op">(</span>gtk_widget_get_ancestor <span class="op">(</span>GTK_WIDGET <span class="op">(</span>btn<span class="op">),</span> LE_TYPE_WINDOW<span class="op">));</span></span>
<span id="cb3-4"><a href="#cb3-4"></a></span>
<span id="cb3-5"><a href="#cb3-5"></a> update_current <span class="op">(</span>win<span class="op">,</span> gtk_list_item_get_position <span class="op">(</span>listitem<span class="op">));</span></span>
<span id="cb3-6"><a href="#cb3-6"></a><span class="op">}</span></span>
<span id="cb3-7"><a href="#cb3-7"></a></span>
<span id="cb3-8"><a href="#cb3-8"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb3-9"><a href="#cb3-9"></a>setup1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-10"><a href="#cb3-10"></a> GtkWidget <span class="op">*</span>button <span class="op">=</span> gtk_button_new <span class="op">();</span></span>
<span id="cb3-11"><a href="#cb3-11"></a> gtk_list_item_set_child <span class="op">(</span>listitem<span class="op">,</span> button<span class="op">);</span></span>
<span id="cb3-12"><a href="#cb3-12"></a> gtk_widget_set_focusable <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> FALSE<span class="op">);</span></span>
<span id="cb3-13"><a href="#cb3-13"></a> g_signal_connect <span class="op">(</span>button<span class="op">,</span> <span class="st">&quot;clicked&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>select_cb<span class="op">),</span> listitem<span class="op">);</span></span>
<span id="cb3-14"><a href="#cb3-14"></a><span class="op">}</span></span>
<span id="cb3-15"><a href="#cb3-15"></a></span>
<span id="cb3-16"><a href="#cb3-16"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb3-17"><a href="#cb3-17"></a>bind1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<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="cb3-18"><a href="#cb3-18"></a> LeWindow <span class="op">*</span>win <span class="op">=</span> LE_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span>
<span id="cb3-19"><a href="#cb3-19"></a> GtkWidget <span class="op">*</span>button <span class="op">=</span> gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">);</span></span>
<span id="cb3-20"><a href="#cb3-20"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>non_current<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span>NULL<span class="op">};</span></span>
<span id="cb3-21"><a href="#cb3-21"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>current<span class="op">[</span><span class="dv">2</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="st">&quot;current&quot;</span><span class="op">,</span> NULL<span class="op">};</span></span>
<span id="cb3-22"><a href="#cb3-22"></a> LeData <span class="op">*</span>data <span class="op">=</span> LE_DATA <span class="op">(</span>gtk_list_item_get_item <span class="op">(</span>listitem<span class="op">));</span></span>
<span id="cb3-23"><a href="#cb3-23"></a></span>
<span id="cb3-24"><a href="#cb3-24"></a> <span class="cf">if</span> <span class="op">(</span>data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-25"><a href="#cb3-25"></a> le_data_set_listitem <span class="op">(</span>data<span class="op">,</span> listitem<span class="op">);</span></span>
<span id="cb3-26"><a href="#cb3-26"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-&gt;</span>position <span class="op">==</span> gtk_list_item_get_position <span class="op">(</span>listitem<span class="op">))</span></span>
<span id="cb3-27"><a href="#cb3-27"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> current<span class="op">);</span></span>
<span id="cb3-28"><a href="#cb3-28"></a> <span class="cf">else</span></span>
<span id="cb3-29"><a href="#cb3-29"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> non_current<span class="op">);</span></span>
<span id="cb3-30"><a href="#cb3-30"></a> <span class="op">}</span></span>
<span id="cb3-31"><a href="#cb3-31"></a><span class="op">}</span></span>
<span id="cb3-32"><a href="#cb3-32"></a></span>
<span id="cb3-33"><a href="#cb3-33"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb3-34"><a href="#cb3-34"></a>unbind1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-35"><a href="#cb3-35"></a> LeData <span class="op">*</span>data <span class="op">=</span> LE_DATA <span class="op">(</span>gtk_list_item_get_item <span class="op">(</span>listitem<span class="op">));</span></span>
<span id="cb3-36"><a href="#cb3-36"></a> <span class="cf">if</span> <span class="op">(</span>data<span class="op">)</span></span>
<span id="cb3-37"><a href="#cb3-37"></a> le_data_set_listitem <span class="op">(</span>data<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb3-38"><a href="#cb3-38"></a><span class="op">}</span></span></code></pre></div>
<ul>
<li>8-14: <code>setup1_cb</code> is a setup signal handler on the
GtkSignalListItemFactory. This factory is inserted to the factory
property of the first GtkColumnViewColumn. It sets the child of
<code>listitem</code> to a GtkButton instance. The “clicked” signal on
the button is connected to the handler <code>select_cb</code>. When the
listitem is destroyed, the child (GtkButton) is also destroyed. At the
same time, the connection of the signal and the handler is also
destroyed. So, you dont need teardown signal handler.</li>
<li>1-6: <code>select_cb</code> is a “clicked” signal handler. LeWindow
is defined in <code>listeditor.c</code>. Its a child class of
GtkApplicationWindow. The handler just calls the
<code>update_current</code> function. The function will be explained
later.</li>
<li>16-31: <code>bind1_cb</code> is a bind signal handler. It sets the
“listitem” element of the item (LeData) to point the
<code>listitem</code> (GtkListItem instance). It makes the item possible
to find the corresponding GtkListItem instance. If the item is the
current line, the CSS class of the button includes “current” class.
Otherwise it has no CSS class. This is necessary because the button may
be recycled and it has had former CSS class. The class need to be
updated.</li>
<li>33-38: <code>unbind1_cb</code> is an unbind signal handler. It
removes the <code>listitem</code> instance from the “listitem” element
of the item. The element becomes NULL, which tells no GtkListItem is
bound. When referring GtkListItem, it needs to check the “listitem”
element whether it points a GtkListItem or not (NULL). Otherwise bad
things will happen.</li>
</ul>
<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="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-2"><a href="#cb4-2"></a>update_current <span class="op">(</span>LeWindow <span class="op">*</span>win<span class="op">,</span> <span class="dt">int</span> new<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-3"></a> <span class="dt">char</span> <span class="op">*</span>s<span class="op">;</span></span>
<span id="cb4-4"><a href="#cb4-4"></a> LeData <span class="op">*</span>data<span class="op">;</span></span>
<span id="cb4-5"><a href="#cb4-5"></a> GtkListItem <span class="op">*</span>listitem<span class="op">;</span></span>
<span id="cb4-6"><a href="#cb4-6"></a> GtkButton <span class="op">*</span>button<span class="op">;</span></span>
<span id="cb4-7"><a href="#cb4-7"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>non_current<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span>NULL<span class="op">};</span></span>
<span id="cb4-8"><a href="#cb4-8"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>current<span class="op">[</span><span class="dv">2</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="st">&quot;current&quot;</span><span class="op">,</span> NULL<span class="op">};</span></span>
<span id="cb4-9"><a href="#cb4-9"></a></span>
<span id="cb4-10"><a href="#cb4-10"></a> <span class="cf">if</span> <span class="op">(</span>new <span class="op">&gt;=</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb4-11"><a href="#cb4-11"></a> s <span class="op">=</span> g_strdup_printf <span class="op">(</span><span class="st">&quot;%d&quot;</span><span class="op">,</span> new<span class="op">);</span></span>
<span id="cb4-12"><a href="#cb4-12"></a> <span class="cf">else</span></span>
<span id="cb4-13"><a href="#cb4-13"></a> s <span class="op">=</span> <span class="st">&quot;&quot;</span><span class="op">;</span></span>
<span id="cb4-14"><a href="#cb4-14"></a> gtk_label_set_text <span class="op">(</span>GTK_LABEL <span class="op">(</span>win<span class="op">-&gt;</span>position_label<span class="op">),</span> s<span class="op">);</span></span>
<span id="cb4-15"><a href="#cb4-15"></a> <span class="cf">if</span> <span class="op">(*</span>s<span class="op">)</span> <span class="co">// s isn&#39;t an empty string</span></span>
<span id="cb4-16"><a href="#cb4-16"></a> g_free <span class="op">(</span>s<span class="op">);</span></span>
<span id="cb4-17"><a href="#cb4-17"></a></span>
<span id="cb4-18"><a href="#cb4-18"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-&gt;</span>position <span class="op">&gt;=</span><span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-19"><a href="#cb4-19"></a> data <span class="op">=</span> LE_DATA <span class="op">(</span>g_list_model_get_item <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>win<span class="op">-&gt;</span>liststore<span class="op">),</span> win<span class="op">-&gt;</span>position<span class="op">));</span></span>
<span id="cb4-20"><a href="#cb4-20"></a> <span class="cf">if</span> <span class="op">((</span>listitem <span class="op">=</span> le_data_get_listitem <span class="op">(</span>data<span class="op">))</span> <span class="op">!=</span> NULL<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-21"><a href="#cb4-21"></a> button <span class="op">=</span> GTK_BUTTON <span class="op">(</span>gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">));</span></span>
<span id="cb4-22"><a href="#cb4-22"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> non_current<span class="op">);</span></span>
<span id="cb4-23"><a href="#cb4-23"></a> g_object_unref <span class="op">(</span>listitem<span class="op">);</span></span>
<span id="cb4-24"><a href="#cb4-24"></a> <span class="op">}</span></span>
<span id="cb4-25"><a href="#cb4-25"></a> g_object_unref <span class="op">(</span>data<span class="op">);</span></span>
<span id="cb4-26"><a href="#cb4-26"></a> <span class="op">}</span></span>
<span id="cb4-27"><a href="#cb4-27"></a> win<span class="op">-&gt;</span>position <span class="op">=</span> new<span class="op">;</span></span>
<span id="cb4-28"><a href="#cb4-28"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-&gt;</span>position <span class="op">&gt;=</span><span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-29"><a href="#cb4-29"></a> data <span class="op">=</span> LE_DATA <span class="op">(</span>g_list_model_get_item <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>win<span class="op">-&gt;</span>liststore<span class="op">),</span> win<span class="op">-&gt;</span>position<span class="op">));</span></span>
<span id="cb4-30"><a href="#cb4-30"></a> <span class="cf">if</span> <span class="op">((</span>listitem <span class="op">=</span> le_data_get_listitem <span class="op">(</span>data<span class="op">))</span> <span class="op">!=</span> NULL<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-31"><a href="#cb4-31"></a> button <span class="op">=</span> GTK_BUTTON <span class="op">(</span>gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">));</span></span>
<span id="cb4-32"><a href="#cb4-32"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> current<span class="op">);</span></span>
<span id="cb4-33"><a href="#cb4-33"></a> g_object_unref <span class="op">(</span>listitem<span class="op">);</span></span>
<span id="cb4-34"><a href="#cb4-34"></a> <span class="op">}</span></span>
<span id="cb4-35"><a href="#cb4-35"></a> g_object_unref <span class="op">(</span>data<span class="op">);</span></span>
<span id="cb4-36"><a href="#cb4-36"></a> <span class="op">}</span></span>
<span id="cb4-37"><a href="#cb4-37"></a><span class="op">}</span></span></code></pre></div>
<p>The function <code>update_current</code> does several things.</p>
<ul>
<li>It has two parameters. The first one is <code>win</code>, which is
an instance of LeWindow class. It has some elements.
<ul>
<li>win-&gt;position: an Integer. it is the current position. If no
current line exists, it is -1.</li>
<li>win-&gt;position_label: GtkLabel. It shows the current
position.</li>
</ul></li>
<li>The second parameter is <code>new</code>, which is the new current
position. At the beginning of the function, win-&gt;position points the
old position.</li>
<li>10-16: Update the text of GtkLabel.</li>
<li>18-26: If the old position (win-&gt;position) is not negative, the
current line exists. It gets a GtkListItem instance via the item
(LeData) of the list. And it gets the GtkButton instance which is the
child of the GtkListItem. It clears the “css-classes” property of the
button.</li>
<li>27: Updates win-&gt;position.</li>
<li>28-36: If the new position is not negative (Its possible to be
negative when the current line has been removed), the current line
exists. It sets the “css-classes” property of the button to
<code>{"current", NULL}</code>. It is a NULL-terminated array of
strings. Each string is a CSS class. Now the button has “current” style
class.</li>
</ul>
<p>The color of buttons are determined by the “background” CSS style.
The following CSS is applied to the default GdkDisplay in advance (in
the startup handler of the application).</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode css"><code class="sourceCode css"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>columnview listview row button<span class="fu">.current</span> {<span class="kw">background</span>: <span class="cn">red</span><span class="op">;</span>}</span></code></pre></div>
<p>The selectors “columnview listview row” is needed before “button”
selector. Otherwise the buttons in the GtkColumnview wont be found. The
button selector has “current” class. So, the only “current” class button
is colored with red. Other buttons are not colored, which means they are
white.</p>
<h2
id="gtk_widget_dispose_template-function">Gtk_widget_dispose_template
function</h2>
<p>The function <code>gtk_widget_dispose_template</code> clears the
template children for the given widget. This is the opposite of
<code>gtk_widget_init_template()</code>. It is a new function of GTK 4.8
version. If your GTK version is lower than 4.8, you need to modify the
program.</p>
<h2 id="a-waring-from-gtktext">A waring from GtkText</h2>
<p>If your program has the following two, a warning message can be
issued.</p>
<ul>
<li>The list has many items and it needs to be scrolled.</li>
<li>A GtkText instance is the focus widget.</li>
</ul>
<pre><code>GtkText - unexpected blinking selection. Removing</code></pre>
<p>I dont have an exact idea why this happens. But if GtkText
“focusable” property is FALSE, the warning doesnt happen. So it
probably comes from focus and scroll.</p>
<p>You can avoid this by unsetting any focus widget under the main
window. When scroll begins, the “value-changed” signal on the vertical
adjustment of the scrolled window is emitted.</p>
<p>The following is extracted from the ui file and C source file.</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode xml"><code class="sourceCode xml"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>... ... ...</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkScrolledWindow&quot;</span>&gt;</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></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="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></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="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;vadjustment&quot;</span>&gt;</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkAdjustment&quot;</span>&gt;</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">signal</span><span class="ot"> name=</span><span class="st">&quot;value-changed&quot;</span><span class="ot"> handler=</span><span class="st">&quot;adjustment_value_changed_cb&quot;</span><span class="ot"> swapped=</span><span class="st">&quot;no&quot;</span><span class="ot"> object=</span><span class="st">&quot;LeWindow&quot;</span>/&gt;</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a> &lt;/<span class="kw">property</span>&gt;</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>... ... ... </span></code></pre></div>
<div class="sourceCode" id="cb8"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb8-2"><a href="#cb8-2"></a>adjustment_value_changed_cb <span class="op">(</span>GtkAdjustment <span class="op">*</span>adjustment<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-3"><a href="#cb8-3"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>user_data<span class="op">);</span></span>
<span id="cb8-4"><a href="#cb8-4"></a></span>
<span id="cb8-5"><a href="#cb8-5"></a> gtk_window_set_focus <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb8-6"><a href="#cb8-6"></a><span class="op">}</span></span></code></pre></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</body>
</html>

View file

@ -8,9 +8,10 @@ The new feature is described in [Gtk API Reference -- List Widget Overview](http
GTK 4 has other means to implement lists. GTK 4 has other means to implement lists.
They are GtkListBox and GtkTreeView which are took over from GTK 3. They are GtkListBox and GtkTreeView which are took over from GTK 3.
There's an article in [Gtk Development blog](https://blog.gtk.org/2020/06/07/scalable-lists-in-gtk-4/) about list widgets by Matthias Clasen. There's an article in [Gtk Development blog](https://blog.gtk.org/2020/06/07/scalable-lists-in-gtk-4/) about list widgets by Matthias Clasen.
He described why GtkListView are developed to replace GtkListBox and GtkTreeView. He described why GtkListView are developed to replace GtkTreeView.
GtkTreeView is deprecated since version 4.10.
GtkListView, GtkGridView, GtkColumnView and related objects are described in Section 26 to 29. GtkListView, GtkGridView, GtkColumnView and related objects are described in Section 29 to 33.
## Outline ## Outline
@ -21,7 +22,7 @@ A list is like an array, but in many cases it is implemented with pointers which
And it has a start point. And it has a start point.
So, each item can be referred by the index of the item (first item, second item, ..., nth item, ...). So, each item can be referred by the index of the item (first item, second item, ..., nth item, ...).
There are two cases. There are two cases.
One is the index starts from one (one-based) and the other is from zero (zero-based). The 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 and its items are 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.
@ -29,11 +30,11 @@ 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 instance maps items in the list to GListView. GtkListItemFactory instance maps items in the list to GtkListView.
![List](../image/list.png) ![List](../image/list.png)
## GListModel ## GListModel and GtkStringList
If you want to make a list of strings with GListModel, for example, "one", "two", "three", "four", note that strings can't be items of the list. If you want to make a list of strings with GListModel, for example, "one", "two", "three", "four", note that strings can't be items of the list.
Because GListModel is a list of GObject objects and strings aren't GObject objects. Because GListModel is a list of GObject objects and strings aren't GObject objects.
@ -253,7 +254,7 @@ There is an explanation in the [GTK Development Blog](https://blog.gtk.org/2020/
> 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.
Therefore, GtkListItem instance is used as the `this` object of the lookup tag when it is evaluated. Therefore, GtkListItem instance is used as the `this` object of the lookup tag when it is evaluated.
`this` object will be explained in [section 30](../src/sec30). `this` object will be explained in [section 31](../src/sec31).
The C source code is as follows. The C source code is as follows.
Its name is `list2.c` and located under [src/misc](../src/misc) directory. Its name is `list2.c` and located under [src/misc](../src/misc) directory.
@ -370,7 +371,7 @@ Instead, closure tag is appropriate in this case.
Closure tag specifies a function and the type of the return value of the function. Closure tag specifies a function and the type of the return value of the function.
~~~C ~~~C
const char * char *
get_file_name (GtkListItem *item, GFileInfo *info) { get_file_name (GtkListItem *item, GFileInfo *info) {
return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL; return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
} }
@ -406,7 +407,7 @@ The contents of closure tag (it is between \<closure...\> and\</closure\>) is pa
`<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, which is a 'this' object. The first parameter is always the GListItem instance, which is a 'this' object.
The 'this' object is explained in section 28. The 'this' object is explained in section 31.
- `gtk_file_name` function is the callback function for the closure tag. - `gtk_file_name` function is the callback function for the closure tag.
It first checks the `info` parameter. 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.
@ -531,5 +532,4 @@ $ ./a.out
![screenshot list3](../image/list3.png) ![screenshot list3](../image/list3.png)
Up: [README.md](../README.md), Prev: [Section 28](sec28.md), Next: [Section 30](sec30.md) Up: [README.md](../README.md), Prev: [Section 28](sec28.md), Next: [Section 30](sec30.md)

View file

@ -64,7 +64,7 @@ Such "x-" subtype is not a standard mime type.)
Content type is also used by desktop systems. Content type is also used by desktop systems.
GtkGridView uses the same GtkSingleSelection instance (`singleselection`). GtkGridView uses the same GtkSingleSelection instance (`singleselection`).
So, its model property is set with it. So, its model property is set to it.
## Ui file of the window ## Ui file of the window
@ -467,7 +467,7 @@ The last parameter is the pointer to the pointer to a GError.
If your distribution supports GTK 4, using `g_app_info_launch_default_for_uri` is convenient. If your distribution supports GTK 4, using `g_app_info_launch_default_for_uri` is convenient.
The function automatically determines the default application from the file and launches it. The function automatically determines the default application from the file and launches it.
For example, if the file is text, then it launches gedit with the file. For example, if the file is text, then it launches GNOME text editor with the file.
Such feature comes from desktop. Such feature comes from desktop.
## Compilation and execution ## Compilation and execution
@ -477,7 +477,7 @@ To compile and execute list4, type as follows.
~~~ ~~~
$ cd list4 # or cd src/list4. It depends your current directory. $ cd list4 # or cd src/list4. It depends your current directory.
$ meson _build $ meson setup _build
$ ninja -C _build $ ninja -C _build
$ _build/list4 $ _build/list4
~~~ ~~~

View file

@ -58,8 +58,8 @@ The type of the value is int.
|G\_TYPE\_INT |int |gint | | |G\_TYPE\_INT |int |gint | |
|G\_TYPE\_FLOAT |float |gfloat | | |G\_TYPE\_FLOAT |float |gfloat | |
|G\_TYPE\_DOUBLE |double|gdouble | | |G\_TYPE\_DOUBLE |double|gdouble | |
|G\_TYPE\_POINTER | |gpointer | | |G\_TYPE\_POINTER |void *|gpointer |general pointer |
|G\_TYPE\_STRING | |gchararray|null-terminated Cstring| |G\_TYPE\_STRING |char *|gchararray|null-terminated Cstring|
|G\_TYPE\_OBJECT | |GObject | | |G\_TYPE\_OBJECT | |GObject | |
|GTK\_TYPE\_WINDOW| |GtkWindow | | |GTK\_TYPE\_WINDOW| |GtkWindow | |
@ -119,7 +119,7 @@ expression = gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "l
If `expression` is evaluated, the second parameter `another_expression` is evaluated in advance. If `expression` is evaluated, the second parameter `another_expression` is evaluated in advance.
The value of `another_expression` is the `label` (GtkLabel instance). The value of `another_expression` is the `label` (GtkLabel instance).
Then, `expression` looks up "label" property of the label and the evaluation results "Hello". Then, `expression` looks up "label" property of the label and the evaluation results in "Hello".
In the example above, the second argument of `gtk_property_expression_new` is another expression. In the example above, the second argument of `gtk_property_expression_new` is another expression.
But the second argument can be NULL. But the second argument can be NULL.
@ -145,7 +145,7 @@ There's a simple program `exp_property_simple.c` in `src/expression` directory.
14 if (gtk_expression_evaluate (expression, label, &value)) 14 if (gtk_expression_evaluate (expression, label, &value))
15 g_print ("The value is %s.\n", g_value_get_string (&value)); 15 g_print ("The value is %s.\n", g_value_get_string (&value));
16 else 16 else
17 g_print ("The constant expression wasn't evaluated correctly.\n"); 17 g_print ("The property expression wasn't evaluated correctly.\n");
18 gtk_expression_unref (expression); 18 gtk_expression_unref (expression);
19 g_value_unset (&value); 19 g_value_unset (&value);
20 20
@ -164,7 +164,7 @@ The expression just knows how to take the property from a future-given GtkLabel
The result is stored in the GValue `value`. The result is stored in the GValue `value`.
The function `g_value_get_string` gets a string from the GValue. The function `g_value_get_string` gets a string from the GValue.
But the string is owned by the GValue so you must not free the string. But the string is owned by the GValue so you must not free the string.
- 18-19: Release the expression and unset the GValue. - 18-19: Releases the expression and unset the GValue.
At the same time the string in the GValue is freed. At the same time the string in the GValue is freed.
If the second argument of `gtk_property_expression_new` isn't NULL, it is another expression. If the second argument of `gtk_property_expression_new` isn't NULL, it is another expression.
@ -195,6 +195,18 @@ gtk_cclosure_expression_new (GType value_type,
gpointer user_data, gpointer user_data,
GClosureNotify user_destroy); GClosureNotify user_destroy);
~~~ ~~~
@else
~~~{.C}
GtkExpression *
gtk_cclosure_expression_new (GType value_type,
GClosureMarshal marshal,
guint n_params,
GtkExpression **params,
GCallback callback_func,
gpointer user_data,
GClosureNotify user_destroy);
~~~
@end
- `value_type` is the type of the value when it is evaluated. - `value_type` is the type of the value when it is evaluated.
- `marshal` is a marshaller. - `marshal` is a marshaller.
@ -224,6 +236,7 @@ callback (this, param1, param2, ...)
For example, For example,
@@@if gfm
~~~C ~~~C
int int
callback (GObject *object, int x, const char *s) callback (GObject *object, int x, const char *s)
@ -276,13 +289,13 @@ If you want to return error report, change the return value type to be a pointer
One for error and the other for the sum. One for error and the other for the sum.
The first argument of `gtk_cclosure_expression_new` is `G_TYPE_POINTER`. The first argument of `gtk_cclosure_expression_new` is `G_TYPE_POINTER`.
There is a sample program `exp_closure_with_error_report` in `src/expression` directory. There is a sample program `exp_closure_with_error_report` in `src/expression` directory.
- 19: gtk\_init initializes GTK. It is necessary for GtkLabel. - 19: The function `gtk_init`` initializes GTK. It is necessary for GtkLabel.
- 20: A GtkLabel instance is created with "123+456". - 20: A GtkLabel instance is created with "123+456".
- 21: The instance has floating reference. It is changed to an ordinary reference count. - 21: The instance has floating reference. It is changed to an ordinary reference count.
- 22-23: Create a closure expression. Its return value type is `G_TYPE_INT` and no parameters or 'this' object. - 22-23: Creates a closure expression. Its return value type is `G_TYPE_INT` and no parameters or 'this' object.
- 24: Evaluates the expression with the label as a 'this' object. - 24: Evaluates the expression with the label as a 'this' object.
- 25: If the evaluation successes, show the sum of "123+456". It's 579. - 25: If the evaluation successes, the sum of "123+456", which is 579, is shown.
- 27: If it fails, show an error message. - 27: If it fails, an error message appears.
- 28-30: Releases the expression and the label. Unsets the value. - 28-30: Releases the expression and the label. Unsets the value.
Closure expression is flexible than other type of expression because you can specify your own callback function. Closure expression is flexible than other type of expression because you can specify your own callback function.
@ -292,6 +305,7 @@ Closure expression is flexible than other type of expression because you can spe
GtkExpressionWatch is a structure, not an object. GtkExpressionWatch is a structure, not an object.
It represents a watched GtkExpression. It represents a watched GtkExpression.
Two functions create GtkExpressionWatch structure. Two functions create GtkExpressionWatch structure.
They are `gtk_expression_bind` and `gtk_expression_watch`.
### gtk\_expression\_bind function ### gtk\_expression\_bind function
@ -411,7 +425,7 @@ For example, if it is zero, the slider moves to an integer point.
28 GtkExpression *expression, *params[1]; 28 GtkExpression *expression, *params[1];
29 29
30 /* Builds a window with exp.ui resource */ 30 /* Builds a window with exp.ui resource */
31 build = gtk_builder_new_from_file ("exp_bind.ui"); 31 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/exp/exp_bind.ui");
32 win = GTK_WIDGET (gtk_builder_get_object (build, "win")); 32 win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
33 label = GTK_WIDGET (gtk_builder_get_object (build, "label")); 33 label = GTK_WIDGET (gtk_builder_get_object (build, "label"));
34 // scale = GTK_WIDGET (gtk_builder_get_object (build, "scale")); 34 // scale = GTK_WIDGET (gtk_builder_get_object (build, "scale"));
@ -448,7 +462,7 @@ The point of the program is:
- 41-42: Two expressions are defined. - 41-42: Two expressions are defined.
One is a property expression and the other is a closure expression. One is a property expression and the other is a closure expression.
The property expression look up the "value"property of the adjustment instance. The property expression looks up the "value" property of the adjustment instance.
The closure expression just converts the double into an integer. The closure expression just converts the double into an integer.
- 43: `gtk_expression_bind` binds the label property of the GtkLabel instance to the integer returned by the closure expression. - 43: `gtk_expression_bind` binds the label property of the GtkLabel instance to the integer returned by the closure expression.
It creates a GtkExpressionWatch structure. It creates a GtkExpressionWatch structure.
@ -462,8 +476,8 @@ This signal is emitted when the close button is clicked.
The handler is called just before the window closes. The handler is called just before the window closes.
It is the right moment to make the GtkExpressionWatch unwatched. It is the right moment to make the GtkExpressionWatch unwatched.
- 10-14: "close-request" signal handler. - 10-14: "close-request" signal handler.
`gtk_expression_watch_unwatch (watch)` makes the watch stop watching the expression. The function `gtk_expression_watch_unwatch (watch)` makes the watch stop watching the expression.
It releases the expression and calls `gtk_expression_watch_unref (watch)` in it. It also releases the expression.
If you want to bind a property to an expression, `gtk_expression_bind` is the best choice. If you want to bind a property to an expression, `gtk_expression_bind` is the best choice.
You can do it with `gtk_expression_watch` function, but it is less suitable. You can do it with `gtk_expression_watch` function, but it is less suitable.
@ -619,7 +633,7 @@ These tags are usually used for GtkBuilderListItemFactory.
<property name="child"> <property name="child">
<object class="GtkLabel"> <object class="GtkLabel">
<binding name="label"> <binding name="label">
<lookup name="name" type="string"> <lookup name="string" type="GtkStringObject">
<lookup name="item">GtkListItem</lookup> <lookup name="item">GtkListItem</lookup>
</lookup> </lookup>
</binding> </binding>
@ -629,14 +643,13 @@ These tags are usually used for GtkBuilderListItemFactory.
</interface> </interface>
~~~ ~~~
GtkBuilderListItemFactory uses GtkBuilder to extends the GtkListItem with the XML data.
In the xml file above, "GtkListItem" is an instance of the GtkListItem template. In the xml file above, "GtkListItem" is an instance of the GtkListItem template.
It is the 'this' object given to the expressions. It is the 'this' object given to the expressions.
(The information is in the [GTK Development Blog](https://blog.gtk.org/2020/09/)). (The information is in the [GTK Development Blog](https://blog.gtk.org/2020/09/)).
GtkBuilderListItemFactory uses GtkBuilder to build the XML data. GtkBuilder calls `gtk_expression_bind` function when it finds a binding tag.
It sets the current object of the GtkBuilder to the GtkListItem instance.
GtkBuilder calls `gtk_expression_bind` function in the binding tag analysis.
The function sets the 'this' object like this: The function sets the 'this' object like this:
1. If the binding tag has object attribute, the object will be the 'this' object. 1. If the binding tag has object attribute, the object will be the 'this' object.
@ -760,7 +773,7 @@ String duplication is necessary.
The C source file is very simple because almost everything is done in the ui file. The C source file is very simple because almost everything is done in the ui file.
### Conversion between GValues ## Conversion between GValues
If you bind different type properties, type conversion is automatically done. If you bind different type properties, type conversion is automatically done.
Suppose a label property (string) is bound to default-width property (int). Suppose a label property (string) is bound to default-width property (int).
@ -782,4 +795,43 @@ If the current width is 100, an int `100` is converted to a string `"100"`.
If you use `g_object_get` and `g_object_set` to copy properties, the value is automatically converted. If you use `g_object_get` and `g_object_set` to copy properties, the value is automatically converted.
## Meson.build
The source files are in `src/expression` directory.
You can build all the files at once.
~~~
$ cd src/expression
$ meson setup _build
$ ninja -C _build
~~~
For example, if you want to run "exp", which is the executable file from "exp.c", type `_build/exp`.
You can run other programs as well.
The file `meson.build` is as follows.
~~~meson
1 project('exp', 'c')
2
3 gtkdep = dependency('gtk4')
4
5 gnome=import('gnome')
6 resources = gnome.compile_resources('resources','exp.gresource.xml')
7
8 sourcefiles=files('exp.c')
9
10 executable('exp', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true, install: false)
11 executable('exp_constant', 'exp_constant.c', dependencies: gtkdep, export_dynamic: true, install: false)
12 executable('exp_constant_simple', 'exp_constant_simple.c', dependencies: gtkdep, export_dynamic: true, install: false)
13 executable('exp_property_simple', 'exp_property_simple.c', dependencies: gtkdep, export_dynamic: true, install: false)
14 executable('closure', 'closure.c', dependencies: gtkdep, export_dynamic: true, install: false)
15 executable('closure_each', 'closure_each.c', dependencies: gtkdep, export_dynamic: true, install: false)
16 executable('exp_closure_simple', 'exp_closure_simple.c', dependencies: gtkdep, export_dynamic: true, install: false)
17 executable('exp_closure_with_error_report', 'exp_closure_with_error_report.c', dependencies: gtkdep, export_dynamic: true, install: false)
18 executable('exp_bind', 'exp_bind.c', resources, dependencies: gtkdep, export_dynamic: true, install: false)
19 executable('exp_watch', 'exp_watch.c', dependencies: gtkdep, export_dynamic: true, install: false)
20 executable('exp_test', 'exp_test.c', resources, dependencies: gtkdep, export_dynamic: true, install: false)
~~~
Up: [README.md](../README.md), Prev: [Section 30](sec30.md), Next: [Section 32](sec32.md) Up: [README.md](../README.md), Prev: [Section 30](sec30.md), Next: [Section 32](sec32.md)

View file

@ -218,9 +218,9 @@ This is the title on the header of the column.
- 32: Sets the "expand" property to TRUE to allow the column to expand as much as possible. - 32: Sets the "expand" property to TRUE to allow the column to expand as much as possible.
(See the image above). (See the image above).
- 33- 69: Sets the "factory" property to GtkBuilderListItemFactory. - 33- 69: Sets the "factory" property to GtkBuilderListItemFactory.
The factory has "bytes" property which holds a ui string to define a template to build GtkListItem composite widget. The factory has "bytes" property which holds a ui string to define a template to extend GtkListItem class.
The CDATA section (line 36-66) is the ui string to put into the "bytes" property. The CDATA section (line 36-66) is the ui string to put into the "bytes" property.
The contents are the same as the ui file `factory_list.ui` in the section 27. The contents are the same as the ui file `factory_list.ui` in the section 30.
- 70-77: Sets the "sorter" property to GtkStringSorter object. - 70-77: Sets the "sorter" property to GtkStringSorter object.
This object provides a sorter that compares strings. This object provides a sorter that compares strings.
It has "expression" property. It has "expression" property.
@ -456,7 +456,8 @@ All the source files are in [`src/column`](../src/column) directory.
Change your current directory to the directory and type the following. Change your current directory to the directory and type the following.
~~~ ~~~
$ meson _build $ cd src/colomn
$ meson setup _build
$ ninja -C _build $ ninja -C _build
$ _build/column $ _build/column
~~~ ~~~

View file

@ -8,23 +8,14 @@ GtkBuilderlistItemFactory is convenient when GtkListView just shows the contents
Its binding direction is always from an item of a list to a child of GtkListItem. Its binding direction is always from an item of a list to a child of GtkListItem.
When it comes to dynamic connection, it's not enough. When it comes to dynamic connection, it's not enough.
For example, you want to edit the contents of a list. For example, suppose you want to edit the contents of a list.
You set a child of GtkListItem to a GtkText instance so a user can edit a text with it. You set a child of GtkListItem to a GtkText instance so a user can edit a text with it.
You need to bind an item in the list with the buffer of the GtkText. You need to bind an item in the list with the buffer of the GtkText.
The direction is opposite from the one with GtkBuilderListItemFactory. The direction is opposite from the one with GtkBuilderListItemFactory.
It is from the GtkText instance to the item in the list. It is from the GtkText instance to the item in the list.
You can implement this with GtkSignalListItemFactory, which is more flexible than GtkBuilderListItemFactory. You can implement this with GtkSignalListItemFactory, which is more flexible than GtkBuilderListItemFactory.
Two things are shown in this section. This section shows just some parts of the source file `listeditor.c`.
- Binding from a child of a GtkListItem instance to an item of a list.
- Access a child of GtkListItem dynamically.
This direction is the same as the one with GtkBulderListItemFactory.
But GtkBulderListItemFactory uses GtkExpression from the item property of the GtkListItem.
So, it updates its child widget only when the item property changes.
In this example the child reflects the change in the same item in the list dynamically.
This section shows just a part of the source file `listeditor.c`.
If you want to see the whole codes, see `src/listeditor` directory of the [Gtk4 tutorial repository](https://github.com/ToshioCP/Gtk4-tutorial). If you want to see the whole codes, see `src/listeditor` directory of the [Gtk4 tutorial repository](https://github.com/ToshioCP/Gtk4-tutorial).
## A list editor ## A list editor
@ -35,7 +26,7 @@ It reads a text file line by line.
Each line is an item of the list. Each line is an item of the list.
The list is displayed with GtkColumnView. The list is displayed with GtkColumnView.
There are two columns. There are two columns.
The one is a button, which makes the line be a current line. The one is a button, which shows if the line is a current line.
If the line is the current line, the button is colored with red. If the line is the current line, the button is colored with red.
The other is a string which is the contents of the corresponding item of the list. The other is a string which is the contents of the corresponding item of the list.
@ -49,18 +40,18 @@ You can compile end execute it as follows.
- Type the following on your commandline. - Type the following on your commandline.
~~~ ~~~
$ meson _build $ meson setup _build
$ ninja -C _build $ ninja -C _build
$ _build/listeditor $ _build/listeditor
~~~ ~~~
- Append button: appends a line after the current line, or at the last line if no current line exists. - Append button: appends a line after the current line, or at the last line if no current line exists.
- Insert button: inserts a line before the current line. - Insert button: inserts a line before the current line, or at the top line if no current line exists.
- Remove button: removes a current line. - Remove button: removes a current line.
- Read button: reads a file. - Read button: reads a file.
- Write button: writes the contents to a file. - Write button: writes the contents to a file.
- close button: close the contents. - close button: closes the contents.
- quit button: quit the application. - quit button: quits the application.
- Button on the select column: makes the line current. - Button on the select column: makes the line current.
- String column: GtkText. You can edit a string in the field. - String column: GtkText. You can edit a string in the field.
@ -71,7 +62,7 @@ The file name is shown at the right of the write button.
The second column (GtkColumnViewColumn) sets its factory property to GtkSignalListItemFactory. The second column (GtkColumnViewColumn) sets its factory property to GtkSignalListItemFactory.
It uses three signals setup, bind and unbind. It uses three signals setup, bind and unbind.
The following is their sgnal handlers. The following shows the signal handlers.
~~~C ~~~C
1 static void 1 static void
@ -85,7 +76,7 @@ The following is their sgnal handlers.
9 bind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) { 9 bind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
10 GtkWidget *text = gtk_list_item_get_child (listitem); 10 GtkWidget *text = gtk_list_item_get_child (listitem);
11 GtkEntryBuffer *buffer = gtk_text_get_buffer (GTK_TEXT (text)); 11 GtkEntryBuffer *buffer = gtk_text_get_buffer (GTK_TEXT (text));
12 LeData *data = LE_DATA (gtk_list_item_get_item (listitem)); 12 LeData *data = LE_DATA (gtk_list_item_get_item(listitem));
13 GBinding *bind; 13 GBinding *bind;
14 14
15 gtk_editable_set_text (GTK_EDITABLE (text), le_data_look_string (data)); 15 gtk_editable_set_text (GTK_EDITABLE (text), le_data_look_string (data));
@ -99,9 +90,10 @@ The following is their sgnal handlers.
23 unbind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) { 23 unbind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
24 GBinding *bind = G_BINDING (g_object_get_data (G_OBJECT (listitem), "bind")); 24 GBinding *bind = G_BINDING (g_object_get_data (G_OBJECT (listitem), "bind"));
25 25
26 g_binding_unbind(bind); 26 if (bind)
27 g_object_set_data (G_OBJECT (listitem), "bind", NULL); 27 g_binding_unbind(bind);
28 } 28 g_object_set_data (G_OBJECT (listitem), "bind", NULL);
29 }
~~~ ~~~
- 1-6: `setup2_cb` is a setup signal handler on the GtkSignalListItemFactory. - 1-6: `setup2_cb` is a setup signal handler on the GtkSignalListItemFactory.
@ -113,17 +105,13 @@ So, teardown signal handler isn't necessary.
It is called when the `listitem` is bound to an item in the list. It is called when the `listitem` is bound to an item in the list.
The list items are LeData instances. The list items are LeData instances.
LeData is defined in the file `listeditor.c` (the C source file of the list editor). LeData is defined in the file `listeditor.c` (the C source file of the list editor).
It is a child class of GObject and has two data. It is a child class of GObject and has string data which is the content of the line.
The one is `listitem` which points a first column GtkListItem instance when they are connected.
Be careful that the GtkListItem instance is *not* the `listitem` in this handler.
If no GtkListItem is connected, it is NULL.
The other is `string` which is a content of the line.
- 10-11: `text` is a child of the `listitem` and it is a GtkText instance. - 10-11: `text` is a child of the `listitem` and it is a GtkText instance.
And `buffer` is a GtkTextBuffer instance of the `text`. And `buffer` is a GtkEntryBuffer instance of the `text`.
- 12: The LeData instance `data` is an item pointed by the `listitem`. - 12: The LeData instance `data` is an item pointed by the `listitem`.
- 15-16: Sets the text of `text` to `le_data_look_string (data)`. - 15-16: Sets the text of `text` to `le_data_look_string (data)`.
le\_data\_look\_string returns the string of the `data` and the ownership of the string is still taken by the `data`. le\_data\_look\_string returns the string of the `data` and the ownership of the string is still taken by the `data`.
So, the caller don't need to free the string. So, the caller doesn't need to free the string.
- 18: `g_object_bind_property` binds a property and another object property. - 18: `g_object_bind_property` binds a property and another object property.
This line binds the "text" property of the `buffer` (source) and the "string" property of the `data` (destination). This line binds the "text" property of the `buffer` (source) and the "string" property of the `data` (destination).
It is a uni-directional binding (`G_BINDING_DEFAULT`). It is a uni-directional binding (`G_BINDING_DEFAULT`).
@ -136,14 +124,19 @@ The key is a string (or GQuark) and the value is a gpointer (pointer to any type
The function `g_object_set_data` sets the association from the key to the value. The function `g_object_set_data` sets the association from the key to the value.
This line sets the association from "bind" to `bind` instance. This line sets the association from "bind" to `bind` instance.
It makes possible for the "unbind" handler to get the `bind` instance. It makes possible for the "unbind" handler to get the `bind` instance.
- 22-28: `unbind2_cb` is a unbind signal handler. - 22-29: `unbind2_cb` is a unbind signal handler.
- 24: Retrieves the `bind` instance from the table in the `listitem` instance. - 24: Retrieves the `bind` instance from the table in the `listitem` instance.
- 26: Unbind the binding. - 26-27: Unbind the binding.
- 27: Removes the value corresponds to the "bind" key. - 28: Removes the value corresponds to the "bind" key.
This technique is not so complicated. This technique is not so complicated.
You can use it when you make a cell editable application. You can use it when you make a cell editable application.
If it is impossible to use `g_object_bind_property`, use a notify signal on the GtkEntryBuffer instance.
You can use "deleted-text" and "inserted-text" signal instead.
The handler of the signals above copies the text in the GtkEntryBuffer instance to the LeData string.
Connect the notify signal handler in `bind2_cb` and disconnect it in `unbind2_cb`.
## Change the cell of GtkColumnView dynamically ## Change the cell of GtkColumnView dynamically
Next topic is to change the GtkColumnView (or GtkListView) cells dynamically. Next topic is to change the GtkColumnView (or GtkListView) cells dynamically.
@ -168,159 +161,157 @@ The current line doesn't need to be on the display.
It is possible to be on the line out of the Window (GtkScrolledWindow). It is possible to be on the line out of the Window (GtkScrolledWindow).
Actually, the program doesn't use GtkSingleSelection. Actually, the program doesn't use GtkSingleSelection.
It is necessary to know the corresponding GtkListItem instance from the item in the list. The LeWindow instance has two instance variables for recording the current line.
It is the opposite direction from `gtk_list_item_get_item` function.
To accomplish this, we set a `listitem` element of LeData to point the corresponding GtkListItem instance. - `win->position`: An int type variable. It is the position of the current line. It is zero-based. If no current line exists, it is -1.
Therefore, items (LeData) in the list always know the GtkListItem. - `win->current_button`: A variable points the button, located at the first column, on the current line. If no current line exists, it is NULL.
If there's no GtkListItem bound to the item, NULL is assigned.
If the current line moves, the following two functions are called.
They updates the two varables.
~~~C
1 static void
2 update_current_position (LeWindow *win, int new) {
3 char *s;
4
5 win->position = new;
6 if (win->position >= 0)
7 s = g_strdup_printf ("%d", win->position);
8 else
9 s = "";
10 gtk_label_set_text (GTK_LABEL (win->position_label), s);
11 if (*s) // s isn't an empty string
12 g_free (s);
13 }
14
15 static void
16 update_current_button (LeWindow *win, GtkButton *new_button) {
17 const char *non_current[1] = {NULL};
18 const char *current[2] = {"current", NULL};
19
20 if (win->current_button) {
21 gtk_widget_set_css_classes (GTK_WIDGET (win->current_button), non_current);
22 g_object_unref (win->current_button);
23 }
24 win->current_button = new_button;
25 if (win->current_button) {
26 g_object_ref (win->current_button);
27 gtk_widget_set_css_classes (GTK_WIDGET (win->current_button), current);
28 }
29 }
~~~
The varable `win->position_label` points a GtkLabel instance.
The label shows the current line position.
The current button has CSS "current" class.
The button is colored red through the CSS "button.current {background: red;}".
The order of the call for these two functions is important.
The first function, which updates the position, is usually called first.
After that, a new line is appended or inserted.
Then, the second function is called.
The following functions call the two functions above.
Be careful about the order of the call.
~~~C ~~~C
1 void 1 void
2 select_cb (GtkButton *btn, GtkListItem *listitem) { 2 select_cb (GtkButton *btn, GtkListItem *listitem) {
3 LeWindow *win = LE_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (btn), LE_TYPE_WINDOW)); 3 LeWindow *win = LE_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (btn), LE_TYPE_WINDOW));
4 4
5 update_current (win, gtk_list_item_get_position (listitem)); 5 update_current_position (win, gtk_list_item_get_position (listitem));
6 } 6 update_current_button (win, btn);
7 7 }
8 static void 8
9 setup1_cb (GtkListItemFactory *factory, GtkListItem *listitem) { 9 static void
10 GtkWidget *button = gtk_button_new (); 10 setup1_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
11 gtk_list_item_set_child (listitem, button); 11 GtkWidget *button = gtk_button_new ();
12 gtk_widget_set_focusable (GTK_WIDGET (button), FALSE); 12 gtk_list_item_set_child (listitem, button);
13 g_signal_connect (button, "clicked", G_CALLBACK (select_cb), listitem); 13 gtk_widget_set_focusable (GTK_WIDGET (button), FALSE);
14 } 14 g_signal_connect (button, "clicked", G_CALLBACK (select_cb), listitem);
15 15 }
16 static void 16
17 bind1_cb (GtkListItemFactory *factory, GtkListItem *listitem, gpointer user_data) { 17 static void
18 LeWindow *win = LE_WINDOW (user_data); 18 bind1_cb (GtkListItemFactory *factory, GtkListItem *listitem, gpointer user_data) {
19 GtkWidget *button = gtk_list_item_get_child (listitem); 19 LeWindow *win = LE_WINDOW (user_data);
20 const char *non_current[1] = {NULL}; 20 GtkWidget *button = gtk_list_item_get_child (listitem);
21 const char *current[2] = {"current", NULL}; 21
22 LeData *data = LE_DATA (gtk_list_item_get_item (listitem)); 22 if (win->position == gtk_list_item_get_position (listitem))
23 23 update_current_button (win, GTK_BUTTON (button));
24 if (data) { 24 }
25 le_data_set_listitem (data, listitem);
26 if (win->position == gtk_list_item_get_position (listitem))
27 gtk_widget_set_css_classes (GTK_WIDGET (button), current);
28 else
29 gtk_widget_set_css_classes (GTK_WIDGET (button), non_current);
30 }
31 }
32
33 static void
34 unbind1_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
35 LeData *data = LE_DATA (gtk_list_item_get_item (listitem));
36 if (data)
37 le_data_set_listitem (data, NULL);
38 }
~~~ ~~~
- 8-14: `setup1_cb` is a setup signal handler on the GtkSignalListItemFactory. - 1-7: `select_cb` is a "clicked" signal handler.
This factory is inserted to the factory property of the first GtkColumnViewColumn. The handler just calls the two functions and update the position and button.
- 9-15: `setup1_cb` is a setup signal handler on the GtkSignalListItemFactory.
It sets the child of `listitem` to a GtkButton instance. It sets the child of `listitem` to a GtkButton instance.
The "clicked" signal on the button is connected to the handler `select_cb`. The "clicked" signal on the button is connected to the handler `select_cb`.
When the listitem is destroyed, the child (GtkButton) is also destroyed. When the listitem is destroyed, the child (GtkButton) is also destroyed.
At the same time, the connection of the signal and the handler is also destroyed. At the same time, the connection of the signal and the handler is also destroyed.
So, you don't need teardown signal handler. So, you don't need teardown signal handler.
- 1-6: `select_cb` is a "clicked" signal handler. - 17-24: `bind1_cb` is a bind signal handler.
LeWindow is defined in `listeditor.c`. Usually, the position moves before this handler is called.
It's a child class of GtkApplicationWindow. If the item is on the current line, the button is updated.
The handler just calls the `update_current` function. No unbind handler is necessary.
The function will be explained later.
- 16-31: `bind1_cb` is a bind signal handler. When a line is added, the current position is updated in advance.
It sets the "listitem" element of the item (LeData) to point the `listitem` (GtkListItem instance).
It makes the item possible to find the corresponding GtkListItem instance.
If the item is the current line, the CSS class of the button includes "current" class.
Otherwise it has no CSS class.
This is necessary because the button may be recycled and it has had former CSS class.
The class need to be updated.
- 33-38: `unbind1_cb` is an unbind signal handler.
It removes the `listitem` instance from the "listitem" element of the item.
The element becomes NULL, which tells no GtkListItem is bound.
When referring GtkListItem, it needs to check the "listitem" element whether it points a GtkListItem or not (NULL).
Otherwise bad things will happen.
~~~C ~~~C
1 static void 1 static void
2 update_current (LeWindow *win, int new) { 2 app_cb (GtkButton *btn, LeWindow *win) {
3 char *s; 3 LeData *data = le_data_new_with_data ("");
4 LeData *data; 4
5 GtkListItem *listitem; 5 if (win->position >= 0) {
6 GtkButton *button; 6 update_current_position (win, win->position + 1);
7 const char *non_current[1] = {NULL}; 7 g_list_store_insert (win->liststore, win->position, data);
8 const char *current[2] = {"current", NULL}; 8 } else {
9 9 update_current_position (win, g_list_model_get_n_items (G_LIST_MODEL (win->liststore)));
10 if (new >= 0) 10 g_list_store_append (win->liststore, data);
11 s = g_strdup_printf ("%d", new); 11 }
12 else 12 g_object_unref (data);
13 s = ""; 13 }
14 gtk_label_set_text (GTK_LABEL (win->position_label), s); 14
15 if (*s) // s isn't an empty string 15 static void
16 g_free (s); 16 ins_cb (GtkButton *btn, LeWindow *win) {
17 17 LeData *data = le_data_new_with_data ("");
18 if (win->position >=0) { 18
19 data = LE_DATA (g_list_model_get_item (G_LIST_MODEL (win->liststore), win->position)); 19 if (win->position >= 0)
20 if ((listitem = le_data_get_listitem (data)) != NULL) { 20 g_list_store_insert (win->liststore, win->position, data);
21 button = GTK_BUTTON (gtk_list_item_get_child (listitem)); 21 else {
22 gtk_widget_set_css_classes (GTK_WIDGET (button), non_current); 22 update_current_position (win, 0);
23 g_object_unref (listitem); 23 g_list_store_insert (win->liststore, 0, data);
24 } 24 }
25 g_object_unref (data); 25 g_object_unref (data);
26 } 26 }
27 win->position = new;
28 if (win->position >=0) {
29 data = LE_DATA (g_list_model_get_item (G_LIST_MODEL (win->liststore), win->position));
30 if ((listitem = le_data_get_listitem (data)) != NULL) {
31 button = GTK_BUTTON (gtk_list_item_get_child (listitem));
32 gtk_widget_set_css_classes (GTK_WIDGET (button), current);
33 g_object_unref (listitem);
34 }
35 g_object_unref (data);
36 }
37 }
~~~ ~~~
The function `update_current` does several things. When a line is removed, the current position becomes -1 and no button is current.
- It has two parameters. ~~~C
The first one is `win`, which is an instance of LeWindow class. 1 static void
It has some elements. 2 rm_cb (GtkButton *btn, LeWindow *win) {
- win->position: an Integer. it is the current position. If no current line exists, it is -1. 3 if (win->position >= 0) {
- win->position_label: GtkLabel. It shows the current position. 4 g_list_store_remove (win->liststore, win->position);
- The second parameter is `new`, which is the new current position. 5 update_current_position (win, -1);
At the beginning of the function, win->position points the old position. 6 update_current_button (win, NULL);
- 10-16: Update the text of GtkLabel. 7 }
- 18-26: If the old position (win->position) is not negative, the current line exists. 8 }
It gets a GtkListItem instance via the item (LeData) of the list. ~~~
And it gets the GtkButton instance which is the child of the GtkListItem.
It clears the "css-classes" property of the button.
- 27: Updates win->position.
- 28-36: If the new position is not negative (It's possible to be negative when the current line has been removed), the current line exists.
It sets the "css-classes" property of the button to `{"current", NULL}`.
It is a NULL-terminated array of strings.
Each string is a CSS class.
Now the button has "current" style class.
The color of buttons are determined by the "background" CSS style. The color of buttons are determined by the "background" CSS style.
The following CSS is applied to the default GdkDisplay in advance (in the startup handler of the application). The following CSS node is a bit complicated.
CSS node `column view` has `listview` child node.
It covers the rows in the GtkColumnView.
The `listview` node is the same as the one for GtkListView.
It has `row` child node, which is for each child widget.
Therefore, the following node corresponds buttons on the GtkColumnView widget.
In addition, it is applied to the "current" class.
~~~css ~~~css
columnview listview row button.current {background: red;} columnview listview row button.current {background: red;}
~~~ ~~~
The selectors "columnview listview row" is needed before "button" selector.
Otherwise the buttons in the GtkColumnview won't be found.
The button selector has "current" class.
So, the only "current" class button is colored with red.
Other buttons are not colored, which means they are white.
## Gtk\_widget\_dispose\_template function
The function `gtk_widget_dispose_template` clears the template children for the given widget.
This is the opposite of `gtk_widget_init_template()`.
It is a new function of GTK 4.8 version.
If your GTK version is lower than 4.8, you need to modify the program.
## A waring from GtkText ## A waring from GtkText
If your program has the following two, a warning message can be issued. If your program has the following two, a warning message can be issued.

View file

@ -6,7 +6,8 @@ The table of contents is at the end of this abstract.
- Section 3 to 23 describes the basics, with the example of a simple editor `tfe` (Text File Editor). - Section 3 to 23 describes the basics, with the example of a simple editor `tfe` (Text File Editor).
- Section 24 to 27 describes GtkDrawingArea. - Section 24 to 27 describes GtkDrawingArea.
- Section 28 to 32 describes the list model and the list view (GtkListView, GtkGridView and GtkColumnView). - Section 28 describes Drag and Drop.
- Section 29 to 33 describes the list model and the list view (GtkListView, GtkGridView and GtkColumnView).
It also describes GtkExpression. It also describes GtkExpression.
The latest version of the tutorial is located at [GTK4-tutorial GitHub repository](https://github.com/ToshioCP/Gtk4-tutorial). The latest version of the tutorial is located at [GTK4-tutorial GitHub repository](https://github.com/ToshioCP/Gtk4-tutorial).

View file

@ -2,5 +2,7 @@
<gresources> <gresources>
<gresource prefix="/com/github/ToshioCP/exp"> <gresource prefix="/com/github/ToshioCP/exp">
<file>exp.ui</file> <file>exp.ui</file>
<file>exp_bind.ui</file>
<file>exp_test.ui</file>
</gresource> </gresource>
</gresources> </gresources>

View file

@ -28,7 +28,7 @@ app_startup (GApplication *application) {
GtkExpression *expression, *params[1]; GtkExpression *expression, *params[1];
/* Builds a window with exp.ui resource */ /* Builds a window with exp.ui resource */
build = gtk_builder_new_from_file ("exp_bind.ui"); build = gtk_builder_new_from_resource ("/com/github/ToshioCP/exp/exp_bind.ui");
win = GTK_WIDGET (gtk_builder_get_object (build, "win")); win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
label = GTK_WIDGET (gtk_builder_get_object (build, "label")); label = GTK_WIDGET (gtk_builder_get_object (build, "label"));
// scale = GTK_WIDGET (gtk_builder_get_object (build, "scale")); // scale = GTK_WIDGET (gtk_builder_get_object (build, "scale"));

View file

@ -14,7 +14,7 @@ main (int argc, char **argv) {
if (gtk_expression_evaluate (expression, label, &value)) if (gtk_expression_evaluate (expression, label, &value))
g_print ("The value is %s.\n", g_value_get_string (&value)); g_print ("The value is %s.\n", g_value_get_string (&value));
else else
g_print ("The constant expression wasn't evaluated correctly.\n"); g_print ("The property expression wasn't evaluated correctly.\n");
gtk_expression_unref (expression); gtk_expression_unref (expression);
g_value_unset (&value); g_value_unset (&value);

View file

@ -23,7 +23,7 @@ app_startup (GApplication *application) {
GtkBuilder *build; GtkBuilder *build;
GtkWidget *win; GtkWidget *win;
build = gtk_builder_new_from_file ("exp_test.ui"); build = gtk_builder_new_from_resource ("/com/github/ToshioCP/exp/exp_test.ui");
win = GTK_WIDGET (gtk_builder_get_object (build, "win")); win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
gtk_window_set_application (GTK_WINDOW (win), app); gtk_window_set_application (GTK_WINDOW (win), app);
g_object_unref (build); g_object_unref (build);

View file

@ -15,6 +15,6 @@ executable('closure', 'closure.c', dependencies: gtkdep, export_dynamic: true, i
executable('closure_each', 'closure_each.c', dependencies: gtkdep, export_dynamic: true, install: false) executable('closure_each', 'closure_each.c', dependencies: gtkdep, export_dynamic: true, install: false)
executable('exp_closure_simple', 'exp_closure_simple.c', dependencies: gtkdep, export_dynamic: true, install: false) executable('exp_closure_simple', 'exp_closure_simple.c', dependencies: gtkdep, export_dynamic: true, install: false)
executable('exp_closure_with_error_report', 'exp_closure_with_error_report.c', dependencies: gtkdep, export_dynamic: true, install: false) executable('exp_closure_with_error_report', 'exp_closure_with_error_report.c', dependencies: gtkdep, export_dynamic: true, install: false)
executable('exp_bind', 'exp_bind.c', dependencies: gtkdep, export_dynamic: true, install: false) executable('exp_bind', 'exp_bind.c', resources, dependencies: gtkdep, export_dynamic: true, install: false)
executable('exp_watch', 'exp_watch.c', dependencies: gtkdep, export_dynamic: true, install: false) executable('exp_watch', 'exp_watch.c', dependencies: gtkdep, export_dynamic: true, install: false)
executable('exp_test', 'exp_test.c', dependencies: gtkdep, export_dynamic: true, install: false) executable('exp_test', 'exp_test.c', resources, dependencies: gtkdep, export_dynamic: true, install: false)

View file

@ -13,7 +13,6 @@ static GParamSpec *ledata_properties[N_PROPERTIES] = {NULL, };
typedef struct _LeData { typedef struct _LeData {
GObject parent; GObject parent;
GtkListItem *listitem;
char *string; char *string;
} LeData; } LeData;
@ -41,19 +40,9 @@ le_data_get_property (GObject *object, guint property_id, GValue *value, GParamS
static void static void
le_data_init (LeData *self) { le_data_init (LeData *self) {
self->listitem = NULL;
self->string = NULL; self->string = NULL;
} }
static void
le_data_dispose (GObject *object) {
LeData *self = LE_DATA (object);
if (self->listitem)
g_clear_object (&self->listitem);
G_OBJECT_CLASS (le_data_parent_class)->dispose (object);
}
static void static void
le_data_finalize (GObject *object) { le_data_finalize (GObject *object) {
LeData *self = LE_DATA (object); LeData *self = LE_DATA (object);
@ -67,7 +56,6 @@ static void
le_data_class_init (LeDataClass *class) { le_data_class_init (LeDataClass *class) {
GObjectClass *gobject_class = G_OBJECT_CLASS (class); GObjectClass *gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = le_data_dispose;
gobject_class->finalize = le_data_finalize; gobject_class->finalize = le_data_finalize;
gobject_class->set_property = le_data_set_property; gobject_class->set_property = le_data_set_property;
gobject_class->get_property = le_data_get_property; gobject_class->get_property = le_data_get_property;
@ -75,14 +63,16 @@ le_data_class_init (LeDataClass *class) {
g_object_class_install_properties (gobject_class,N_PROPERTIES, ledata_properties); g_object_class_install_properties (gobject_class,N_PROPERTIES, ledata_properties);
} }
/* setter and getter */ /* getter and setter */
void
le_data_set_listitem (LeData *self, GtkListItem *listitem) {
g_return_if_fail (GTK_IS_LIST_ITEM (listitem) || listitem == NULL);
if (self->listitem) char *
g_object_unref (self->listitem); le_data_get_string (LeData *self) {
self->listitem = listitem ? g_object_ref (listitem) : NULL; return g_strdup (self->string);
}
const char *
le_data_look_string (LeData *self) {
return self->string;
} }
void void
@ -99,35 +89,9 @@ le_data_take_string (LeData *self, char *string) {
self->string = string; self->string = string;
} }
GtkListItem *
le_data_get_listitem (LeData *self) {
return self->listitem ? g_object_ref (self->listitem) : NULL;
}
GtkListItem *
le_data_look_listitem (LeData *self) {
return self->listitem ? self->listitem : NULL;
}
char *
le_data_get_string (LeData *self) {
return g_strdup (self->string);
}
const char *
le_data_look_string (LeData *self) {
return self->string;
}
LeData * LeData *
le_data_new_with_data (GtkListItem *listitem, const char *string) { le_data_new_with_data (const char *string) {
g_return_val_if_fail (GTK_IS_LIST_ITEM (listitem) || listitem == NULL, NULL); return LE_DATA (g_object_new (LE_TYPE_DATA, "string", string, NULL));
LeData *data;
data = LE_DATA (g_object_new (LE_TYPE_DATA, NULL));
data->listitem = listitem ? g_object_ref (listitem) : NULL;
data->string = g_strdup (string);
return data;
} }
LeData * LeData *
@ -141,151 +105,149 @@ G_DECLARE_FINAL_TYPE (LeWindow, le_window, LE, WINDOW, GtkApplicationWindow)
typedef struct _LeWindow { typedef struct _LeWindow {
GtkApplicationWindow parent; GtkApplicationWindow parent;
int position; /* current position */ int position; /* current position */
GtkButton *current_button;
GFile *file; GFile *file;
GtkWidget *position_label; GtkWidget *position_label;
GtkWidget *filename; GtkWidget *filename;
GtkWidget *columnview; GtkWidget *columnview;
GtkNoSelection *noselection;
GListStore *liststore; GListStore *liststore;
} LeWindow; } LeWindow;
G_DEFINE_TYPE (LeWindow, le_window, GTK_TYPE_APPLICATION_WINDOW) G_DEFINE_FINAL_TYPE (LeWindow, le_window, GTK_TYPE_APPLICATION_WINDOW)
static void static void
update_current (LeWindow *win, int new) { update_current_position (LeWindow *win, int new) {
char *s; char *s;
LeData *data;
GtkListItem *listitem;
GtkButton *button;
const char *non_current[1] = {NULL};
const char *current[2] = {"current", NULL};
if (new >= 0) win->position = new;
s = g_strdup_printf ("%d", new); if (win->position >= 0)
s = g_strdup_printf ("%d", win->position);
else else
s = ""; s = "";
gtk_label_set_text (GTK_LABEL (win->position_label), s); gtk_label_set_text (GTK_LABEL (win->position_label), s);
if (*s) // s isn't an empty string if (*s) // s isn't an empty string
g_free (s); g_free (s);
}
if (win->position >=0) { static void
data = LE_DATA (g_list_model_get_item (G_LIST_MODEL (win->liststore), win->position)); update_current_button (LeWindow *win, GtkButton *new_button) {
if ((listitem = le_data_get_listitem (data)) != NULL) { const char *non_current[1] = {NULL};
button = GTK_BUTTON (gtk_list_item_get_child (listitem)); const char *current[2] = {"current", NULL};
gtk_widget_set_css_classes (GTK_WIDGET (button), non_current);
g_object_unref (listitem); if (win->current_button) {
} gtk_widget_set_css_classes (GTK_WIDGET (win->current_button), non_current);
g_object_unref (data); g_object_unref (win->current_button);
} }
win->position = new; win->current_button = new_button;
if (win->position >=0) { if (win->current_button) {
data = LE_DATA (g_list_model_get_item (G_LIST_MODEL (win->liststore), win->position)); g_object_ref (win->current_button);
if ((listitem = le_data_get_listitem (data)) != NULL) { gtk_widget_set_css_classes (GTK_WIDGET (win->current_button), current);
button = GTK_BUTTON (gtk_list_item_get_child (listitem));
gtk_widget_set_css_classes (GTK_WIDGET (button), current);
g_object_unref (listitem);
}
g_object_unref (data);
} }
} }
/* ----- Button "clicled" signal handlers ----- */ /* ----- Button "clicled" signal handlers ----- */
static void static void
app_cb (GtkButton *btn, LeWindow *win) { app_cb (GtkButton *btn, LeWindow *win) {
LeData *data; LeData *data = le_data_new_with_data ("");
data = le_data_new_with_data (NULL, "");
if (win->position >= 0) { if (win->position >= 0) {
g_list_store_insert (win->liststore, win->position + 1, data); update_current_position (win, win->position + 1);
update_current (win, win->position + 1); g_list_store_insert (win->liststore, win->position, data);
} else { } else {
update_current_position (win, g_list_model_get_n_items (G_LIST_MODEL (win->liststore)));
g_list_store_append (win->liststore, data); g_list_store_append (win->liststore, data);
update_current (win, g_list_model_get_n_items (G_LIST_MODEL (win->liststore)) - 1);
} }
g_object_unref (data); g_object_unref (data);
} }
static void static void
ins_cb (GtkButton *btn, LeWindow *win) { ins_cb (GtkButton *btn, LeWindow *win) {
LeData *data; LeData *data = le_data_new_with_data ("");
data = le_data_new_with_data (NULL, ""); if (win->position >= 0)
if (win->position >= 0) {
g_list_store_insert (win->liststore, win->position, data); g_list_store_insert (win->liststore, win->position, data);
win->position += 1; else {
update_current (win, win->position - 1); update_current_position (win, 0);
g_list_store_insert (win->liststore, 0, data);
} }
g_object_unref (data); g_object_unref (data);
} }
static void static void
rm_cb (GtkButton *btn, LeWindow *win) { rm_cb (GtkButton *btn, LeWindow *win) {
int position;
if (win->position >= 0) { if (win->position >= 0) {
position = win->position; g_list_store_remove (win->liststore, win->position);
win->position = -1; update_current_position (win, -1);
g_list_store_remove (win->liststore, position); update_current_button (win, NULL);
update_current (win, -1);
} }
} }
static void static void
open_dialog_response(GtkWidget *dialog, gint response, LeWindow *win) { open_dialog_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) {
GtkFileDialog *dialog = GTK_FILE_DIALOG (source_object);
LeWindow *win = LE_WINDOW (user_data);
GFile *file; GFile *file;
char *contents; char *contents;
GListStore *liststore;
GListStore *liststore_old;
LeData *data;
char *s; char *s;
gsize length;
GFileInputStream *stream; GFileInputStream *stream;
GDataInputStream *dstream; GDataInputStream *dstream;
GError *err = NULL; GError *err = NULL;
LeData *data;
if (response == GTK_RESPONSE_ACCEPT if ((file = gtk_file_dialog_open_finish (dialog, res, &err)) == NULL) {
&& G_IS_FILE (file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog))) g_warning ("%s\n", err->message);
&& g_file_load_contents (file, NULL, &contents, &length, NULL, &err)) { g_error_free (err);
if (! (stream = g_file_read (file, NULL, &err))) { return;
g_warning ("%s\n", err->message);
g_error_free (err);
return;
}
dstream = g_data_input_stream_new (G_INPUT_STREAM (stream));
g_object_unref (stream);
while ((contents = g_data_input_stream_read_line_utf8 (dstream, &length, NULL, &err)) != NULL) {
data = le_data_new_with_data (NULL, contents);
g_free (contents);
g_list_store_append (win->liststore, data);
g_object_unref (data);
}
if (err) {
g_warning ("%s\n", err->message);
if (g_list_model_get_n_items(G_LIST_MODEL (win->liststore)) > 0)
g_list_store_remove_all (win->liststore);
return;
} else if (! g_input_stream_close (G_INPUT_STREAM (dstream), NULL, &err)) { /* EOF */
g_warning ("%s\n", err->message);
g_error_free (err);
return;
}
win->file = file; /* win->file is NULL (has already checked) and it take the ownership of 'file' */
s = g_file_get_basename (file);
gtk_label_set_text (GTK_LABEL (win->filename), s);
g_free (s);
update_current (win, -1);
} }
gtk_window_destroy (GTK_WINDOW (dialog)); if ((stream = g_file_read (file, NULL, &err)) == NULL) {
g_warning ("%s\n", err->message);
g_error_free (err);
return;
}
dstream = g_data_input_stream_new (G_INPUT_STREAM (stream));
g_object_unref (stream);
liststore = g_list_store_new (LE_TYPE_DATA);
while ((contents = g_data_input_stream_read_line_utf8 (dstream, NULL, NULL, &err)) != NULL) {
data = le_data_new_with_data (contents);
g_list_store_append (liststore, data);
g_free (contents);
g_object_unref (data);
}
if (err) {
g_warning ("%s\n", err->message);
g_error_free (err);
g_object_unref (liststore);
return;
}
if (! g_input_stream_close (G_INPUT_STREAM (dstream), NULL, &err)) {
g_warning ("%s\n", err->message);
g_error_free (err);
g_object_unref (liststore);
return;
}
/* Now the file has successfully read. */
if (win->file)
g_object_unref (file);
win->file = file; /* The ownership of the GFile moves to the window. */
s = g_file_get_basename (file);
gtk_label_set_text (GTK_LABEL (win->filename), s);
g_free (s);
liststore_old = win->liststore;
gtk_no_selection_set_model (win->noselection, G_LIST_MODEL (liststore));
win->liststore = liststore; /* The ownership of the stringlist moves to the window. */
g_object_unref (liststore_old);
update_current_position (win, -1);
} }
static void static void
read_cb (GtkButton *btn, LeWindow *win) { read_cb (GtkButton *btn, LeWindow *win) {
GtkWidget *dialog; GtkFileDialog *dialog;
if (win->file || g_list_model_get_n_items (G_LIST_MODEL (win->liststore)) > 0) dialog = gtk_file_dialog_new ();
return; gtk_file_dialog_open (dialog, GTK_WINDOW (win), NULL, open_dialog_cb, win);
dialog = gtk_file_chooser_dialog_new ("Open file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_OPEN, g_object_unref (dialog);
"Cancel", GTK_RESPONSE_CANCEL,
"Open", GTK_RESPONSE_ACCEPT,
NULL);
g_signal_connect (dialog, "response", G_CALLBACK (open_dialog_response), win);
gtk_window_present (GTK_WINDOW (dialog));
} }
static void static void
@ -293,8 +255,9 @@ write_data (LeWindow *win) {
GFileOutputStream *ostream; GFileOutputStream *ostream;
gssize size; gssize size;
gsize length; gsize length;
LeData *data;
int i, n_items; int i, n_items;
LeData *data;
const char *s;
GError *err = NULL; GError *err = NULL;
if (! (ostream = g_file_replace (win->file, NULL, TRUE, G_FILE_CREATE_NONE, NULL, &err))) { if (! (ostream = g_file_replace (win->file, NULL, TRUE, G_FILE_CREATE_NONE, NULL, &err))) {
@ -305,18 +268,19 @@ write_data (LeWindow *win) {
n_items = g_list_model_get_n_items (G_LIST_MODEL (win->liststore)); n_items = g_list_model_get_n_items (G_LIST_MODEL (win->liststore));
for (i=0; i<n_items; ++i) { for (i=0; i<n_items; ++i) {
data = LE_DATA (g_list_model_get_item (G_LIST_MODEL (win->liststore), i)); data = LE_DATA (g_list_model_get_item (G_LIST_MODEL (win->liststore), i));
length = (gsize) strlen (le_data_look_string (data)); s = le_data_look_string (data);
size = g_output_stream_write (G_OUTPUT_STREAM (ostream), le_data_look_string (data), length, NULL, &err); length = (gsize) strlen (s);
size = g_output_stream_write (G_OUTPUT_STREAM (ostream), s, length, NULL, &err);
g_object_unref (data); g_object_unref (data);
if (size < 0) { if (size < 0) {
g_warning ("%s\n", err->message); g_warning ("%s\n", err->message);
g_error_free (err); g_clear_error (&err);
break; break;
} }
size = g_output_stream_write (G_OUTPUT_STREAM (ostream), "\n", 1, NULL, &err); size = g_output_stream_write (G_OUTPUT_STREAM (ostream), "\n", 1, NULL, &err);
if (size < 0) { if (size < 0) {
g_warning ("%s\n", err->message); g_warning ("%s\n", err->message);
g_error_free (err); g_clear_error (&err);
break; break;
} }
} }
@ -327,36 +291,34 @@ write_data (LeWindow *win) {
} }
static void static void
saveas_dialog_response (GtkWidget *dialog, gint response, LeWindow *win) { saveas_dialog_cb (GObject* source_object, GAsyncResult* res, gpointer user_data) {
GtkFileDialog *dialog = GTK_FILE_DIALOG (source_object);
LeWindow *win = LE_WINDOW (user_data);
GFile *file; GFile *file;
GError *err = NULL;
char *s; char *s;
if (response == GTK_RESPONSE_ACCEPT) { if ((file = gtk_file_dialog_save_finish (dialog, res, &err)) == NULL) {
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)); g_warning ("%s\n", err->message);
if (G_IS_FILE (file)) { g_error_free (err);
win->file = file; /* the ownership is taken by win */ return;
s = g_file_get_basename (file);
gtk_label_set_text (GTK_LABEL (win->filename), s);
g_free (s);
write_data (win);
}
else {
g_warning ("gtk_file_chooser_get_file returns non GFile.\n");
}
} }
gtk_window_destroy (GTK_WINDOW (dialog)); if (win->file)
g_object_unref (win->file);
win->file = file; /* the ownership is taken by win */
s = g_file_get_basename (file);
gtk_label_set_text (GTK_LABEL (win->filename), s);
g_free (s);
write_data (win);
} }
static void static void
show_saveas_dialog (LeWindow *win) { show_saveas_dialog (LeWindow *win) {
GtkWidget *dialog; GtkFileDialog *dialog;
dialog = gtk_file_chooser_dialog_new ("Save file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_SAVE, dialog = gtk_file_dialog_new ();
"Cancel", GTK_RESPONSE_CANCEL, gtk_file_dialog_save (dialog, GTK_WINDOW (win), NULL, saveas_dialog_cb, win);
"Save", GTK_RESPONSE_ACCEPT, g_object_unref (dialog);
NULL);
g_signal_connect (dialog, "response", G_CALLBACK (saveas_dialog_response), win);
gtk_widget_show (dialog);
} }
static void static void
@ -371,14 +333,15 @@ write_cb (GtkButton *btn, LeWindow *win) {
static void static void
close_cb (GtkButton *btn, LeWindow *win) { close_cb (GtkButton *btn, LeWindow *win) {
if (g_list_model_get_n_items (G_LIST_MODEL (win->liststore)) > 0) guint n_items;
if ((n_items = g_list_model_get_n_items (G_LIST_MODEL (win->liststore))) > 0)
g_list_store_remove_all (win->liststore); g_list_store_remove_all (win->liststore);
if (win->file) { if (win->file) {
g_clear_object (&win->file); g_clear_object (&win->file);
gtk_label_set_text (GTK_LABEL (win->filename), ""); gtk_label_set_text (GTK_LABEL (win->filename), "");
} }
win->position = -1; update_current_position (win, -1);
gtk_label_set_text (GTK_LABEL (win->position_label), "");
} }
static void static void
@ -391,7 +354,8 @@ void
select_cb (GtkButton *btn, GtkListItem *listitem) { select_cb (GtkButton *btn, GtkListItem *listitem) {
LeWindow *win = LE_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (btn), LE_TYPE_WINDOW)); LeWindow *win = LE_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (btn), LE_TYPE_WINDOW));
update_current (win, gtk_list_item_get_position (listitem)); update_current_position (win, gtk_list_item_get_position (listitem));
update_current_button (win, btn);
} }
/* ----- Handlers on GtkSignalListItemFacory ----- */ /* ----- Handlers on GtkSignalListItemFacory ----- */
@ -407,24 +371,9 @@ static void
bind1_cb (GtkListItemFactory *factory, GtkListItem *listitem, gpointer user_data) { bind1_cb (GtkListItemFactory *factory, GtkListItem *listitem, gpointer user_data) {
LeWindow *win = LE_WINDOW (user_data); LeWindow *win = LE_WINDOW (user_data);
GtkWidget *button = gtk_list_item_get_child (listitem); GtkWidget *button = gtk_list_item_get_child (listitem);
const char *non_current[1] = {NULL};
const char *current[2] = {"current", NULL};
LeData *data = LE_DATA (gtk_list_item_get_item (listitem));
if (data) { if (win->position == gtk_list_item_get_position (listitem))
le_data_set_listitem (data, listitem); update_current_button (win, GTK_BUTTON (button));
if (win->position == gtk_list_item_get_position (listitem))
gtk_widget_set_css_classes (GTK_WIDGET (button), current);
else
gtk_widget_set_css_classes (GTK_WIDGET (button), non_current);
}
}
static void
unbind1_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
LeData *data = LE_DATA (gtk_list_item_get_item (listitem));
if (data)
le_data_set_listitem (data, NULL);
} }
static void static void
@ -438,7 +387,7 @@ static void
bind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) { bind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
GtkWidget *text = gtk_list_item_get_child (listitem); GtkWidget *text = gtk_list_item_get_child (listitem);
GtkEntryBuffer *buffer = gtk_text_get_buffer (GTK_TEXT (text)); GtkEntryBuffer *buffer = gtk_text_get_buffer (GTK_TEXT (text));
LeData *data = LE_DATA (gtk_list_item_get_item (listitem)); LeData *data = LE_DATA (gtk_list_item_get_item(listitem));
GBinding *bind; GBinding *bind;
gtk_editable_set_text (GTK_EDITABLE (text), le_data_look_string (data)); gtk_editable_set_text (GTK_EDITABLE (text), le_data_look_string (data));
@ -452,7 +401,8 @@ static void
unbind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) { unbind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
GBinding *bind = G_BINDING (g_object_get_data (G_OBJECT (listitem), "bind")); GBinding *bind = G_BINDING (g_object_get_data (G_OBJECT (listitem), "bind"));
g_binding_unbind(bind); if (bind)
g_binding_unbind(bind);
g_object_set_data (G_OBJECT (listitem), "bind", NULL); g_object_set_data (G_OBJECT (listitem), "bind", NULL);
} }
@ -463,24 +413,29 @@ adjustment_value_changed_cb (GtkAdjustment *adjustment, gpointer user_data) {
gtk_window_set_focus (GTK_WINDOW (win), NULL); gtk_window_set_focus (GTK_WINDOW (win), NULL);
} }
static void
le_window_init (LeWindow *win) {
gtk_widget_init_template (GTK_WIDGET (win));
win->position = -1;
win->file =NULL;
}
static void static void
le_window_dispose (GObject *object) { le_window_dispose (GObject *object) {
LeWindow *win = LE_WINDOW (object); LeWindow *win = LE_WINDOW (object);
if (win->current_button)
g_clear_object (&win->current_button);
if (win->file)
g_clear_object (&win->file);
/* this function is available since GTK 4.8 */ /* this function is available since GTK 4.8 */
gtk_widget_dispose_template (GTK_WIDGET (win), LE_TYPE_WINDOW); gtk_widget_dispose_template (GTK_WIDGET (win), LE_TYPE_WINDOW);
/* chain to the parent */ /* chain to the parent */
G_OBJECT_CLASS (le_window_parent_class)->dispose (object); G_OBJECT_CLASS (le_window_parent_class)->dispose (object);
} }
static void
le_window_init (LeWindow *win) {
gtk_widget_init_template (GTK_WIDGET (win));
win->position = -1;
win->current_button = NULL;
win->file =NULL;
}
static void static void
le_window_class_init (LeWindowClass *class) { le_window_class_init (LeWindowClass *class) {
GObjectClass *gobject_class = G_OBJECT_CLASS (class); GObjectClass *gobject_class = G_OBJECT_CLASS (class);
@ -491,6 +446,7 @@ le_window_class_init (LeWindowClass *class) {
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), LeWindow, position_label); gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), LeWindow, position_label);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), LeWindow, filename); gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), LeWindow, filename);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), LeWindow, columnview); gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), LeWindow, columnview);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), LeWindow, noselection);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), LeWindow, liststore); gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), LeWindow, liststore);
/* The followint macros are available since GTK 4.8 */ /* The followint macros are available since GTK 4.8 */
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), app_cb); gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), app_cb);
@ -502,7 +458,6 @@ le_window_class_init (LeWindowClass *class) {
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), quit_cb); gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), quit_cb);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), setup1_cb); gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), setup1_cb);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), bind1_cb); gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), bind1_cb);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), unbind1_cb);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), setup2_cb); gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), setup2_cb);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), bind2_cb); gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), bind2_cb);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), unbind2_cb); gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), unbind2_cb);

View file

@ -2,8 +2,8 @@
<interface> <interface>
<template class="LeWindow" parent="GtkApplicationWindow"> <template class="LeWindow" parent="GtkApplicationWindow">
<property name="title">list editor</property> <property name="title">list editor</property>
<property name="default-width">600</property> <property name="default-width">1000</property>
<property name="default-height">400</property> <property name="default-height">600</property>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="orientation">GTK_ORIENTATION_VERTICAL</property> <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
@ -95,7 +95,7 @@
<property name="vexpand">TRUE</property> <property name="vexpand">TRUE</property>
<property name="focusable">FALSE</property> <property name="focusable">FALSE</property>
<property name="model"> <property name="model">
<object class="GtkNoSelection"> <object class="GtkNoSelection" id = "noselection">
<property name="model"> <property name="model">
<object class="GListStore" id="liststore"> <object class="GListStore" id="liststore">
<property name="item-type">LeData</property> <property name="item-type">LeData</property>
@ -110,7 +110,6 @@
<object class="GtkSignalListItemFactory"> <object class="GtkSignalListItemFactory">
<signal name="setup" handler="setup1_cb"></signal> <signal name="setup" handler="setup1_cb"></signal>
<signal name="bind" handler="bind1_cb" swapped="no" object="LeWindow"></signal> <signal name="bind" handler="bind1_cb" swapped="no" object="LeWindow"></signal>
<signal name="unbind" handler="unbind1_cb"></signal>
</object> </object>
</property> </property>
</object> </object>
@ -118,6 +117,7 @@
<child> <child>
<object class="GtkColumnViewColumn"> <object class="GtkColumnViewColumn">
<property name="title">String</property> <property name="title">String</property>
<property name="expand">TRUE</property>
<property name="factory"> <property name="factory">
<object class="GtkSignalListItemFactory"> <object class="GtkSignalListItemFactory">
<signal name="setup" handler="setup2_cb"></signal> <signal name="setup" handler="setup2_cb"></signal>

View file

@ -6,9 +6,10 @@ The new feature is described in [Gtk API Reference -- List Widget Overview](http
GTK 4 has other means to implement lists. GTK 4 has other means to implement lists.
They are GtkListBox and GtkTreeView which are took over from GTK 3. They are GtkListBox and GtkTreeView which are took over from GTK 3.
There's an article in [Gtk Development blog](https://blog.gtk.org/2020/06/07/scalable-lists-in-gtk-4/) about list widgets by Matthias Clasen. There's an article in [Gtk Development blog](https://blog.gtk.org/2020/06/07/scalable-lists-in-gtk-4/) about list widgets by Matthias Clasen.
He described why GtkListView are developed to replace GtkListBox and GtkTreeView. He described why GtkListView are developed to replace GtkTreeView.
GtkTreeView is deprecated since version 4.10.
GtkListView, GtkGridView, GtkColumnView and related objects are described in Section 26 to 29. GtkListView, GtkGridView, GtkColumnView and related objects are described in Section 29 to 33.
## Outline ## Outline
@ -19,7 +20,7 @@ A list is like an array, but in many cases it is implemented with pointers which
And it has a start point. And it has a start point.
So, each item can be referred by the index of the item (first item, second item, ..., nth item, ...). So, each item can be referred by the index of the item (first item, second item, ..., nth item, ...).
There are two cases. There are two cases.
One is the index starts from one (one-based) and the other is from zero (zero-based). The 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 and its items are 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.
@ -27,11 +28,11 @@ 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 instance maps items in the list to GListView. GtkListItemFactory instance maps items in the list to GtkListView.
![List](../image/list.png){width=10cm height=7.5cm} ![List](../image/list.png){width=10cm height=7.5cm}
## GListModel ## GListModel and GtkStringList
If you want to make a list of strings with GListModel, for example, "one", "two", "three", "four", note that strings can't be items of the list. If you want to make a list of strings with GListModel, for example, "one", "two", "three", "four", note that strings can't be items of the list.
Because GListModel is a list of GObject objects and strings aren't GObject objects. Because GListModel is a list of GObject objects and strings aren't GObject objects.
@ -172,6 +173,7 @@ If you feel some difficulty, read this section again, especially GtkSignalListIt
GtkBuilderListItemFactory is another GtkListItemFactory. GtkBuilderListItemFactory is another GtkListItemFactory.
Its behavior is defined with ui file. Its behavior is defined with ui file.
@@@if gfm
~~~xml ~~~xml
<interface> <interface>
<template class="GtkListItem"> <template class="GtkListItem">
@ -187,6 +189,23 @@ Its behavior is defined with ui file.
</template> </template>
</interface> </interface>
~~~ ~~~
@@@else
~~~{.xml}
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<binding name="label">
<lookup name="string" type="GtkStringObject">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
~~~
@@@end
Template tag is used to define GtkListItem. Template tag is used to define GtkListItem.
And its child property is GtkLabel object. And its child property is GtkLabel object.
@ -209,7 +228,7 @@ There is an explanation in the [GTK Development Blog](https://blog.gtk.org/2020/
> 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.
Therefore, GtkListItem instance is used as the `this` object of the lookup tag when it is evaluated. Therefore, GtkListItem instance is used as the `this` object of the lookup tag when it is evaluated.
`this` object will be explained in [section 30](sec30). `this` object will be explained in [section 31](sec31).
The C source code is as follows. The C source code is as follows.
Its name is `list2.c` and located under [src/misc](misc) directory. Its name is `list2.c` and located under [src/misc](misc) directory.
@ -229,9 +248,15 @@ GtkDirectoryList is a list model containing GFileInfo objects which are informat
It uses `g_file_enumerate_children_async()` to get the GFileInfo objects. It uses `g_file_enumerate_children_async()` to get the GFileInfo objects.
The list model is created by `gtk_directory_list_new` function. The list model is created by `gtk_directory_list_new` function.
@@@if gfm
~~~C ~~~C
GtkDirectoryList *gtk_directory_list_new (const char *attributes, GFile *file); GtkDirectoryList *gtk_directory_list_new (const char *attributes, GFile *file);
~~~ ~~~
@@@else
~~~{.C}
GtkDirectoryList *gtk_directory_list_new (const char *attributes, GFile *file);
~~~
@@@end
`attributes` is a comma separated list of file attributes. `attributes` is a comma separated list of file attributes.
File attributes are key-value pairs. File attributes are key-value pairs.
@ -252,11 +277,19 @@ The following table shows some example.
The current directory is ".". The current directory is ".".
The following program makes GtkDirectoryList `dl` and its contents are GFileInfo objects under the current directory. The following program makes GtkDirectoryList `dl` and its contents are GFileInfo objects under the current directory.
@@@if gfm
~~~C ~~~C
GFile *file = g_file_new_for_path ("."); GFile *file = g_file_new_for_path (".");
GtkDirectoryList *dl = gtk_directory_list_new ("standard::name", file); GtkDirectoryList *dl = gtk_directory_list_new ("standard::name", file);
g_object_unref (file); g_object_unref (file);
~~~ ~~~
@@@else
~~~{.C}
GFile *file = g_file_new_for_path (".");
GtkDirectoryList *dl = gtk_directory_list_new ("standard::name", file);
g_object_unref (file);
~~~
@@@end
It is not so difficult to make file listing program by changing `list2.c` in the previous subsection. It is not so difficult to make file listing program by changing `list2.c` in the previous subsection.
One problem is that GInfoFile doesn't have properties. One problem is that GInfoFile doesn't have properties.
@ -264,8 +297,9 @@ Lookup tag look for a property, so it is useless for looking for a filename from
Instead, closure tag is appropriate in this case. Instead, closure tag is appropriate in this case.
Closure tag specifies a function and the type of the return value of the function. Closure tag specifies a function and the type of the return value of the function.
@@@if gfm
~~~C ~~~C
const char * char *
get_file_name (GtkListItem *item, GFileInfo *info) { get_file_name (GtkListItem *item, GFileInfo *info) {
return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL; return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
} }
@ -286,6 +320,30 @@ get_file_name (GtkListItem *item, GFileInfo *info) {
"</template>" "</template>"
"</interface>" "</interface>"
~~~ ~~~
@@@else
~~~{.C}
char *
get_file_name (GtkListItem *item, GFileInfo *info) {
return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
}
... ...
... ...
"<interface>"
"<template class=\"GtkListItem\">"
"<property name=\"child\">"
"<object class=\"GtkLabel\">"
"<binding name=\"label\">"
"<closure type=\"gchararray\" function=\"get_file_name\">"
"<lookup name=\"item\">GtkListItem</lookup>"
"</closure>"
"</binding>"
"</object>"
"</property>"
"</template>"
"</interface>"
~~~
@@@end
- The string "gchararray" is a type name. - The string "gchararray" is a type name.
The type "gchar" is a type name and it is the same as C type "char". The type "gchar" is a type name and it is the same as C type "char".
@ -301,7 +359,7 @@ The contents of closure tag (it is between \<closure...\> and\</closure\>) is pa
`<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, which is a 'this' object. The first parameter is always the GListItem instance, which is a 'this' object.
The 'this' object is explained in section 28. The 'this' object is explained in section 31.
- `gtk_file_name` function is the callback function for the closure tag. - `gtk_file_name` function is the callback function for the closure tag.
It first checks the `info` parameter. 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.
@ -341,9 +399,15 @@ $ gcc -Wl,--export-dynamic `pkg-config --cflags gtk4` list3.c `pkg-config --libs
You can also make a shell script to compile `list3.c` You can also make a shell script to compile `list3.c`
@@@if gfm
~~~bash ~~~bash
gcc -Wl,--export-dynamic `pkg-config --cflags gtk4` $1.c `pkg-config --libs gtk4` gcc -Wl,--export-dynamic `pkg-config --cflags gtk4` $1.c `pkg-config --libs gtk4`
~~~ ~~~
@@@else
~~~{.bash}
gcc -Wl,--export-dynamic `pkg-config --cflags gtk4` $1.c `pkg-config --libs gtk4`
~~~
@@@end
Save this one liner to a file `comp`. Save this one liner to a file `comp`.
Then, copy it to `$HOME/bin` and give it executable permission. Then, copy it to `$HOME/bin` and give it executable permission.
@ -361,4 +425,3 @@ $ ./a.out
~~~ ~~~
![screenshot list3](../image/list3.png){width=10cm height=7.3cm} ![screenshot list3](../image/list3.png){width=10cm height=7.3cm}

View file

@ -32,6 +32,7 @@ GtkGridView (model property) => GtkSingleSelection (model property) => GtkDirect
The following is a part of the ui file `list4.ui`. The following is a part of the ui file `list4.ui`.
@@@if gfm
~~~xml ~~~xml
<object class="GtkListView" id="list"> <object class="GtkListView" id="list">
<property name="model"> <property name="model">
@ -48,6 +49,24 @@ The following is a part of the ui file `list4.ui`.
<property name="model">singleselection</property> <property name="model">singleselection</property>
</object> </object>
~~~ ~~~
@@@else
~~~{.xml}
<object class="GtkListView" id="list">
<property name="model">
<object class="GtkSingleSelection" id="singleselection">
<property name="model">
<object class="GtkDirectoryList" id="directorylist">
<property name="attributes">standard::name,standard::icon,standard::content-type</property>
</object>
</property>
</object>
</property>
</object>
<object class="GtkGridView" id="grid">
<property name="model">singleselection</property>
</object>
~~~
@@@end
GtkDirectoryList has an "attributes" property. GtkDirectoryList has an "attributes" property.
It is attributes of GFileInfo such as "standard::name", "standard::icon" and "standard::content-type". It is attributes of GFileInfo such as "standard::name", "standard::icon" and "standard::content-type".
@ -62,7 +81,7 @@ Such "x-" subtype is not a standard mime type.)
Content type is also used by desktop systems. Content type is also used by desktop systems.
GtkGridView uses the same GtkSingleSelection instance (`singleselection`). GtkGridView uses the same GtkSingleSelection instance (`singleselection`).
So, its model property is set with it. So, its model property is set to it.
## Ui file of the window ## Ui file of the window
@ -112,11 +131,19 @@ Its child widget will be set with GtkListView or GtkGridView.
The action `view` is created, connected to the "activate" signal handler and inserted to the window (action map) as follows. The action `view` is created, connected to the "activate" signal handler and inserted to the window (action map) as follows.
@@@if gfm
~~~C ~~~C
act_view = g_simple_action_new_stateful ("view", g_variant_type_new("s"), g_variant_new_string ("list")); act_view = g_simple_action_new_stateful ("view", g_variant_type_new("s"), g_variant_new_string ("list"));
g_signal_connect (act_view, "activate", G_CALLBACK (view_activated), NULL); g_signal_connect (act_view, "activate", G_CALLBACK (view_activated), NULL);
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_view)); g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_view));
~~~ ~~~
@@@else
~~~{.C}
act_view = g_simple_action_new_stateful ("view", g_variant_type_new("s"), g_variant_new_string ("list"));
g_signal_connect (act_view, "activate", G_CALLBACK (view_activated), NULL);
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_view));
~~~
@@@end
The signal handler `view_activated` will be explained later. The signal handler `view_activated` will be explained later.
@ -198,6 +225,7 @@ You can do anything you like by connecting the "activate" signal to the handler.
The example `list4` launches `tfe` text file editor if the item of the list is a text file. The example `list4` launches `tfe` text file editor if the item of the list is a text file.
@@@if gfm
~~~C ~~~C
static void static void
list_activate (GtkListView *list, int position, gpointer user_data) { list_activate (GtkListView *list, int position, gpointer user_data) {
@ -217,6 +245,27 @@ grid_activate (GtkGridView *grid, int position, gpointer user_data) {
g_signal_connect (GTK_LIST_VIEW (list), "activate", G_CALLBACK (list_activate), NULL); g_signal_connect (GTK_LIST_VIEW (list), "activate", G_CALLBACK (list_activate), NULL);
g_signal_connect (GTK_GRID_VIEW (grid), "activate", G_CALLBACK (grid_activate), NULL); g_signal_connect (GTK_GRID_VIEW (grid), "activate", G_CALLBACK (grid_activate), NULL);
~~~ ~~~
@@@else
~~~{.C}
static void
list_activate (GtkListView *list, int position, gpointer user_data) {
GFileInfo *info = G_FILE_INFO (g_list_model_get_item (G_LIST_MODEL (gtk_list_view_get_model (list)), position));
launch_tfe_with_file (info);
}
static void
grid_activate (GtkGridView *grid, int position, gpointer user_data) {
GFileInfo *info = G_FILE_INFO (g_list_model_get_item (G_LIST_MODEL (gtk_grid_view_get_model (grid)), position));
launch_tfe_with_file (info);
}
... ...
... ...
g_signal_connect (GTK_LIST_VIEW (list), "activate", G_CALLBACK (list_activate), NULL);
g_signal_connect (GTK_GRID_VIEW (grid), "activate", G_CALLBACK (grid_activate), NULL);
~~~
@@@end
The second parameter of each handler is the position of the item (GFileInfo) of the GListModel. The second parameter of each handler is the position of the item (GFileInfo) of the GListModel.
So you can get the item with `g_list_model_get_item` function. So you can get the item with `g_list_model_get_item` function.
@ -254,7 +303,7 @@ The last parameter is the pointer to the pointer to a GError.
If your distribution supports GTK 4, using `g_app_info_launch_default_for_uri` is convenient. If your distribution supports GTK 4, using `g_app_info_launch_default_for_uri` is convenient.
The function automatically determines the default application from the file and launches it. The function automatically determines the default application from the file and launches it.
For example, if the file is text, then it launches gedit with the file. For example, if the file is text, then it launches GNOME text editor with the file.
Such feature comes from desktop. Such feature comes from desktop.
## Compilation and execution ## Compilation and execution
@ -264,7 +313,7 @@ To compile and execute list4, type as follows.
~~~ ~~~
$ cd list4 # or cd src/list4. It depends your current directory. $ cd list4 # or cd src/list4. It depends your current directory.
$ meson _build $ meson setup _build
$ ninja -C _build $ ninja -C _build
$ _build/list4 $ _build/list4
~~~ ~~~

View file

@ -56,8 +56,8 @@ The type of the value is int.
|G\_TYPE\_INT |int |gint | | |G\_TYPE\_INT |int |gint | |
|G\_TYPE\_FLOAT |float |gfloat | | |G\_TYPE\_FLOAT |float |gfloat | |
|G\_TYPE\_DOUBLE |double|gdouble | | |G\_TYPE\_DOUBLE |double|gdouble | |
|G\_TYPE\_POINTER | |gpointer | | |G\_TYPE\_POINTER |void *|gpointer |general pointer |
|G\_TYPE\_STRING | |gchararray|null-terminated Cstring| |G\_TYPE\_STRING |char *|gchararray|null-terminated Cstring|
|G\_TYPE\_OBJECT | |GObject | | |G\_TYPE\_OBJECT | |GObject | |
|GTK\_TYPE\_WINDOW| |GtkWindow | | |GTK\_TYPE\_WINDOW| |GtkWindow | |
@ -79,9 +79,15 @@ Constant expression is usually used to give a constant value or instance to anot
A property expression (GtkPropertyExpression) looks up a property in a GObject instance. A property expression (GtkPropertyExpression) looks up a property in a GObject instance.
For example, a property expression that refers "label" property in a GtkLabel object is created like this. For example, a property expression that refers "label" property in a GtkLabel object is created like this.
@@@if gfm
~~~C ~~~C
expression = gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "label"); expression = gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "label");
~~~ ~~~
@@@else
~~~{.C}
expression = gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "label");
~~~
@@@end
The second parameter `another_expression` is one of: The second parameter `another_expression` is one of:
@ -91,15 +97,23 @@ The instance is called `this` object.
For example, For example,
@@@if gfm
~~~C ~~~C
label = gtk_label_new ("Hello"); label = gtk_label_new ("Hello");
another_expression = gtk_constant_expression_new (GTK_TYPE_LABEL, label); another_expression = gtk_constant_expression_new (GTK_TYPE_LABEL, label);
expression = gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "label"); expression = gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "label");
~~~ ~~~
@@@else
~~~{.C}
label = gtk_label_new ("Hello");
another_expression = gtk_constant_expression_new (GTK_TYPE_LABEL, label);
expression = gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "label");
~~~
@@@end
If `expression` is evaluated, the second parameter `another_expression` is evaluated in advance. If `expression` is evaluated, the second parameter `another_expression` is evaluated in advance.
The value of `another_expression` is the `label` (GtkLabel instance). The value of `another_expression` is the `label` (GtkLabel instance).
Then, `expression` looks up "label" property of the label and the evaluation results "Hello". Then, `expression` looks up "label" property of the label and the evaluation results in "Hello".
In the example above, the second argument of `gtk_property_expression_new` is another expression. In the example above, the second argument of `gtk_property_expression_new` is another expression.
But the second argument can be NULL. But the second argument can be NULL.
@ -123,7 +137,7 @@ The expression just knows how to take the property from a future-given GtkLabel
The result is stored in the GValue `value`. The result is stored in the GValue `value`.
The function `g_value_get_string` gets a string from the GValue. The function `g_value_get_string` gets a string from the GValue.
But the string is owned by the GValue so you must not free the string. But the string is owned by the GValue so you must not free the string.
- 18-19: Release the expression and unset the GValue. - 18-19: Releases the expression and unset the GValue.
At the same time the string in the GValue is freed. At the same time the string in the GValue is freed.
If the second argument of `gtk_property_expression_new` isn't NULL, it is another expression. If the second argument of `gtk_property_expression_new` isn't NULL, it is another expression.
@ -144,6 +158,7 @@ When you program in C language, GtkCClosureExpression and GCClosure are appropri
A closure expression is created with `gtk_cclosure_expression_new` function. A closure expression is created with `gtk_cclosure_expression_new` function.
@@@if gfm
~~~C ~~~C
GtkExpression * GtkExpression *
gtk_cclosure_expression_new (GType value_type, gtk_cclosure_expression_new (GType value_type,
@ -154,6 +169,18 @@ gtk_cclosure_expression_new (GType value_type,
gpointer user_data, gpointer user_data,
GClosureNotify user_destroy); GClosureNotify user_destroy);
~~~ ~~~
@else
~~~{.C}
GtkExpression *
gtk_cclosure_expression_new (GType value_type,
GClosureMarshal marshal,
guint n_params,
GtkExpression **params,
GCallback callback_func,
gpointer user_data,
GClosureNotify user_destroy);
~~~
@end
- `value_type` is the type of the value when it is evaluated. - `value_type` is the type of the value when it is evaluated.
- `marshal` is a marshaller. - `marshal` is a marshaller.
@ -183,10 +210,17 @@ callback (this, param1, param2, ...)
For example, For example,
@@@if gfm
~~~C ~~~C
int int
callback (GObject *object, int x, const char *s) callback (GObject *object, int x, const char *s)
~~~ ~~~
@@@else
~~~{.C}
int
callback (GObject *object, int x, const char *s)
~~~
@@@end
The following is `exp_closure_simple.c` in `src/expression`. The following is `exp_closure_simple.c` in `src/expression`.
@ -203,13 +237,13 @@ If you want to return error report, change the return value type to be a pointer
One for error and the other for the sum. One for error and the other for the sum.
The first argument of `gtk_cclosure_expression_new` is `G_TYPE_POINTER`. The first argument of `gtk_cclosure_expression_new` is `G_TYPE_POINTER`.
There is a sample program `exp_closure_with_error_report` in `src/expression` directory. There is a sample program `exp_closure_with_error_report` in `src/expression` directory.
- 19: gtk\_init initializes GTK. It is necessary for GtkLabel. - 19: The function `gtk_init`` initializes GTK. It is necessary for GtkLabel.
- 20: A GtkLabel instance is created with "123+456". - 20: A GtkLabel instance is created with "123+456".
- 21: The instance has floating reference. It is changed to an ordinary reference count. - 21: The instance has floating reference. It is changed to an ordinary reference count.
- 22-23: Create a closure expression. Its return value type is `G_TYPE_INT` and no parameters or 'this' object. - 22-23: Creates a closure expression. Its return value type is `G_TYPE_INT` and no parameters or 'this' object.
- 24: Evaluates the expression with the label as a 'this' object. - 24: Evaluates the expression with the label as a 'this' object.
- 25: If the evaluation successes, show the sum of "123+456". It's 579. - 25: If the evaluation successes, the sum of "123+456", which is 579, is shown.
- 27: If it fails, show an error message. - 27: If it fails, an error message appears.
- 28-30: Releases the expression and the label. Unsets the value. - 28-30: Releases the expression and the label. Unsets the value.
Closure expression is flexible than other type of expression because you can specify your own callback function. Closure expression is flexible than other type of expression because you can specify your own callback function.
@ -219,12 +253,14 @@ Closure expression is flexible than other type of expression because you can spe
GtkExpressionWatch is a structure, not an object. GtkExpressionWatch is a structure, not an object.
It represents a watched GtkExpression. It represents a watched GtkExpression.
Two functions create GtkExpressionWatch structure. Two functions create GtkExpressionWatch structure.
They are `gtk_expression_bind` and `gtk_expression_watch`.
### gtk\_expression\_bind function ### gtk\_expression\_bind function
This function binds the target object's property to the expression. This function binds the target object's property to the expression.
If the value of the expression changes, the property reflects the value immediately. If the value of the expression changes, the property reflects the value immediately.
@@@if gfm
~~~C ~~~C
GtkExpressionWatch* GtkExpressionWatch*
gtk_expression_bind ( gtk_expression_bind (
@ -234,6 +270,17 @@ gtk_expression_bind (
GObject* this_ GObject* this_
) )
~~~ ~~~
@@@else
~~~{.C}
GtkExpressionWatch*
gtk_expression_bind (
GtkExpression* self,
GObject* target,
const char* property,
GObject* this_
)
~~~
@@@end
This function takes the ownership of the expression. This function takes the ownership of the expression.
So, if you want to own the expression, call `gtk_expression_ref ()` to increase the reference count of the expression. So, if you want to own the expression, call `gtk_expression_ref ()` to increase the reference count of the expression.
@ -282,7 +329,7 @@ The point of the program is:
- 41-42: Two expressions are defined. - 41-42: Two expressions are defined.
One is a property expression and the other is a closure expression. One is a property expression and the other is a closure expression.
The property expression look up the "value"property of the adjustment instance. The property expression looks up the "value" property of the adjustment instance.
The closure expression just converts the double into an integer. The closure expression just converts the double into an integer.
- 43: `gtk_expression_bind` binds the label property of the GtkLabel instance to the integer returned by the closure expression. - 43: `gtk_expression_bind` binds the label property of the GtkLabel instance to the integer returned by the closure expression.
It creates a GtkExpressionWatch structure. It creates a GtkExpressionWatch structure.
@ -296,14 +343,15 @@ This signal is emitted when the close button is clicked.
The handler is called just before the window closes. The handler is called just before the window closes.
It is the right moment to make the GtkExpressionWatch unwatched. It is the right moment to make the GtkExpressionWatch unwatched.
- 10-14: "close-request" signal handler. - 10-14: "close-request" signal handler.
`gtk_expression_watch_unwatch (watch)` makes the watch stop watching the expression. The function `gtk_expression_watch_unwatch (watch)` makes the watch stop watching the expression.
It releases the expression and calls `gtk_expression_watch_unref (watch)` in it. It also releases the expression.
If you want to bind a property to an expression, `gtk_expression_bind` is the best choice. If you want to bind a property to an expression, `gtk_expression_bind` is the best choice.
You can do it with `gtk_expression_watch` function, but it is less suitable. You can do it with `gtk_expression_watch` function, but it is less suitable.
### gtk\_expression\_watch function ### gtk\_expression\_watch function
@@@if gfm
~~~C ~~~C
GtkExpressionWatch* GtkExpressionWatch*
gtk_expression_watch ( gtk_expression_watch (
@ -314,6 +362,18 @@ gtk_expression_watch (
GDestroyNotify user_destroy GDestroyNotify user_destroy
) )
~~~ ~~~
@@@else
~~~{.C}
GtkExpressionWatch*
gtk_expression_watch (
GtkExpression* self,
GObject* this_,
GtkExpressionNotify notify,
gpointer user_data,
GDestroyNotify user_destroy
)
~~~
@@@end
The function doesn't take the ownership of the expression. The function doesn't take the ownership of the expression.
It differs from `gtk_expression_bind`. It differs from `gtk_expression_bind`.
@ -326,12 +386,21 @@ Put NULL if you don't need them.
Notify callback has the following format. Notify callback has the following format.
@@@if gfm
~~~C ~~~C
void void
notify ( notify (
gpointer user_data gpointer user_data
) )
~~~ ~~~
@@@else
~~~{.C}
void
notify (
gpointer user_data
)
~~~
@@@end
This function is used to do something when the value of the expression changes. This function is used to do something when the value of the expression changes.
But if you want to bind a property to the value, use `gtk_expression_bind` instead. But if you want to bind a property to the value, use `gtk_expression_bind` instead.
@ -381,6 +450,7 @@ It is put in the content of an object tag.
Name attribute specifies the property name of the object. Name attribute specifies the property name of the object.
The content is an expression. The content is an expression.
@@@if gfm
~~~xml ~~~xml
<constant type="gchararray">Hello world</constant> <constant type="gchararray">Hello world</constant>
<lookup name="label" type="GtkLabel">label</lookup> <lookup name="label" type="GtkLabel">label</lookup>
@ -389,16 +459,27 @@ The content is an expression.
<lookup name="default-width">win</lookup> <lookup name="default-width">win</lookup>
</bind> </bind>
~~~ ~~~
@@@else
~~~{.xml}
<constant type="gchararray">Hello world</constant>
<lookup name="label" type="GtkLabel">label</lookup>
<closure type="gint" function="callback_function"></closure>
<bind name="label">
<lookup name="default-width">win</lookup>
</bind>
~~~
@@@end
These tags are usually used for GtkBuilderListItemFactory. These tags are usually used for GtkBuilderListItemFactory.
@@@if gfm
~~~xml ~~~xml
<interface> <interface>
<template class="GtkListItem"> <template class="GtkListItem">
<property name="child"> <property name="child">
<object class="GtkLabel"> <object class="GtkLabel">
<binding name="label"> <binding name="label">
<lookup name="name" type="string"> <lookup name="string" type="GtkStringObject">
<lookup name="item">GtkListItem</lookup> <lookup name="item">GtkListItem</lookup>
</lookup> </lookup>
</binding> </binding>
@ -407,15 +488,31 @@ These tags are usually used for GtkBuilderListItemFactory.
</template> </template>
</interface> </interface>
~~~ ~~~
@@@else
~~~{.xml}
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<binding name="label">
<lookup name="string" type="GtkStringObject">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
~~~
@@@end
GtkBuilderListItemFactory uses GtkBuilder to extends the GtkListItem with the XML data.
In the xml file above, "GtkListItem" is an instance of the GtkListItem template. In the xml file above, "GtkListItem" is an instance of the GtkListItem template.
It is the 'this' object given to the expressions. It is the 'this' object given to the expressions.
(The information is in the [GTK Development Blog](https://blog.gtk.org/2020/09/)). (The information is in the [GTK Development Blog](https://blog.gtk.org/2020/09/)).
GtkBuilderListItemFactory uses GtkBuilder to build the XML data. GtkBuilder calls `gtk_expression_bind` function when it finds a binding tag.
It sets the current object of the GtkBuilder to the GtkListItem instance.
GtkBuilder calls `gtk_expression_bind` function in the binding tag analysis.
The function sets the 'this' object like this: The function sets the 'this' object like this:
1. If the binding tag has object attribute, the object will be the 'this' object. 1. If the binding tag has object attribute, the object will be the 'this' object.
@ -466,11 +563,12 @@ String duplication is necessary.
The C source file is very simple because almost everything is done in the ui file. The C source file is very simple because almost everything is done in the ui file.
### Conversion between GValues ## Conversion between GValues
If you bind different type properties, type conversion is automatically done. If you bind different type properties, type conversion is automatically done.
Suppose a label property (string) is bound to default-width property (int). Suppose a label property (string) is bound to default-width property (int).
@@@if gfm
~~~xml ~~~xml
<object class="GtkLabel"> <object class="GtkLabel">
<binding name="label"> <binding name="label">
@ -480,6 +578,17 @@ Suppose a label property (string) is bound to default-width property (int).
</binding> </binding>
</object> </object>
~~~ ~~~
@@@else
~~~{.xml}
<object class="GtkLabel">
<binding name="label">
<lookup name="default-width">
win
</lookup>
</binding>
</object>
~~~
@@@end
The expression created by the lookup tag returns a int type GValue. The expression created by the lookup tag returns a int type GValue.
On the other hand "label" property holds a string type GValue. On the other hand "label" property holds a string type GValue.
@ -487,3 +596,23 @@ When a GValue is copied to another GValue, the type is automatically converted i
If the current width is 100, an int `100` is converted to a string `"100"`. If the current width is 100, an int `100` is converted to a string `"100"`.
If you use `g_object_get` and `g_object_set` to copy properties, the value is automatically converted. If you use `g_object_get` and `g_object_set` to copy properties, the value is automatically converted.
## Meson.build
The source files are in `src/expression` directory.
You can build all the files at once.
~~~
$ cd src/expression
$ meson setup _build
$ ninja -C _build
~~~
For example, if you want to run "exp", which is the executable file from "exp.c", type `_build/exp`.
You can run other programs as well.
The file `meson.build` is as follows.
@@@include
expression/meson.build
@@@

View file

@ -60,9 +60,9 @@ This is the title on the header of the column.
- 32: Sets the "expand" property to TRUE to allow the column to expand as much as possible. - 32: Sets the "expand" property to TRUE to allow the column to expand as much as possible.
(See the image above). (See the image above).
- 33- 69: Sets the "factory" property to GtkBuilderListItemFactory. - 33- 69: Sets the "factory" property to GtkBuilderListItemFactory.
The factory has "bytes" property which holds a ui string to define a template to build GtkListItem composite widget. The factory has "bytes" property which holds a ui string to define a template to extend GtkListItem class.
The CDATA section (line 36-66) is the ui string to put into the "bytes" property. The CDATA section (line 36-66) is the ui string to put into the "bytes" property.
The contents are the same as the ui file `factory_list.ui` in the section 27. The contents are the same as the ui file `factory_list.ui` in the section 30.
- 70-77: Sets the "sorter" property to GtkStringSorter object. - 70-77: Sets the "sorter" property to GtkStringSorter object.
This object provides a sorter that compares strings. This object provides a sorter that compares strings.
It has "expression" property. It has "expression" property.
@ -196,7 +196,8 @@ All the source files are in [`src/column`](column) directory.
Change your current directory to the directory and type the following. Change your current directory to the directory and type the following.
~~~ ~~~
$ meson _build $ cd src/colomn
$ meson setup _build
$ ninja -C _build $ ninja -C _build
$ _build/column $ _build/column
~~~ ~~~

View file

@ -6,23 +6,14 @@ GtkBuilderlistItemFactory is convenient when GtkListView just shows the contents
Its binding direction is always from an item of a list to a child of GtkListItem. Its binding direction is always from an item of a list to a child of GtkListItem.
When it comes to dynamic connection, it's not enough. When it comes to dynamic connection, it's not enough.
For example, you want to edit the contents of a list. For example, suppose you want to edit the contents of a list.
You set a child of GtkListItem to a GtkText instance so a user can edit a text with it. You set a child of GtkListItem to a GtkText instance so a user can edit a text with it.
You need to bind an item in the list with the buffer of the GtkText. You need to bind an item in the list with the buffer of the GtkText.
The direction is opposite from the one with GtkBuilderListItemFactory. The direction is opposite from the one with GtkBuilderListItemFactory.
It is from the GtkText instance to the item in the list. It is from the GtkText instance to the item in the list.
You can implement this with GtkSignalListItemFactory, which is more flexible than GtkBuilderListItemFactory. You can implement this with GtkSignalListItemFactory, which is more flexible than GtkBuilderListItemFactory.
Two things are shown in this section. This section shows just some parts of the source file `listeditor.c`.
- Binding from a child of a GtkListItem instance to an item of a list.
- Access a child of GtkListItem dynamically.
This direction is the same as the one with GtkBulderListItemFactory.
But GtkBulderListItemFactory uses GtkExpression from the item property of the GtkListItem.
So, it updates its child widget only when the item property changes.
In this example the child reflects the change in the same item in the list dynamically.
This section shows just a part of the source file `listeditor.c`.
If you want to see the whole codes, see `src/listeditor` directory of the [Gtk4 tutorial repository](https://github.com/ToshioCP/Gtk4-tutorial). If you want to see the whole codes, see `src/listeditor` directory of the [Gtk4 tutorial repository](https://github.com/ToshioCP/Gtk4-tutorial).
## A list editor ## A list editor
@ -33,7 +24,7 @@ It reads a text file line by line.
Each line is an item of the list. Each line is an item of the list.
The list is displayed with GtkColumnView. The list is displayed with GtkColumnView.
There are two columns. There are two columns.
The one is a button, which makes the line be a current line. The one is a button, which shows if the line is a current line.
If the line is the current line, the button is colored with red. If the line is the current line, the button is colored with red.
The other is a string which is the contents of the corresponding item of the list. The other is a string which is the contents of the corresponding item of the list.
@ -47,18 +38,18 @@ You can compile end execute it as follows.
- Type the following on your commandline. - Type the following on your commandline.
~~~ ~~~
$ meson _build $ meson setup _build
$ ninja -C _build $ ninja -C _build
$ _build/listeditor $ _build/listeditor
~~~ ~~~
- Append button: appends a line after the current line, or at the last line if no current line exists. - Append button: appends a line after the current line, or at the last line if no current line exists.
- Insert button: inserts a line before the current line. - Insert button: inserts a line before the current line, or at the top line if no current line exists.
- Remove button: removes a current line. - Remove button: removes a current line.
- Read button: reads a file. - Read button: reads a file.
- Write button: writes the contents to a file. - Write button: writes the contents to a file.
- close button: close the contents. - close button: closes the contents.
- quit button: quit the application. - quit button: quits the application.
- Button on the select column: makes the line current. - Button on the select column: makes the line current.
- String column: GtkText. You can edit a string in the field. - String column: GtkText. You can edit a string in the field.
@ -69,7 +60,7 @@ The file name is shown at the right of the write button.
The second column (GtkColumnViewColumn) sets its factory property to GtkSignalListItemFactory. The second column (GtkColumnViewColumn) sets its factory property to GtkSignalListItemFactory.
It uses three signals setup, bind and unbind. It uses three signals setup, bind and unbind.
The following is their sgnal handlers. The following shows the signal handlers.
@@@include @@@include
listeditor/listeditor.c setup2_cb bind2_cb unbind2_cb listeditor/listeditor.c setup2_cb bind2_cb unbind2_cb
@ -84,17 +75,13 @@ So, teardown signal handler isn't necessary.
It is called when the `listitem` is bound to an item in the list. It is called when the `listitem` is bound to an item in the list.
The list items are LeData instances. The list items are LeData instances.
LeData is defined in the file `listeditor.c` (the C source file of the list editor). LeData is defined in the file `listeditor.c` (the C source file of the list editor).
It is a child class of GObject and has two data. It is a child class of GObject and has string data which is the content of the line.
The one is `listitem` which points a first column GtkListItem instance when they are connected.
Be careful that the GtkListItem instance is *not* the `listitem` in this handler.
If no GtkListItem is connected, it is NULL.
The other is `string` which is a content of the line.
- 10-11: `text` is a child of the `listitem` and it is a GtkText instance. - 10-11: `text` is a child of the `listitem` and it is a GtkText instance.
And `buffer` is a GtkTextBuffer instance of the `text`. And `buffer` is a GtkEntryBuffer instance of the `text`.
- 12: The LeData instance `data` is an item pointed by the `listitem`. - 12: The LeData instance `data` is an item pointed by the `listitem`.
- 15-16: Sets the text of `text` to `le_data_look_string (data)`. - 15-16: Sets the text of `text` to `le_data_look_string (data)`.
le\_data\_look\_string returns the string of the `data` and the ownership of the string is still taken by the `data`. le\_data\_look\_string returns the string of the `data` and the ownership of the string is still taken by the `data`.
So, the caller don't need to free the string. So, the caller doesn't need to free the string.
- 18: `g_object_bind_property` binds a property and another object property. - 18: `g_object_bind_property` binds a property and another object property.
This line binds the "text" property of the `buffer` (source) and the "string" property of the `data` (destination). This line binds the "text" property of the `buffer` (source) and the "string" property of the `data` (destination).
It is a uni-directional binding (`G_BINDING_DEFAULT`). It is a uni-directional binding (`G_BINDING_DEFAULT`).
@ -107,14 +94,19 @@ The key is a string (or GQuark) and the value is a gpointer (pointer to any type
The function `g_object_set_data` sets the association from the key to the value. The function `g_object_set_data` sets the association from the key to the value.
This line sets the association from "bind" to `bind` instance. This line sets the association from "bind" to `bind` instance.
It makes possible for the "unbind" handler to get the `bind` instance. It makes possible for the "unbind" handler to get the `bind` instance.
- 22-28: `unbind2_cb` is a unbind signal handler. - 22-29: `unbind2_cb` is a unbind signal handler.
- 24: Retrieves the `bind` instance from the table in the `listitem` instance. - 24: Retrieves the `bind` instance from the table in the `listitem` instance.
- 26: Unbind the binding. - 26-27: Unbind the binding.
- 27: Removes the value corresponds to the "bind" key. - 28: Removes the value corresponds to the "bind" key.
This technique is not so complicated. This technique is not so complicated.
You can use it when you make a cell editable application. You can use it when you make a cell editable application.
If it is impossible to use `g_object_bind_property`, use a notify signal on the GtkEntryBuffer instance.
You can use "deleted-text" and "inserted-text" signal instead.
The handler of the signals above copies the text in the GtkEntryBuffer instance to the LeData string.
Connect the notify signal handler in `bind2_cb` and disconnect it in `unbind2_cb`.
## Change the cell of GtkColumnView dynamically ## Change the cell of GtkColumnView dynamically
Next topic is to change the GtkColumnView (or GtkListView) cells dynamically. Next topic is to change the GtkColumnView (or GtkListView) cells dynamically.
@ -139,85 +131,79 @@ The current line doesn't need to be on the display.
It is possible to be on the line out of the Window (GtkScrolledWindow). It is possible to be on the line out of the Window (GtkScrolledWindow).
Actually, the program doesn't use GtkSingleSelection. Actually, the program doesn't use GtkSingleSelection.
It is necessary to know the corresponding GtkListItem instance from the item in the list. The LeWindow instance has two instance variables for recording the current line.
It is the opposite direction from `gtk_list_item_get_item` function.
To accomplish this, we set a `listitem` element of LeData to point the corresponding GtkListItem instance. - `win->position`: An int type variable. It is the position of the current line. It is zero-based. If no current line exists, it is -1.
Therefore, items (LeData) in the list always know the GtkListItem. - `win->current_button`: A variable points the button, located at the first column, on the current line. If no current line exists, it is NULL.
If there's no GtkListItem bound to the item, NULL is assigned.
If the current line moves, the following two functions are called.
They updates the two varables.
@@@include @@@include
listeditor/listeditor.c select_cb setup1_cb bind1_cb unbind1_cb listeditor/listeditor.c update_current_position update_current_button
@@@ @@@
- 8-14: `setup1_cb` is a setup signal handler on the GtkSignalListItemFactory. The varable `win->position_label` points a GtkLabel instance.
This factory is inserted to the factory property of the first GtkColumnViewColumn. The label shows the current line position.
The current button has CSS "current" class.
The button is colored red through the CSS "button.current {background: red;}".
The order of the call for these two functions is important.
The first function, which updates the position, is usually called first.
After that, a new line is appended or inserted.
Then, the second function is called.
The following functions call the two functions above.
Be careful about the order of the call.
@@@include
listeditor/listeditor.c select_cb setup1_cb bind1_cb
@@@
- 1-7: `select_cb` is a "clicked" signal handler.
The handler just calls the two functions and update the position and button.
- 9-15: `setup1_cb` is a setup signal handler on the GtkSignalListItemFactory.
It sets the child of `listitem` to a GtkButton instance. It sets the child of `listitem` to a GtkButton instance.
The "clicked" signal on the button is connected to the handler `select_cb`. The "clicked" signal on the button is connected to the handler `select_cb`.
When the listitem is destroyed, the child (GtkButton) is also destroyed. When the listitem is destroyed, the child (GtkButton) is also destroyed.
At the same time, the connection of the signal and the handler is also destroyed. At the same time, the connection of the signal and the handler is also destroyed.
So, you don't need teardown signal handler. So, you don't need teardown signal handler.
- 1-6: `select_cb` is a "clicked" signal handler. - 17-24: `bind1_cb` is a bind signal handler.
LeWindow is defined in `listeditor.c`. Usually, the position moves before this handler is called.
It's a child class of GtkApplicationWindow. If the item is on the current line, the button is updated.
The handler just calls the `update_current` function. No unbind handler is necessary.
The function will be explained later.
- 16-31: `bind1_cb` is a bind signal handler. When a line is added, the current position is updated in advance.
It sets the "listitem" element of the item (LeData) to point the `listitem` (GtkListItem instance).
It makes the item possible to find the corresponding GtkListItem instance.
If the item is the current line, the CSS class of the button includes "current" class.
Otherwise it has no CSS class.
This is necessary because the button may be recycled and it has had former CSS class.
The class need to be updated.
- 33-38: `unbind1_cb` is an unbind signal handler.
It removes the `listitem` instance from the "listitem" element of the item.
The element becomes NULL, which tells no GtkListItem is bound.
When referring GtkListItem, it needs to check the "listitem" element whether it points a GtkListItem or not (NULL).
Otherwise bad things will happen.
@@@include @@@include
listeditor/listeditor.c update_current listeditor/listeditor.c app_cb ins_cb
@@@ @@@
The function `update_current` does several things. When a line is removed, the current position becomes -1 and no button is current.
- It has two parameters. @@@include
The first one is `win`, which is an instance of LeWindow class. listeditor/listeditor.c rm_cb
It has some elements. @@@
- win->position: an Integer. it is the current position. If no current line exists, it is -1.
- win->position_label: GtkLabel. It shows the current position.
- The second parameter is `new`, which is the new current position.
At the beginning of the function, win->position points the old position.
- 10-16: Update the text of GtkLabel.
- 18-26: If the old position (win->position) is not negative, the current line exists.
It gets a GtkListItem instance via the item (LeData) of the list.
And it gets the GtkButton instance which is the child of the GtkListItem.
It clears the "css-classes" property of the button.
- 27: Updates win->position.
- 28-36: If the new position is not negative (It's possible to be negative when the current line has been removed), the current line exists.
It sets the "css-classes" property of the button to `{"current", NULL}`.
It is a NULL-terminated array of strings.
Each string is a CSS class.
Now the button has "current" style class.
The color of buttons are determined by the "background" CSS style. The color of buttons are determined by the "background" CSS style.
The following CSS is applied to the default GdkDisplay in advance (in the startup handler of the application). The following CSS node is a bit complicated.
CSS node `column view` has `listview` child node.
It covers the rows in the GtkColumnView.
The `listview` node is the same as the one for GtkListView.
It has `row` child node, which is for each child widget.
Therefore, the following node corresponds buttons on the GtkColumnView widget.
In addition, it is applied to the "current" class.
@@@if gfm
~~~css ~~~css
columnview listview row button.current {background: red;} columnview listview row button.current {background: red;}
~~~ ~~~
@@@else
The selectors "columnview listview row" is needed before "button" selector. ~~~{.css}
Otherwise the buttons in the GtkColumnview won't be found. columnview listview row button.current {background: red;}
The button selector has "current" class. ~~~
So, the only "current" class button is colored with red. @@@end
Other buttons are not colored, which means they are white.
## Gtk\_widget\_dispose\_template function
The function `gtk_widget_dispose_template` clears the template children for the given widget.
This is the opposite of `gtk_widget_init_template()`.
It is a new function of GTK 4.8 version.
If your GTK version is lower than 4.8, you need to modify the program.
## A waring from GtkText ## A waring from GtkText