mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2024-11-16 19:50:35 +01:00
659 lines
61 KiB
HTML
659 lines
61 KiB
HTML
<!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="sec25.html">Prev: section25</a>
|
||
</li>
|
||
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="sec27.html">Next: section27</a>
|
||
</li>
|
||
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
<h1 id="gtklistview">GtkListView</h1>
|
||
<p>GTK 4 has added new list objects GtkListView, GtkGridView and
|
||
GtkColumnView. The new feature is described in <a
|
||
href="https://docs.gtk.org/gtk4/section-list-widget.html">Gtk API
|
||
Reference, List Widget Overview</a>.</p>
|
||
<p>GTK 4 has other means to implement lists. They are GtkListBox and
|
||
GtkTreeView which are took over from GTK 3. There’s an article in <a
|
||
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
|
||
why GtkListView are developed to replace GtkListBox and GtkTreeView.</p>
|
||
<p>I want to explain GtkListView and its related objects in this
|
||
tutorial.</p>
|
||
<h2 id="outline">Outline</h2>
|
||
<p>A list is a sequential data structure. For example, an ordered string
|
||
sequence “one”, “two”, “three”, “four” is a list. Each element of the
|
||
list is called item. A list is like an array, but in many cases it is
|
||
implemented with pointers which point to the next item of the list. And
|
||
it has a start point. So, each item can be referred by the index of the
|
||
item (first item, second item, …, nth item, …). There are two cases. One
|
||
is the index starts from one (one-based) and the other is it starts from
|
||
zero (zero-based).</p>
|
||
<p>Gio provides GListModel interface. It is a zero-based list of the
|
||
same type of GObject objects, or objects that implement the same
|
||
interface. An object implements GListModel is usually not a widget. So,
|
||
the list is not displayed on the screen directly. There’s another object
|
||
GtkListView which is a widget to display the list. The items in the list
|
||
need to be connected to the items in GtkListView. GtkListItemFactory
|
||
object maps items in the list to GListView.</p>
|
||
<figure>
|
||
<img src="image/list.png" alt="List" />
|
||
<figcaption aria-hidden="true">List</figcaption>
|
||
</figure>
|
||
<p>The instruction to build the whole list related objects is:</p>
|
||
<ol type="1">
|
||
<li>Implement the list object which implements GListModel.</li>
|
||
<li>Build widgets and put GtkListView as a child of
|
||
GtkScrolledWindow.</li>
|
||
<li>Set GtkListItemFactory.</li>
|
||
</ol>
|
||
<h2 id="glistmodel">GListModel</h2>
|
||
<p>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. So, you need a wrapper which is a GObject and contains
|
||
a string. GtkStringObject is the wrapper object and GStringList,
|
||
implements GListModel, is a list of GtkStringObject.</p>
|
||
<div class="sourceCode" id="cb1"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span> <span class="op">*</span>array<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span><span class="st">"one"</span><span class="op">,</span> <span class="st">"two"</span><span class="op">,</span> <span class="st">"three"</span><span class="op">,</span> <span class="st">"four"</span><span class="op">,</span> NULL<span class="op">};</span></span>
|
||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>GtkStringList <span class="op">*</span>stringlist <span class="op">=</span> gtk_string_list_new <span class="op">((</span><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span> <span class="dt">const</span> <span class="op">*)</span> array<span class="op">);</span></span></code></pre></div>
|
||
<p>The function <code>gtk_string_list_new</code> creates GtkStringList
|
||
object. Its items are GtkStringObject objects which contain the strings
|
||
“one”, “two”, “three” and “four”. There are functions to add items to
|
||
the list or remove items from the list.</p>
|
||
<ul>
|
||
<li><code>gtk_string_list_append</code> appends an item to the list</li>
|
||
<li><code>gtk_string_list_remove</code> removes an item from the
|
||
list</li>
|
||
<li><code>gtk_string_list_get_string</code> gets a string in the
|
||
list</li>
|
||
</ul>
|
||
<p>See <a href="https://docs.gtk.org/gtk4/class.StringList.html">GTK 4
|
||
API Reference, GtkStringList</a> for further information.</p>
|
||
<p>I’ll explain the other list objects later.</p>
|
||
<h2 id="gtkselectionmodel">GtkSelectionModel</h2>
|
||
<p>GtkSelectionModel is an interface to support for selections. Thanks
|
||
to this model, user can select items by clicking on them. It is
|
||
implemented by GtkMultiSelection, GtkNoSelection and GtkSingleSelection
|
||
objects. These three objects are usually enough to build an application.
|
||
They are created with GListModel. You can also create them alone and add
|
||
GListModel later.</p>
|
||
<ul>
|
||
<li>GtkMultiSelection supports multiple selection.</li>
|
||
<li>GtkNoSelection supports no selection. This is a wrapper to
|
||
GListModel when GtkSelectionModel is needed.</li>
|
||
<li>GtkSingleSelection supports single selection.</li>
|
||
</ul>
|
||
<h2 id="gtklistview-1">GtkListView</h2>
|
||
<p>GtkListView is a widget to show GListModel items. GtkListItem is used
|
||
by GtkListView to represent items of a list model. But, GtkListItem
|
||
itself is not a widget, so a user needs to set a widget, for example
|
||
GtkLabel, as a child of GtkListItem to display an item of the list
|
||
model. “item” property of GtkListItem points an object that belongs to
|
||
the list model.</p>
|
||
<figure>
|
||
<img src="image/gtklistitem.png" alt="GtkListItem" />
|
||
<figcaption aria-hidden="true">GtkListItem</figcaption>
|
||
</figure>
|
||
<p>In case the number of items is very big, for example more than a
|
||
thousand, GtkListItem is recycled and connected to another item which is
|
||
newly displayed. This recycle makes the number of GtkListItem objects
|
||
fairly small, less than 200. This is very effective to restrain the
|
||
growth of memory consumption so that GListModel can contain lots of
|
||
items, for example, more than a million items.</p>
|
||
<h2 id="gtklistitemfactory">GtkListItemFactory</h2>
|
||
<p>GtkListItemFactory creates or recycles GtkListItem and connects it
|
||
with an item of the list model. There are two child objects of this
|
||
factory, GtkSignalListItemFactory and GtkBuilderListItemFactory.</p>
|
||
<h3 id="gtksignallistitemfactory">GtkSignalListItemFactory</h3>
|
||
<p>GtkSignalListItemFactory provides signals for users to configure a
|
||
GtkListItem object. There are four signals.</p>
|
||
<ol type="1">
|
||
<li>“setup” is emitted to set up GtkListItem object. A user sets its
|
||
child widget in the handler. For example, creates a GtkLabel widget and
|
||
sets the child property of GtkListItem to it. This setting is kept even
|
||
the GtkListItem instance is recycled (to bind to another item of
|
||
GListModel).</li>
|
||
<li>“bind” is emitted to bind an item in the list model to the widget.
|
||
For example, a user gets the item from “item” property of the
|
||
GtkListItem instance. Then gets the string of the item and sets the
|
||
label property of the GtkLabel instance with the string. This signal is
|
||
emitted when the GtkListItem is newly created, recycled or some changes
|
||
has happened to the item of the list.</li>
|
||
<li>“unbind” is emitted to unbind an item. A user undoes everything done
|
||
in step 2 in the signal handler. If some object are created in step 2,
|
||
they must be destroyed.</li>
|
||
<li>“teardown” is emitted to undo everything done in step 1. So, the
|
||
widget created in step 1 must be destroyed. After this signal, the list
|
||
item will be destroyed.</li>
|
||
</ol>
|
||
<p>The following program <code>list1.c</code> shows the list of strings
|
||
“one”, “two”, “three” and “four”. GtkNoSelection is used, so user can’t
|
||
select any item.</p>
|
||
<div class="sourceCode" id="cb2"><pre
|
||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||
<span id="cb2-2"><a href="#cb2-2"></a></span>
|
||
<span id="cb2-3"><a href="#cb2-3"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb2-4"><a href="#cb2-4"></a>setup_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="cb2-5"><a href="#cb2-5"></a> GtkWidget <span class="op">*</span>lb <span class="op">=</span> gtk_label_new <span class="op">(</span>NULL<span class="op">);</span></span>
|
||
<span id="cb2-6"><a href="#cb2-6"></a> gtk_list_item_set_child <span class="op">(</span>listitem<span class="op">,</span> lb<span class="op">);</span></span>
|
||
<span id="cb2-7"><a href="#cb2-7"></a><span class="op">}</span></span>
|
||
<span id="cb2-8"><a href="#cb2-8"></a></span>
|
||
<span id="cb2-9"><a href="#cb2-9"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb2-10"><a href="#cb2-10"></a>bind_cb <span class="op">(</span>GtkSignalListItemFactory <span class="op">*</span>self<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb2-11"><a href="#cb2-11"></a> GtkWidget <span class="op">*</span>lb <span class="op">=</span> gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">);</span></span>
|
||
<span id="cb2-12"><a href="#cb2-12"></a> GtkStringObject <span class="op">*</span>strobj <span class="op">=</span> gtk_list_item_get_item <span class="op">(</span>listitem<span class="op">);</span></span>
|
||
<span id="cb2-13"><a href="#cb2-13"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>text <span class="op">=</span> gtk_string_object_get_string <span class="op">(</span>strobj<span class="op">);</span></span>
|
||
<span id="cb2-14"><a href="#cb2-14"></a></span>
|
||
<span id="cb2-15"><a href="#cb2-15"></a> gtk_label_set_text <span class="op">(</span>GTK_LABEL <span class="op">(</span>lb<span class="op">),</span> text<span class="op">);</span></span>
|
||
<span id="cb2-16"><a href="#cb2-16"></a><span class="op">}</span></span>
|
||
<span id="cb2-17"><a href="#cb2-17"></a></span>
|
||
<span id="cb2-18"><a href="#cb2-18"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb2-19"><a href="#cb2-19"></a>unbind_cb <span class="op">(</span>GtkSignalListItemFactory <span class="op">*</span>self<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb2-20"><a href="#cb2-20"></a> <span class="co">/* There's nothing to do here. */</span></span>
|
||
<span id="cb2-21"><a href="#cb2-21"></a> <span class="co">/* If you does something like setting a signal in bind_cb, */</span></span>
|
||
<span id="cb2-22"><a href="#cb2-22"></a> <span class="co">/* then disconnecting the signal is necessary in unbind_cb. */</span></span>
|
||
<span id="cb2-23"><a href="#cb2-23"></a><span class="op">}</span></span>
|
||
<span id="cb2-24"><a href="#cb2-24"></a></span>
|
||
<span id="cb2-25"><a href="#cb2-25"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb2-26"><a href="#cb2-26"></a>teardown_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="cb2-27"><a href="#cb2-27"></a> gtk_list_item_set_child <span class="op">(</span>listitem<span class="op">,</span> NULL<span class="op">);</span></span>
|
||
<span id="cb2-28"><a href="#cb2-28"></a><span class="co">/* When the child of listitem is set to NULL, the reference to GtkLabel will be released and lb will be destroyed. */</span></span>
|
||
<span id="cb2-29"><a href="#cb2-29"></a><span class="co">/* Therefore, g_object_unref () for the GtkLabel object doesn't need in the user code. */</span></span>
|
||
<span id="cb2-30"><a href="#cb2-30"></a><span class="op">}</span></span>
|
||
<span id="cb2-31"><a href="#cb2-31"></a></span>
|
||
<span id="cb2-32"><a href="#cb2-32"></a><span class="co">/* ----- activate, open, startup handlers ----- */</span></span>
|
||
<span id="cb2-33"><a href="#cb2-33"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb2-34"><a href="#cb2-34"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb2-35"><a href="#cb2-35"></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="cb2-36"><a href="#cb2-36"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> gtk_application_window_new <span class="op">(</span>app<span class="op">);</span></span>
|
||
<span id="cb2-37"><a href="#cb2-37"></a> gtk_window_set_default_size <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="dv">600</span><span class="op">,</span> <span class="dv">400</span><span class="op">);</span></span>
|
||
<span id="cb2-38"><a href="#cb2-38"></a> GtkWidget <span class="op">*</span>scr <span class="op">=</span> gtk_scrolled_window_new <span class="op">();</span></span>
|
||
<span id="cb2-39"><a href="#cb2-39"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> scr<span class="op">);</span></span>
|
||
<span id="cb2-40"><a href="#cb2-40"></a></span>
|
||
<span id="cb2-41"><a href="#cb2-41"></a> <span class="dt">char</span> <span class="op">*</span>array<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span></span>
|
||
<span id="cb2-42"><a href="#cb2-42"></a> <span class="st">"one"</span><span class="op">,</span> <span class="st">"two"</span><span class="op">,</span> <span class="st">"three"</span><span class="op">,</span> <span class="st">"four"</span><span class="op">,</span> NULL</span>
|
||
<span id="cb2-43"><a href="#cb2-43"></a> <span class="op">};</span></span>
|
||
<span id="cb2-44"><a href="#cb2-44"></a> GtkStringList <span class="op">*</span>sl <span class="op">=</span> gtk_string_list_new <span class="op">((</span><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span> <span class="dt">const</span> <span class="op">*)</span> array<span class="op">);</span></span>
|
||
<span id="cb2-45"><a href="#cb2-45"></a> GtkNoSelection <span class="op">*</span>ns <span class="op">=</span> gtk_no_selection_new <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>sl<span class="op">));</span></span>
|
||
<span id="cb2-46"><a href="#cb2-46"></a></span>
|
||
<span id="cb2-47"><a href="#cb2-47"></a> GtkListItemFactory <span class="op">*</span>factory <span class="op">=</span> gtk_signal_list_item_factory_new <span class="op">();</span></span>
|
||
<span id="cb2-48"><a href="#cb2-48"></a> g_signal_connect <span class="op">(</span>factory<span class="op">,</span> <span class="st">"setup"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>setup_cb<span class="op">),</span> NULL<span class="op">);</span></span>
|
||
<span id="cb2-49"><a href="#cb2-49"></a> g_signal_connect <span class="op">(</span>factory<span class="op">,</span> <span class="st">"bind"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>bind_cb<span class="op">),</span> NULL<span class="op">);</span></span>
|
||
<span id="cb2-50"><a href="#cb2-50"></a> g_signal_connect <span class="op">(</span>factory<span class="op">,</span> <span class="st">"unbind"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>unbind_cb<span class="op">),</span> NULL<span class="op">);</span></span>
|
||
<span id="cb2-51"><a href="#cb2-51"></a> g_signal_connect <span class="op">(</span>factory<span class="op">,</span> <span class="st">"teardown"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>teardown_cb<span class="op">),</span> NULL<span class="op">);</span></span>
|
||
<span id="cb2-52"><a href="#cb2-52"></a></span>
|
||
<span id="cb2-53"><a href="#cb2-53"></a> GtkWidget <span class="op">*</span>lv <span class="op">=</span> gtk_list_view_new <span class="op">(</span>GTK_SELECTION_MODEL <span class="op">(</span>ns<span class="op">),</span> factory<span class="op">);</span></span>
|
||
<span id="cb2-54"><a href="#cb2-54"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> lv<span class="op">);</span></span>
|
||
<span id="cb2-55"><a href="#cb2-55"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||
<span id="cb2-56"><a href="#cb2-56"></a><span class="op">}</span></span>
|
||
<span id="cb2-57"><a href="#cb2-57"></a></span>
|
||
<span id="cb2-58"><a href="#cb2-58"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb2-59"><a href="#cb2-59"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb2-60"><a href="#cb2-60"></a><span class="op">}</span></span>
|
||
<span id="cb2-61"><a href="#cb2-61"></a></span>
|
||
<span id="cb2-62"><a href="#cb2-62"></a><span class="co">/* ----- main ----- */</span></span>
|
||
<span id="cb2-63"><a href="#cb2-63"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.list1"</span></span>
|
||
<span id="cb2-64"><a href="#cb2-64"></a></span>
|
||
<span id="cb2-65"><a href="#cb2-65"></a><span class="dt">int</span></span>
|
||
<span id="cb2-66"><a href="#cb2-66"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb2-67"><a href="#cb2-67"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||
<span id="cb2-68"><a href="#cb2-68"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||
<span id="cb2-69"><a href="#cb2-69"></a></span>
|
||
<span id="cb2-70"><a href="#cb2-70"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_FLAGS_NONE<span class="op">);</span></span>
|
||
<span id="cb2-71"><a href="#cb2-71"></a></span>
|
||
<span id="cb2-72"><a href="#cb2-72"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">"startup"</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="cb2-73"><a href="#cb2-73"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">"activate"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
|
||
<span id="cb2-74"><a href="#cb2-74"></a></span>
|
||
<span id="cb2-75"><a href="#cb2-75"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span>
|
||
<span id="cb2-76"><a href="#cb2-76"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||
<span id="cb2-77"><a href="#cb2-77"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||
<span id="cb2-78"><a href="#cb2-78"></a><span class="op">}</span></span></code></pre></div>
|
||
<p>The file <code>list1.c</code> is located under the directory
|
||
src/misc. Make a shell script below and save it to your bin directory.
|
||
(If you’ve installed GTK 4 from the source to $HOME/local, then your bin
|
||
directory is $Home/local/bin. Otherwise, $Home/bin is your private bin
|
||
directory.)</p>
|
||
<div class="sourceCode" id="cb3"><pre
|
||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gcc</span> <span class="kw">`</span><span class="ex">pkg-config</span> <span class="at">--cflags</span> gtk4<span class="kw">`</span> <span class="va">$1</span>.c <span class="kw">`</span><span class="ex">pkg-config</span> <span class="at">--libs</span> gtk4<span class="kw">`</span></span></code></pre></div>
|
||
<p>Change the current directory to the directory includes
|
||
<code>list1.c</code> and type as follows.</p>
|
||
<pre><code>$ chmod 755 $HOME/local/bin/comp # or chmod 755 $Home/bin/comp
|
||
$ comp list1
|
||
$ ./a.out</code></pre>
|
||
<p>Then, <code>list1.c</code> has been compiled and executed.</p>
|
||
<figure>
|
||
<img src="image/list1.png" alt="list1" />
|
||
<figcaption aria-hidden="true">list1</figcaption>
|
||
</figure>
|
||
<p>I think the program is not so difficult. If you feel some difficulty,
|
||
read this section again, especially GtkSignalListItemFactory
|
||
subsubsection.</p>
|
||
<h3 id="gtkbuilderlistitemfactory">GtkBuilderListItemFactory</h3>
|
||
<p>GtkBuilderListItemFactory is another GtkListItemFactory. Its behavior
|
||
is defined with ui file.</p>
|
||
<div class="sourceCode" id="cb5"><pre
|
||
class="sourceCode xml"><code class="sourceCode xml"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><<span class="kw">interface</span>></span>
|
||
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> <<span class="kw">template</span><span class="ot"> class=</span><span class="st">"GtkListItem"</span>></span>
|
||
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"child"</span>></span>
|
||
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span>></span>
|
||
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a> <<span class="kw">binding</span><span class="ot"> name=</span><span class="st">"label"</span>></span>
|
||
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"string"</span><span class="ot"> type=</span><span class="st">"GtkStringObject"</span>></span>
|
||
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"item"</span>>GtkListItem</<span class="kw">lookup</span>></span>
|
||
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a> </<span class="kw">lookup</span>></span>
|
||
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a> </<span class="kw">binding</span>></span>
|
||
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a> </<span class="kw">object</span>></span>
|
||
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a> </<span class="kw">property</span>></span>
|
||
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a> </<span class="kw">template</span>></span>
|
||
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a></<span class="kw">interface</span>></span></code></pre></div>
|
||
<p>Template tag is used to define GtkListItem. And its child property is
|
||
GtkLabel object. The factory sees this template and creates GtkLabel and
|
||
sets the child property of GtkListItem. This is the same as what setup
|
||
handler of GtkSignalListItemFactory did.</p>
|
||
<p>Then, bind the label property of GtkLabel to string property of
|
||
GtkStringObject. The string object is referred to by item property of
|
||
GtkListItem. So, the lookup tag is like this:</p>
|
||
<pre><code>string <- GtkStringObject <- item <- GtkListItem</code></pre>
|
||
<p>The last lookup tag has a content <code>GtkListItem</code>. Usually,
|
||
C type like <code>GtkListItem</code> doesn’t appear in the content of
|
||
tags. This is a special case. There is an explanation about it in the <a
|
||
href="https://blog.gtk.org/2020/09/05/a-primer-on-gtklistview/">GTK
|
||
Development Blog</a> by Matthias Clasen.</p>
|
||
<blockquote>
|
||
<p>Remember that the classname (GtkListItem) in a ui template is used as
|
||
the “this” pointer referring to the object that is being
|
||
instantiated.</p>
|
||
</blockquote>
|
||
<p>Therefore, GtkListItem instance is used as the <code>this</code>
|
||
object of the lookup tag when it is evaluated. <code>this</code> object
|
||
will be explained in <a href="sec28.html">section 28</a>.</p>
|
||
<p>The C source code is as follows. Its name is <code>list2.c</code> and
|
||
located under src/misc directory.</p>
|
||
<div class="sourceCode" id="cb7"><pre
|
||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||
<span id="cb7-2"><a href="#cb7-2"></a></span>
|
||
<span id="cb7-3"><a href="#cb7-3"></a><span class="co">/* ----- activate, open, startup handlers ----- */</span></span>
|
||
<span id="cb7-4"><a href="#cb7-4"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb7-5"><a href="#cb7-5"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb7-6"><a href="#cb7-6"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
|
||
<span id="cb7-7"><a href="#cb7-7"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> gtk_application_window_new <span class="op">(</span>app<span class="op">);</span></span>
|
||
<span id="cb7-8"><a href="#cb7-8"></a> gtk_window_set_default_size <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="dv">600</span><span class="op">,</span> <span class="dv">400</span><span class="op">);</span></span>
|
||
<span id="cb7-9"><a href="#cb7-9"></a> GtkWidget <span class="op">*</span>scr <span class="op">=</span> gtk_scrolled_window_new <span class="op">();</span></span>
|
||
<span id="cb7-10"><a href="#cb7-10"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> scr<span class="op">);</span></span>
|
||
<span id="cb7-11"><a href="#cb7-11"></a></span>
|
||
<span id="cb7-12"><a href="#cb7-12"></a> <span class="dt">char</span> <span class="op">*</span>array<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span></span>
|
||
<span id="cb7-13"><a href="#cb7-13"></a> <span class="st">"one"</span><span class="op">,</span> <span class="st">"two"</span><span class="op">,</span> <span class="st">"three"</span><span class="op">,</span> <span class="st">"four"</span><span class="op">,</span> NULL</span>
|
||
<span id="cb7-14"><a href="#cb7-14"></a> <span class="op">};</span></span>
|
||
<span id="cb7-15"><a href="#cb7-15"></a> GtkStringList <span class="op">*</span>sl <span class="op">=</span> gtk_string_list_new <span class="op">((</span><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span> <span class="dt">const</span> <span class="op">*)</span> array<span class="op">);</span></span>
|
||
<span id="cb7-16"><a href="#cb7-16"></a> GtkSingleSelection <span class="op">*</span>ss <span class="op">=</span> gtk_single_selection_new <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>sl<span class="op">));</span></span>
|
||
<span id="cb7-17"><a href="#cb7-17"></a></span>
|
||
<span id="cb7-18"><a href="#cb7-18"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>ui_string <span class="op">=</span></span>
|
||
<span id="cb7-19"><a href="#cb7-19"></a><span class="st">"<interface>"</span></span>
|
||
<span id="cb7-20"><a href="#cb7-20"></a> <span class="st">"<template class=</span><span class="sc">\"</span><span class="st">GtkListItem</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb7-21"><a href="#cb7-21"></a> <span class="st">"<property name=</span><span class="sc">\"</span><span class="st">child</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb7-22"><a href="#cb7-22"></a> <span class="st">"<object class=</span><span class="sc">\"</span><span class="st">GtkLabel</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb7-23"><a href="#cb7-23"></a> <span class="st">"<binding name=</span><span class="sc">\"</span><span class="st">label</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb7-24"><a href="#cb7-24"></a> <span class="st">"<lookup name=</span><span class="sc">\"</span><span class="st">string</span><span class="sc">\"</span><span class="st"> type=</span><span class="sc">\"</span><span class="st">GtkStringObject</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb7-25"><a href="#cb7-25"></a> <span class="st">"<lookup name=</span><span class="sc">\"</span><span class="st">item</span><span class="sc">\"</span><span class="st">>GtkListItem</lookup>"</span></span>
|
||
<span id="cb7-26"><a href="#cb7-26"></a> <span class="st">"</lookup>"</span></span>
|
||
<span id="cb7-27"><a href="#cb7-27"></a> <span class="st">"</binding>"</span></span>
|
||
<span id="cb7-28"><a href="#cb7-28"></a> <span class="st">"</object>"</span></span>
|
||
<span id="cb7-29"><a href="#cb7-29"></a> <span class="st">"</property>"</span></span>
|
||
<span id="cb7-30"><a href="#cb7-30"></a> <span class="st">"</template>"</span></span>
|
||
<span id="cb7-31"><a href="#cb7-31"></a><span class="st">"</interface>"</span></span>
|
||
<span id="cb7-32"><a href="#cb7-32"></a><span class="op">;</span></span>
|
||
<span id="cb7-33"><a href="#cb7-33"></a> GBytes <span class="op">*</span>gbytes <span class="op">=</span> g_bytes_new_static <span class="op">(</span>ui_string<span class="op">,</span> strlen <span class="op">(</span>ui_string<span class="op">));</span></span>
|
||
<span id="cb7-34"><a href="#cb7-34"></a> GtkListItemFactory <span class="op">*</span>factory <span class="op">=</span> gtk_builder_list_item_factory_new_from_bytes <span class="op">(</span>NULL<span class="op">,</span> gbytes<span class="op">);</span></span>
|
||
<span id="cb7-35"><a href="#cb7-35"></a></span>
|
||
<span id="cb7-36"><a href="#cb7-36"></a> GtkWidget <span class="op">*</span>lv <span class="op">=</span> gtk_list_view_new <span class="op">(</span>GTK_SELECTION_MODEL <span class="op">(</span>ss<span class="op">),</span> factory<span class="op">);</span></span>
|
||
<span id="cb7-37"><a href="#cb7-37"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> lv<span class="op">);</span></span>
|
||
<span id="cb7-38"><a href="#cb7-38"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||
<span id="cb7-39"><a href="#cb7-39"></a><span class="op">}</span></span>
|
||
<span id="cb7-40"><a href="#cb7-40"></a></span>
|
||
<span id="cb7-41"><a href="#cb7-41"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb7-42"><a href="#cb7-42"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb7-43"><a href="#cb7-43"></a><span class="op">}</span></span>
|
||
<span id="cb7-44"><a href="#cb7-44"></a></span>
|
||
<span id="cb7-45"><a href="#cb7-45"></a><span class="co">/* ----- main ----- */</span></span>
|
||
<span id="cb7-46"><a href="#cb7-46"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.list2"</span></span>
|
||
<span id="cb7-47"><a href="#cb7-47"></a></span>
|
||
<span id="cb7-48"><a href="#cb7-48"></a><span class="dt">int</span></span>
|
||
<span id="cb7-49"><a href="#cb7-49"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb7-50"><a href="#cb7-50"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||
<span id="cb7-51"><a href="#cb7-51"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||
<span id="cb7-52"><a href="#cb7-52"></a></span>
|
||
<span id="cb7-53"><a href="#cb7-53"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_FLAGS_NONE<span class="op">);</span></span>
|
||
<span id="cb7-54"><a href="#cb7-54"></a></span>
|
||
<span id="cb7-55"><a href="#cb7-55"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">"startup"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span>
|
||
<span id="cb7-56"><a href="#cb7-56"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">"activate"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
|
||
<span id="cb7-57"><a href="#cb7-57"></a></span>
|
||
<span id="cb7-58"><a href="#cb7-58"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span>
|
||
<span id="cb7-59"><a href="#cb7-59"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||
<span id="cb7-60"><a href="#cb7-60"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||
<span id="cb7-61"><a href="#cb7-61"></a><span class="op">}</span></span></code></pre></div>
|
||
<p>No signal handler is needed for GtkBulderListItemFactory.
|
||
GtkSingleSelection is used, so user can select one item at a time.</p>
|
||
<p>Because this is a small program, the ui data is given as a
|
||
string.</p>
|
||
<h2 id="gtkdirectorylist">GtkDirectoryList</h2>
|
||
<p>GtkDirectoryList is a list model containing GFileInfo objects which
|
||
are information of files under a certain directory. It uses
|
||
<code>g_file_enumerate_children_async()</code> to get the GFileInfo
|
||
objects. The list model is created by
|
||
<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>
|
||
<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
|
||
name. For example, “standard::name” key is the name of a file.
|
||
“standard” means general file information. “name” means filename. The
|
||
following table shows some example.</p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 19%" />
|
||
<col style="width: 80%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">key</th>
|
||
<th style="text-align: left;">meaning</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;">standard::type</td>
|
||
<td style="text-align: left;">file type. for example, regular file,
|
||
directory, symbolic link, etc.</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;">standard::name</td>
|
||
<td style="text-align: left;">filename</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;">standard::size</td>
|
||
<td style="text-align: left;">file size in bytes</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;">access::can-read</td>
|
||
<td style="text-align: left;">read privilege if the user is able to read
|
||
the file</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;">time::modified</td>
|
||
<td style="text-align: left;">the time the file was last modified in
|
||
seconds since the UNIX epoch</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>The current directory is “.”. The following program makes
|
||
GtkDirectoryList <code>dl</code> and its contents are GFileInfo objects
|
||
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">"."</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">"standard::name"</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>
|
||
<p>It is not so difficult to make file listing program by changing
|
||
<code>list2.c</code> in the previous subsection. One problem is that
|
||
GInfoFile doesn’t have properties. Lookup tag look for a property, so it
|
||
is useless for looking for a filename from a GFileInfo object. Instead,
|
||
closure tag is appropriate in this case. Closure tag specifies a
|
||
function and the type of the return value of the function.</p>
|
||
<div class="sourceCode" id="cb10"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span> <span class="op">*</span></span>
|
||
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>get_file_name <span class="op">(</span>GtkListItem <span class="op">*</span>item<span class="op">,</span> GFileInfo <span class="op">*</span>info<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(!</span> G_IS_FILE_INFO <span class="op">(</span>info<span class="op">))</span></span>
|
||
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> NULL<span class="op">;</span></span>
|
||
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span></span>
|
||
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> g_strdup <span class="op">(</span>g_file_info_get_name <span class="op">(</span>info<span class="op">));</span></span>
|
||
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span></span>
|
||
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span></span>
|
||
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a><span class="st">"<interface>"</span></span>
|
||
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a> <span class="st">"<template class=</span><span class="sc">\"</span><span class="st">GtkListItem</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a> <span class="st">"<property name=</span><span class="sc">\"</span><span class="st">child</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a> <span class="st">"<object class=</span><span class="sc">\"</span><span class="st">GtkLabel</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a> <span class="st">"<binding name=</span><span class="sc">\"</span><span class="st">label</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a> <span class="st">"<closure type=</span><span class="sc">\"</span><span class="st">gchararray</span><span class="sc">\"</span><span class="st"> function=</span><span class="sc">\"</span><span class="st">get_file_name</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a> <span class="st">"<lookup name=</span><span class="sc">\"</span><span class="st">item</span><span class="sc">\"</span><span class="st">>GtkListItem</lookup>"</span></span>
|
||
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true" tabindex="-1"></a> <span class="st">"</closure>"</span></span>
|
||
<span id="cb10-20"><a href="#cb10-20" aria-hidden="true" tabindex="-1"></a> <span class="st">"</binding>"</span></span>
|
||
<span id="cb10-21"><a href="#cb10-21" aria-hidden="true" tabindex="-1"></a> <span class="st">"</object>"</span></span>
|
||
<span id="cb10-22"><a href="#cb10-22" aria-hidden="true" tabindex="-1"></a> <span class="st">"</property>"</span></span>
|
||
<span id="cb10-23"><a href="#cb10-23" aria-hidden="true" tabindex="-1"></a> <span class="st">"</template>"</span></span>
|
||
<span id="cb10-24"><a href="#cb10-24" aria-hidden="true" tabindex="-1"></a><span class="st">"</interface>"</span></span></code></pre></div>
|
||
<ul>
|
||
<li>“gchararray” is the type name of strings. “gchar” is the same as
|
||
“char” type. Therefore, “gchararray” is “an array of char type”, which
|
||
is the same as string type. It is used to get the type of GValue object.
|
||
GValue is a generic value and it can contain various type of values. For
|
||
example, the type name can be gboolean, gchar (char), gint (int), gfloat
|
||
(float), gdouble (double), gchararray (char *) and so on. These type
|
||
names are the names of the fundamental types that are registered to the
|
||
type system. See <a
|
||
href="https://github.com/ToshioCP/Gobject-tutorial/blob/main/gfm/sec5.md#gvalue">GObject
|
||
tutorial</a>.</li>
|
||
<li>closure tag has type attribute and function attribute. Function
|
||
attribute specifies the function name and type attribute specifies the
|
||
type of the return value of the function. The contents of closure tag
|
||
(it is between <closure…> and</closure>) is parameters of
|
||
the function.
|
||
<code><lookup name="item">GtkListItem</lookup></code> gives
|
||
the value of the item property of the GtkListItem. This will be the
|
||
second argument of the function. The first parameter is always the
|
||
GListItem instance.</li>
|
||
<li><code>gtk_file_name</code> function first check the
|
||
<code>info</code> parameter. Because it can be NULL when GListItem
|
||
<code>item</code> is unbound. If its GFileInfo, then return the filename
|
||
(copy of the filename).</li>
|
||
</ul>
|
||
<p>The whole program (<code>list3.c</code>) is as follows. The program
|
||
is located in src/misc directory.</p>
|
||
<div class="sourceCode" id="cb11"><pre
|
||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb11-1"><a href="#cb11-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||
<span id="cb11-2"><a href="#cb11-2"></a></span>
|
||
<span id="cb11-3"><a href="#cb11-3"></a><span class="dt">char</span> <span class="op">*</span></span>
|
||
<span id="cb11-4"><a href="#cb11-4"></a>get_file_name <span class="op">(</span>GtkListItem <span class="op">*</span>item<span class="op">,</span> GFileInfo <span class="op">*</span>info<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb11-5"><a href="#cb11-5"></a> <span class="cf">if</span> <span class="op">(!</span> G_IS_FILE_INFO <span class="op">(</span>info<span class="op">))</span></span>
|
||
<span id="cb11-6"><a href="#cb11-6"></a> <span class="cf">return</span> NULL<span class="op">;</span></span>
|
||
<span id="cb11-7"><a href="#cb11-7"></a> <span class="cf">else</span></span>
|
||
<span id="cb11-8"><a href="#cb11-8"></a> <span class="cf">return</span> g_strdup <span class="op">(</span>g_file_info_get_name <span class="op">(</span>info<span class="op">));</span></span>
|
||
<span id="cb11-9"><a href="#cb11-9"></a><span class="op">}</span></span>
|
||
<span id="cb11-10"><a href="#cb11-10"></a></span>
|
||
<span id="cb11-11"><a href="#cb11-11"></a><span class="co">/* ----- activate, open, startup handlers ----- */</span></span>
|
||
<span id="cb11-12"><a href="#cb11-12"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb11-13"><a href="#cb11-13"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb11-14"><a href="#cb11-14"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
|
||
<span id="cb11-15"><a href="#cb11-15"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> gtk_application_window_new <span class="op">(</span>app<span class="op">);</span></span>
|
||
<span id="cb11-16"><a href="#cb11-16"></a> gtk_window_set_default_size <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="dv">600</span><span class="op">,</span> <span class="dv">400</span><span class="op">);</span></span>
|
||
<span id="cb11-17"><a href="#cb11-17"></a> GtkWidget <span class="op">*</span>scr <span class="op">=</span> gtk_scrolled_window_new <span class="op">();</span></span>
|
||
<span id="cb11-18"><a href="#cb11-18"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> scr<span class="op">);</span></span>
|
||
<span id="cb11-19"><a href="#cb11-19"></a></span>
|
||
<span id="cb11-20"><a href="#cb11-20"></a> GFile <span class="op">*</span>file <span class="op">=</span> g_file_new_for_path <span class="op">(</span><span class="st">"."</span><span class="op">);</span></span>
|
||
<span id="cb11-21"><a href="#cb11-21"></a> GtkDirectoryList <span class="op">*</span>dl <span class="op">=</span> gtk_directory_list_new <span class="op">(</span><span class="st">"standard::name"</span><span class="op">,</span> file<span class="op">);</span></span>
|
||
<span id="cb11-22"><a href="#cb11-22"></a> g_object_unref <span class="op">(</span>file<span class="op">);</span></span>
|
||
<span id="cb11-23"><a href="#cb11-23"></a> GtkNoSelection <span class="op">*</span>ns <span class="op">=</span> gtk_no_selection_new <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>dl<span class="op">));</span></span>
|
||
<span id="cb11-24"><a href="#cb11-24"></a></span>
|
||
<span id="cb11-25"><a href="#cb11-25"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>ui_string <span class="op">=</span></span>
|
||
<span id="cb11-26"><a href="#cb11-26"></a><span class="st">"<interface>"</span></span>
|
||
<span id="cb11-27"><a href="#cb11-27"></a> <span class="st">"<template class=</span><span class="sc">\"</span><span class="st">GtkListItem</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb11-28"><a href="#cb11-28"></a> <span class="st">"<property name=</span><span class="sc">\"</span><span class="st">child</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb11-29"><a href="#cb11-29"></a> <span class="st">"<object class=</span><span class="sc">\"</span><span class="st">GtkLabel</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb11-30"><a href="#cb11-30"></a> <span class="st">"<binding name=</span><span class="sc">\"</span><span class="st">label</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb11-31"><a href="#cb11-31"></a> <span class="st">"<closure type=</span><span class="sc">\"</span><span class="st">gchararray</span><span class="sc">\"</span><span class="st"> function=</span><span class="sc">\"</span><span class="st">get_file_name</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb11-32"><a href="#cb11-32"></a> <span class="st">"<lookup name=</span><span class="sc">\"</span><span class="st">item</span><span class="sc">\"</span><span class="st">>GtkListItem</lookup>"</span></span>
|
||
<span id="cb11-33"><a href="#cb11-33"></a> <span class="st">"</closure>"</span></span>
|
||
<span id="cb11-34"><a href="#cb11-34"></a> <span class="st">"</binding>"</span></span>
|
||
<span id="cb11-35"><a href="#cb11-35"></a> <span class="st">"</object>"</span></span>
|
||
<span id="cb11-36"><a href="#cb11-36"></a> <span class="st">"</property>"</span></span>
|
||
<span id="cb11-37"><a href="#cb11-37"></a> <span class="st">"</template>"</span></span>
|
||
<span id="cb11-38"><a href="#cb11-38"></a><span class="st">"</interface>"</span></span>
|
||
<span id="cb11-39"><a href="#cb11-39"></a><span class="op">;</span></span>
|
||
<span id="cb11-40"><a href="#cb11-40"></a> GBytes <span class="op">*</span>gbytes <span class="op">=</span> g_bytes_new_static <span class="op">(</span>ui_string<span class="op">,</span> strlen <span class="op">(</span>ui_string<span class="op">));</span></span>
|
||
<span id="cb11-41"><a href="#cb11-41"></a> GtkListItemFactory <span class="op">*</span>factory <span class="op">=</span> gtk_builder_list_item_factory_new_from_bytes <span class="op">(</span>NULL<span class="op">,</span> gbytes<span class="op">);</span></span>
|
||
<span id="cb11-42"><a href="#cb11-42"></a></span>
|
||
<span id="cb11-43"><a href="#cb11-43"></a> GtkWidget <span class="op">*</span>lv <span class="op">=</span> gtk_list_view_new <span class="op">(</span>GTK_SELECTION_MODEL <span class="op">(</span>ns<span class="op">),</span> factory<span class="op">);</span></span>
|
||
<span id="cb11-44"><a href="#cb11-44"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> lv<span class="op">);</span></span>
|
||
<span id="cb11-45"><a href="#cb11-45"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||
<span id="cb11-46"><a href="#cb11-46"></a><span class="op">}</span></span>
|
||
<span id="cb11-47"><a href="#cb11-47"></a></span>
|
||
<span id="cb11-48"><a href="#cb11-48"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb11-49"><a href="#cb11-49"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb11-50"><a href="#cb11-50"></a><span class="op">}</span></span>
|
||
<span id="cb11-51"><a href="#cb11-51"></a></span>
|
||
<span id="cb11-52"><a href="#cb11-52"></a><span class="co">/* ----- main ----- */</span></span>
|
||
<span id="cb11-53"><a href="#cb11-53"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.list3"</span></span>
|
||
<span id="cb11-54"><a href="#cb11-54"></a></span>
|
||
<span id="cb11-55"><a href="#cb11-55"></a><span class="dt">int</span></span>
|
||
<span id="cb11-56"><a href="#cb11-56"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb11-57"><a href="#cb11-57"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||
<span id="cb11-58"><a href="#cb11-58"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||
<span id="cb11-59"><a href="#cb11-59"></a></span>
|
||
<span id="cb11-60"><a href="#cb11-60"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_FLAGS_NONE<span class="op">);</span></span>
|
||
<span id="cb11-61"><a href="#cb11-61"></a></span>
|
||
<span id="cb11-62"><a href="#cb11-62"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">"startup"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span>
|
||
<span id="cb11-63"><a href="#cb11-63"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">"activate"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
|
||
<span id="cb11-64"><a href="#cb11-64"></a></span>
|
||
<span id="cb11-65"><a href="#cb11-65"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span>
|
||
<span id="cb11-66"><a href="#cb11-66"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||
<span id="cb11-67"><a href="#cb11-67"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||
<span id="cb11-68"><a href="#cb11-68"></a><span class="op">}</span></span></code></pre></div>
|
||
<p>The ui data (xml data above) is used to build the GListItem template
|
||
at runtime. GtkBuilder refers to the symbol table to find the function
|
||
<code>get_file_name</code>.</p>
|
||
<p>Generally, a symbol table is used by a linker to link objects to an
|
||
executable file. It includes function names and their location. A linker
|
||
usually doesn’t put a symbol table into the created executable file. But
|
||
if <code>--export-dynamic</code> option is given, the linker adds the
|
||
symbol table to the executable file.</p>
|
||
<p>To accomplish it, an option <code>-Wl,--export-dynamic</code> is
|
||
given to the C compiler.</p>
|
||
<ul>
|
||
<li><code>-Wl</code> is a C compiler option that passes the following
|
||
option to the linker.</li>
|
||
<li><code>--export-dynamic</code> is a linker option. The following is
|
||
cited from the linker document. “When creating a dynamically linked
|
||
executable, add all symbols to the dynamic symbol table. The dynamic
|
||
symbol table is the set of symbols which are visible from dynamic
|
||
objects at run time.”</li>
|
||
</ul>
|
||
<p>Compile and execute it.</p>
|
||
<pre><code>$ gcc -Wl,--export-dynamic `pkg-config --cflags gtk4` list3.c `pkg-config --libs gtk4`</code></pre>
|
||
<p>You can also make a shell script to compile <code>list3.c</code></p>
|
||
<div class="sourceCode" id="cb13"><pre
|
||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gcc</span> <span class="at">-Wl,--export-dynamic</span> <span class="kw">`</span><span class="ex">pkg-config</span> <span class="at">--cflags</span> gtk4<span class="kw">`</span> <span class="va">$1</span>.c <span class="kw">`</span><span class="ex">pkg-config</span> <span class="at">--libs</span> gtk4<span class="kw">`</span></span></code></pre></div>
|
||
<p>Save this one liner to a file <code>comp</code>. Then, copy it to
|
||
<code>$HOME/bin</code> and give it executable permission.</p>
|
||
<pre><code>$ cp comp $HOME/bin/comp
|
||
$ chmod +x $HOME/bin/comp</code></pre>
|
||
<p>You can compile <code>list3.c</code> and execute it, like this:</p>
|
||
<pre><code>$ comp list3
|
||
$ ./a.out</code></pre>
|
||
<figure>
|
||
<img src="image/list3.png" alt="screenshot list3" />
|
||
<figcaption aria-hidden="true">screenshot list3</figcaption>
|
||
</figure>
|
||
</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>
|