Gtk4-tutorial/docs/sec4.html
2023-01-03 15:30:06 +09:00

467 lines
36 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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="sec3.html">Prev: section3</a>
</li>
<li class="nav-item">
<a class="nav-link" href="sec5.html">Next: section5</a>
</li>
</ul>
</div>
</div>
</nav>
<h1 id="widgets-1">Widgets (1)</h1>
<h2 id="gtklabel-gtkbutton-and-gtkbox">GtkLabel, GtkButton and
GtkBox</h2>
<h3 id="gtklabel">GtkLabel</h3>
<p>In the previous section we made a window and displayed it on the
screen. Now we go on to the next topic, where we add widgets to this
window. The simplest widget is GtkLabel. It is a widget with text in
it.</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2"></a></span>
<span id="cb1-3"><a href="#cb1-3"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb1-4"><a href="#cb1-4"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-5"><a href="#cb1-5"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
<span id="cb1-6"><a href="#cb1-6"></a> GtkWidget <span class="op">*</span>lab<span class="op">;</span></span>
<span id="cb1-7"><a href="#cb1-7"></a></span>
<span id="cb1-8"><a href="#cb1-8"></a> win <span class="op">=</span> gtk_application_window_new <span class="op">(</span>GTK_APPLICATION <span class="op">(</span>app<span class="op">));</span></span>
<span id="cb1-9"><a href="#cb1-9"></a> gtk_window_set_title <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="st">&quot;lb1&quot;</span><span class="op">);</span></span>
<span id="cb1-10"><a href="#cb1-10"></a> gtk_window_set_default_size <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="dv">400</span><span class="op">,</span> <span class="dv">300</span><span class="op">);</span></span>
<span id="cb1-11"><a href="#cb1-11"></a></span>
<span id="cb1-12"><a href="#cb1-12"></a> lab <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="cb1-13"><a href="#cb1-13"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> lab<span class="op">);</span></span>
<span id="cb1-14"><a href="#cb1-14"></a></span>
<span id="cb1-15"><a href="#cb1-15"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
<span id="cb1-16"><a href="#cb1-16"></a><span class="op">}</span></span>
<span id="cb1-17"><a href="#cb1-17"></a></span>
<span id="cb1-18"><a href="#cb1-18"></a><span class="dt">int</span></span>
<span id="cb1-19"><a href="#cb1-19"></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="cb1-20"><a href="#cb1-20"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb1-21"><a href="#cb1-21"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb1-22"><a href="#cb1-22"></a></span>
<span id="cb1-23"><a href="#cb1-23"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span><span class="st">&quot;com.github.ToshioCP.lb1&quot;</span><span class="op">,</span> G_APPLICATION_DEFAULT_FLAGS<span class="op">);</span></span>
<span id="cb1-24"><a href="#cb1-24"></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="cb1-25"><a href="#cb1-25"></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="cb1-26"><a href="#cb1-26"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb1-27"><a href="#cb1-27"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb1-28"><a href="#cb1-28"></a><span class="op">}</span></span></code></pre></div>
<p>Save this program to a file <code>lb1.c</code>. Then compile and run
it.</p>
<pre><code>$ comp lb1
$ ./a.out</code></pre>
<p>A window with a message “Hello.” appears.</p>
<figure>
<img src="image/screenshot_lb1.png" alt="Screenshot of the label" />
<figcaption aria-hidden="true">Screenshot of the label</figcaption>
</figure>
<p>Theres only a little change between <code>pr4.c</code> and
<code>lb1.c</code>. A program <code>diff</code> is good to know the
difference between two files.</p>
<pre><code>$ cd misc; diff pr4.c lb1.c
4c4
&lt; app_activate (GApplication *app, gpointer user_data) {
---
&gt; app_activate (GApplication *app) {
5a6
&gt; GtkWidget *lab;
8c9
&lt; gtk_window_set_title (GTK_WINDOW (win), &quot;pr4&quot;);
---
&gt; gtk_window_set_title (GTK_WINDOW (win), &quot;lb1&quot;);
9a11,14
&gt;
&gt; lab = gtk_label_new (&quot;Hello.&quot;);
&gt; gtk_window_set_child (GTK_WINDOW (win), lab);
&gt;
18c23
&lt; app = gtk_application_new (&quot;com.github.ToshioCP.pr4&quot;, G_APPLICATION_DEFAULT_FLAGS);
---
&gt; app = gtk_application_new (&quot;com.github.ToshioCP.lb1&quot;, G_APPLICATION_DEFAULT_FLAGS);</code></pre>
<p>This tells us:</p>
<ul>
<li>A signal handler <code>app_activate</code> doesnt have
<code>user_data</code> parameter. If the fourth argument of
<code>g_signal_connect</code> is NULL, you can leave out
<code>user_data</code>.</li>
<li>The definition of a new variable <code>lab</code> is added.</li>
<li>The title of the window is changed.</li>
<li>A label is created and connected to the window as a child.</li>
</ul>
<p>The function
<code>gtk_window_set_child (GTK_WINDOW (win), lab)</code> makes the
label <code>lab</code> a child widget of the window <code>win</code>. Be
careful. A child widget is different from a child object. Objects have
parent-child relationships and widgets also have parent-child
relationships. But these two relationships are totally different. Dont
be confused. In the program <code>lb1.c</code>, <code>lab</code> is a
child widget of <code>win</code>. Child widgets are always located in
their parent widget on the screen. See how the window has appeared on
the screen. The application window includes the label.</p>
<p>The window <code>win</code> doesnt have any parents. We call such a
window top-level window. An application can have more than one top-level
window.</p>
<h3 id="gtkbutton">GtkButton</h3>
<p>The next widget is GtkButton. It displays a button on the screen with
a label or icon on it. In this subsection, we will make a button with a
label. When the button is clicked, it emits a “clicked” signal. The
following program shows how to catch the signal and do something.</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2"></a></span>
<span id="cb4-3"><a href="#cb4-3"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-4"><a href="#cb4-4"></a>click_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-5"><a href="#cb4-5"></a> g_print <span class="op">(</span><span class="st">&quot;Clicked.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span>
<span id="cb4-6"><a href="#cb4-6"></a><span class="op">}</span></span>
<span id="cb4-7"><a href="#cb4-7"></a></span>
<span id="cb4-8"><a href="#cb4-8"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-9"><a href="#cb4-9"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-10"><a href="#cb4-10"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
<span id="cb4-11"><a href="#cb4-11"></a> GtkWidget <span class="op">*</span>btn<span class="op">;</span></span>
<span id="cb4-12"><a href="#cb4-12"></a></span>
<span id="cb4-13"><a href="#cb4-13"></a> win <span class="op">=</span> gtk_application_window_new <span class="op">(</span>GTK_APPLICATION <span class="op">(</span>app<span class="op">));</span></span>
<span id="cb4-14"><a href="#cb4-14"></a> gtk_window_set_title <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="st">&quot;lb2&quot;</span><span class="op">);</span></span>
<span id="cb4-15"><a href="#cb4-15"></a> gtk_window_set_default_size <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="dv">400</span><span class="op">,</span> <span class="dv">300</span><span class="op">);</span></span>
<span id="cb4-16"><a href="#cb4-16"></a></span>
<span id="cb4-17"><a href="#cb4-17"></a> btn <span class="op">=</span> gtk_button_new_with_label <span class="op">(</span><span class="st">&quot;Click me&quot;</span><span class="op">);</span></span>
<span id="cb4-18"><a href="#cb4-18"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> btn<span class="op">);</span></span>
<span id="cb4-19"><a href="#cb4-19"></a> g_signal_connect <span class="op">(</span>btn<span class="op">,</span> <span class="st">&quot;clicked&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>click_cb<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb4-20"><a href="#cb4-20"></a></span>
<span id="cb4-21"><a href="#cb4-21"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
<span id="cb4-22"><a href="#cb4-22"></a><span class="op">}</span></span>
<span id="cb4-23"><a href="#cb4-23"></a></span>
<span id="cb4-24"><a href="#cb4-24"></a><span class="dt">int</span></span>
<span id="cb4-25"><a href="#cb4-25"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-26"><a href="#cb4-26"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb4-27"><a href="#cb4-27"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb4-28"><a href="#cb4-28"></a></span>
<span id="cb4-29"><a href="#cb4-29"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span><span class="st">&quot;com.github.ToshioCP.lb2&quot;</span><span class="op">,</span> G_APPLICATION_DEFAULT_FLAGS<span class="op">);</span></span>
<span id="cb4-30"><a href="#cb4-30"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb4-31"><a href="#cb4-31"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span>
<span id="cb4-32"><a href="#cb4-32"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb4-33"><a href="#cb4-33"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb4-34"><a href="#cb4-34"></a><span class="op">}</span></span></code></pre></div>
<p>Look at the line 17 to 19. First, it creates a GtkButton instance
<code>btn</code> with a label “Click me”. Then, adds the button to the
window <code>win</code> as a child. Finally, connects a “clicked” signal
of the button to the handler <code>click_cb</code>. So, if
<code>btn</code> is clicked, the function <code>click_cb</code> is
invoked. The suffix “cb” means “call back”.</p>
<p>Name the program <code>lb2.c</code> and save it. Now compile and run
it.</p>
<figure>
<img src="image/screenshot_lb2.png" alt="Screenshot of the label" />
<figcaption aria-hidden="true">Screenshot of the label</figcaption>
</figure>
<p>A window with the button appears. Click the button (it is a large
button, you can click everywhere in the window), then a string
“Clicked.” appears on the terminal. It shows the handler was invoked by
clicking the button.</p>
<p>Its good that we make sure that the clicked signal was caught and
the handler was invoked by using <code>g_print</code>. However, using
<code>g_print</code> is out of harmony with GTK, which is a GUI library.
So, we will change the handler. The following code is
<code>lb3.c</code>.</p>
<div class="sourceCode" id="cb5"><pre
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>
<span id="cb5-2"><a href="#cb5-2"></a>click_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">,</span> GtkWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3"></a> gtk_window_destroy <span class="op">(</span>win<span class="op">);</span></span>
<span id="cb5-4"><a href="#cb5-4"></a><span class="op">}</span></span>
<span id="cb5-5"><a href="#cb5-5"></a></span>
<span id="cb5-6"><a href="#cb5-6"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb5-7"><a href="#cb5-7"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-8"><a href="#cb5-8"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
<span id="cb5-9"><a href="#cb5-9"></a> GtkWidget <span class="op">*</span>btn<span class="op">;</span></span>
<span id="cb5-10"><a href="#cb5-10"></a></span>
<span id="cb5-11"><a href="#cb5-11"></a> win <span class="op">=</span> gtk_application_window_new <span class="op">(</span>GTK_APPLICATION <span class="op">(</span>app<span class="op">));</span></span>
<span id="cb5-12"><a href="#cb5-12"></a> gtk_window_set_title <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="st">&quot;lb3&quot;</span><span class="op">);</span></span>
<span id="cb5-13"><a href="#cb5-13"></a> gtk_window_set_default_size <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="dv">400</span><span class="op">,</span> <span class="dv">300</span><span class="op">);</span></span>
<span id="cb5-14"><a href="#cb5-14"></a></span>
<span id="cb5-15"><a href="#cb5-15"></a> btn <span class="op">=</span> gtk_button_new_with_label <span class="op">(</span><span class="st">&quot;Close&quot;</span><span class="op">);</span></span>
<span id="cb5-16"><a href="#cb5-16"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> btn<span class="op">);</span></span>
<span id="cb5-17"><a href="#cb5-17"></a> g_signal_connect <span class="op">(</span>btn<span class="op">,</span> <span class="st">&quot;clicked&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>click_cb<span class="op">),</span> win<span class="op">);</span></span>
<span id="cb5-18"><a href="#cb5-18"></a></span>
<span id="cb5-19"><a href="#cb5-19"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
<span id="cb5-20"><a href="#cb5-20"></a><span class="op">}</span></span></code></pre></div>
<p>And the difference between <code>lb2.c</code> and <code>lb3.c</code>
is as follows.</p>
<pre><code>$ cd misc; diff lb2.c lb3.c
4,5c4,5
&lt; click_cb (GtkButton *btn) {
&lt; g_print (&quot;Clicked.\n&quot;);
---
&gt; click_cb (GtkButton *btn, GtkWindow *win) {
&gt; gtk_window_destroy (win);
14c14
&lt; gtk_window_set_title (GTK_WINDOW (win), &quot;lb2&quot;);
---
&gt; gtk_window_set_title (GTK_WINDOW (win), &quot;lb3&quot;);
17c17
&lt; btn = gtk_button_new_with_label (&quot;Click me&quot;);
---
&gt; btn = gtk_button_new_with_label (&quot;Close&quot;);
19c19
&lt; g_signal_connect (btn, &quot;clicked&quot;, G_CALLBACK (click_cb), NULL);
---
&gt; g_signal_connect (btn, &quot;clicked&quot;, G_CALLBACK (click_cb), win);
29c29
&lt; app = gtk_application_new (&quot;com.github.ToshioCP.lb2&quot;, G_APPLICATION_DEFAULT_FLAGS);
---
&gt; app = gtk_application_new (&quot;com.github.ToshioCP.lb3&quot;, G_APPLICATION_DEFAULT_FLAGS);
35d34
&lt; </code></pre>
<p>The changes are:</p>
<ul>
<li>The function <code>g_print</code> in <code>lb2.c</code> was deleted
and two lines are inserted.
<ul>
<li><code>click_cb</code> has the second parameter, which comes from the
fourth argument of the <code>g_signal_connect</code> at the line 19. One
thing to be careful is the types are different between the second
parameter of <code>click_cb</code> and the fourth argument of
<code>g_signal_connect</code>. The former is <code>GtkWindow *</code>
and the latter is <code>GtkWidget *</code>. The compiler doesnt
complain because <code>g_signal_connect</code> uses gpointer (general
type of pointer). In this program the instance pointed by
<code>win</code> is a GtkApplicationWindow object. It is a descendant of
GtkWindow and GtkWidget class, so both <code>GtkWindow *</code> and
<code>GtkWidget *</code> are correct types for the instance.</li>
<li><code>gtk_destroy (win)</code> destroys the top-level window. Then
the application quits.</li>
</ul></li>
<li>The label of <code>btn</code> is changed from “Click me” to
“Close”.</li>
<li>The fourth argument of <code>g_signal_connect</code> is changed from
<code>NULL</code> to <code>win</code>.</li>
</ul>
<p>The most important change is the fourth argument of the
<code>g_signal_connect</code>. This argument is described as “data to
pass to handler” in the definition of <a
href="https://docs.gtk.org/gobject/func.signal_connect.html"><code>g_signal_connect</code></a>.</p>
<h3 id="gtkbox">GtkBox</h3>
<p>GtkWindow and GtkApplicationWindow can have only one child. If you
want to add two or more widgets in a window, you need a container
widget. GtkBox is one of the containers. It arranges two or more child
widgets into a single row or column. The following procedure shows the
way to add two buttons in a window.</p>
<ul>
<li>Create a GtkApplicationWindow instance.</li>
<li>Create a GtkBox instance and add it to the GtkApplicationWindow as a
child.</li>
<li>Create a GtkButton instance and append it to the GtkBox.</li>
<li>Create another GtkButton instance and append it to the GtkBox.</li>
</ul>
<p>After this, the Widgets are connected as the following diagram.</p>
<figure>
<img src="image/box.png" alt="Parent-child relationship" />
<figcaption aria-hidden="true">Parent-child relationship</figcaption>
</figure>
<p>The program <code>lb4.c</code> is as follows.</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb7-2"><a href="#cb7-2"></a></span>
<span id="cb7-3"><a href="#cb7-3"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb7-4"><a href="#cb7-4"></a>click1_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-5"><a href="#cb7-5"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>s<span class="op">;</span></span>
<span id="cb7-6"><a href="#cb7-6"></a></span>
<span id="cb7-7"><a href="#cb7-7"></a> s <span class="op">=</span> gtk_button_get_label <span class="op">(</span>btn<span class="op">);</span></span>
<span id="cb7-8"><a href="#cb7-8"></a> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span>s<span class="op">,</span> <span class="st">&quot;Hello.&quot;</span><span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb7-9"><a href="#cb7-9"></a> gtk_button_set_label <span class="op">(</span>btn<span class="op">,</span> <span class="st">&quot;Good-bye.&quot;</span><span class="op">);</span></span>
<span id="cb7-10"><a href="#cb7-10"></a> <span class="cf">else</span></span>
<span id="cb7-11"><a href="#cb7-11"></a> gtk_button_set_label <span class="op">(</span>btn<span class="op">,</span> <span class="st">&quot;Hello.&quot;</span><span class="op">);</span></span>
<span id="cb7-12"><a href="#cb7-12"></a><span class="op">}</span></span>
<span id="cb7-13"><a href="#cb7-13"></a></span>
<span id="cb7-14"><a href="#cb7-14"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb7-15"><a href="#cb7-15"></a>click2_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">,</span> GtkWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-16"><a href="#cb7-16"></a> gtk_window_destroy <span class="op">(</span>win<span class="op">);</span></span>
<span id="cb7-17"><a href="#cb7-17"></a><span class="op">}</span></span>
<span id="cb7-18"><a href="#cb7-18"></a></span>
<span id="cb7-19"><a href="#cb7-19"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb7-20"><a href="#cb7-20"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-21"><a href="#cb7-21"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
<span id="cb7-22"><a href="#cb7-22"></a> GtkWidget <span class="op">*</span>box<span class="op">;</span></span>
<span id="cb7-23"><a href="#cb7-23"></a> GtkWidget <span class="op">*</span>btn1<span class="op">;</span></span>
<span id="cb7-24"><a href="#cb7-24"></a> GtkWidget <span class="op">*</span>btn2<span class="op">;</span></span>
<span id="cb7-25"><a href="#cb7-25"></a></span>
<span id="cb7-26"><a href="#cb7-26"></a> win <span class="op">=</span> gtk_application_window_new <span class="op">(</span>GTK_APPLICATION <span class="op">(</span>app<span class="op">));</span></span>
<span id="cb7-27"><a href="#cb7-27"></a> gtk_window_set_title <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="st">&quot;lb4&quot;</span><span class="op">);</span></span>
<span id="cb7-28"><a href="#cb7-28"></a> gtk_window_set_default_size <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="dv">400</span><span class="op">,</span> <span class="dv">300</span><span class="op">);</span></span>
<span id="cb7-29"><a href="#cb7-29"></a></span>
<span id="cb7-30"><a href="#cb7-30"></a> box <span class="op">=</span> gtk_box_new <span class="op">(</span>GTK_ORIENTATION_VERTICAL<span class="op">,</span> <span class="dv">5</span><span class="op">);</span></span>
<span id="cb7-31"><a href="#cb7-31"></a> gtk_box_set_homogeneous <span class="op">(</span>GTK_BOX <span class="op">(</span>box<span class="op">),</span> TRUE<span class="op">);</span></span>
<span id="cb7-32"><a href="#cb7-32"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> box<span class="op">);</span></span>
<span id="cb7-33"><a href="#cb7-33"></a></span>
<span id="cb7-34"><a href="#cb7-34"></a> btn1 <span class="op">=</span> gtk_button_new_with_label <span class="op">(</span><span class="st">&quot;Hello.&quot;</span><span class="op">);</span></span>
<span id="cb7-35"><a href="#cb7-35"></a> g_signal_connect <span class="op">(</span>btn1<span class="op">,</span> <span class="st">&quot;clicked&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>click1_cb<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb7-36"><a href="#cb7-36"></a></span>
<span id="cb7-37"><a href="#cb7-37"></a> btn2 <span class="op">=</span> gtk_button_new_with_label <span class="op">(</span><span class="st">&quot;Close&quot;</span><span class="op">);</span></span>
<span id="cb7-38"><a href="#cb7-38"></a> g_signal_connect <span class="op">(</span>btn2<span class="op">,</span> <span class="st">&quot;clicked&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>click2_cb<span class="op">),</span> win<span class="op">);</span></span>
<span id="cb7-39"><a href="#cb7-39"></a></span>
<span id="cb7-40"><a href="#cb7-40"></a> gtk_box_append <span class="op">(</span>GTK_BOX <span class="op">(</span>box<span class="op">),</span> btn1<span class="op">);</span></span>
<span id="cb7-41"><a href="#cb7-41"></a> gtk_box_append <span class="op">(</span>GTK_BOX <span class="op">(</span>box<span class="op">),</span> btn2<span class="op">);</span></span>
<span id="cb7-42"><a href="#cb7-42"></a></span>
<span id="cb7-43"><a href="#cb7-43"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
<span id="cb7-44"><a href="#cb7-44"></a><span class="op">}</span></span>
<span id="cb7-45"><a href="#cb7-45"></a></span>
<span id="cb7-46"><a href="#cb7-46"></a><span class="dt">int</span></span>
<span id="cb7-47"><a href="#cb7-47"></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-48"><a href="#cb7-48"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb7-49"><a href="#cb7-49"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb7-50"><a href="#cb7-50"></a></span>
<span id="cb7-51"><a href="#cb7-51"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span><span class="st">&quot;com.github.ToshioCP.lb4&quot;</span><span class="op">,</span> G_APPLICATION_DEFAULT_FLAGS<span class="op">);</span></span>
<span id="cb7-52"><a href="#cb7-52"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb7-53"><a href="#cb7-53"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span>
<span id="cb7-54"><a href="#cb7-54"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb7-55"><a href="#cb7-55"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb7-56"><a href="#cb7-56"></a><span class="op">}</span></span></code></pre></div>
<p>Look at the function <code>app_activate</code>.</p>
<p>After the creation of a GtkApplicationWindow instance, a GtkBox
instance is created.</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>box <span class="op">=</span> gtk_box_new<span class="op">(</span>GTK_ORIENTATION_VERTICAL<span class="op">,</span> <span class="dv">5</span><span class="op">);</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>gtk_box_set_homogeneous <span class="op">(</span>GTK_BOX <span class="op">(</span>box<span class="op">),</span> TRUE<span class="op">);</span></span></code></pre></div>
<p>The first argument arranges the children of the box vertically. The
orientation constants are defined like this:</p>
<ul>
<li>GTK_ORIENTATION_VERTICAL: the children widgets are arranged
vertically</li>
<li>GTK_ORIENTATION_HORIZONTAL: the children widgets are arranged
horizontally</li>
</ul>
<p>The second argument is the size between the children. The unit of the
length is pixel.</p>
<p>The next function fills the box with the children, giving them the
same space.</p>
<p>After that, two buttons <code>btn1</code> and <code>btn2</code> are
created and the signal handlers are set. Then, these two buttons are
appended to the box.</p>
<div class="sourceCode" id="cb9"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb9-2"><a href="#cb9-2"></a>click1_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-3"><a href="#cb9-3"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>s<span class="op">;</span></span>
<span id="cb9-4"><a href="#cb9-4"></a></span>
<span id="cb9-5"><a href="#cb9-5"></a> s <span class="op">=</span> gtk_button_get_label <span class="op">(</span>btn<span class="op">);</span></span>
<span id="cb9-6"><a href="#cb9-6"></a> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span>s<span class="op">,</span> <span class="st">&quot;Hello.&quot;</span><span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb9-7"><a href="#cb9-7"></a> gtk_button_set_label <span class="op">(</span>btn<span class="op">,</span> <span class="st">&quot;Good-bye.&quot;</span><span class="op">);</span></span>
<span id="cb9-8"><a href="#cb9-8"></a> <span class="cf">else</span></span>
<span id="cb9-9"><a href="#cb9-9"></a> gtk_button_set_label <span class="op">(</span>btn<span class="op">,</span> <span class="st">&quot;Hello.&quot;</span><span class="op">);</span></span>
<span id="cb9-10"><a href="#cb9-10"></a><span class="op">}</span></span></code></pre></div>
<p>The function <code>gtk_button_get_lable</code> returns a text from
the label. The string is owned by the button and you cant modify or
free it. The <code>const</code> qualifier is necessary for the string
<code>s</code>. If you change the string, your compiler will give you a
waring.</p>
<p>You always need to be careful with the const qualifier when you see
the GTK 4 API reference.</p>
<figure>
<img src="image/screenshot_lb4.png" alt="Screenshot of the box" />
<figcaption aria-hidden="true">Screenshot of the box</figcaption>
</figure>
<p>The handler corresponds to <code>btn1</code> toggles its label. The
handler corresponds to <code>btn2</code> destroys the top-level window
and the application quits.</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</body>
</html>