Gtk4-tutorial/docs/sec20.html

645 lines
61 KiB
HTML
Raw Normal View History

<!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="sec19.html">Prev: section19</a>
</li>
<li class="nav-item">
<a class="nav-link" href="sec21.html">Next: section21</a>
</li>
</ul>
</div>
</div>
</nav>
<h1 id="composite-widgets-and-alert-dialog">Composite widgets and alert
dialog</h1>
<p>The source files are in the <a
href="https://github.com/ToshioCP/Gtk4-tutorial">Gtk4 tutorial GitHub
repository</a>. Download it and see <code>src/tfe6</code> directory.</p>
<h2 id="an-outline-of-new-tfe-text-editor">An outline of new Tfe text
editor</h2>
<p>Tfe text editor will be restructured. The program is divided into six
parts.</p>
<ul>
<li>Main program: the C main function.</li>
<li>TfeApplication object: It is like GtkApplication but keeps GSettings
and CSS Provider.</li>
<li>TfeWindow object: It is a window with buttons and a notebook.</li>
<li>TfePref object: A preference dialog.</li>
<li>TfeAlert object: An alert dialog.</li>
<li>pdf2css.h and pdf2css.c: Font and CSS utility functions.</li>
</ul>
<p>This section describes TfeAlert. Others will be explained in the
following sections.</p>
<h2 id="composite-widgets">Composite widgets</h2>
<p>The alert dialog is like this:</p>
2023-01-03 07:30:06 +01:00
<figure>
<img src="image/alert.png" alt="Alert dialog" />
<figcaption aria-hidden="true">Alert dialog</figcaption>
2023-01-03 07:30:06 +01:00
</figure>
<p>Tfe uses it when a user quits the application or closes a notebook
without saving data to files.</p>
<p>The dialog has a title, buttons, an icon and a message. Therefore, it
consists of several widgets. Such dialog is called a composite
widget.</p>
<p>Composite widgets are defined with template XMLs. The class is built
in the class initialization function and the instances are built and
desposed by the following functions.</p>
<ul>
<li>gtk_widget_init_template</li>
<li>gtk_widget_dispose_template</li>
</ul>
<p>TfeAlert is a good example to know composite widgets. It is defined
with the three files.</p>
<ul>
<li>tfealert.ui: XML file</li>
<li>tfealert.h: Header file</li>
<li>tfealert.c: C program file</li>
</ul>
<h2 id="the-xml-file">The XML file</h2>
<p>A template tag is used in a composite widget XML.</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb1-1"><a href="#cb1-1"></a><span class="fu">&lt;?xml</span><span class="ot"> version=</span><span class="st">&quot;1.0&quot;</span><span class="ot"> encoding=</span><span class="st">&quot;UTF-8&quot;</span><span class="fu">?&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2"></a>&lt;<span class="kw">interface</span>&gt;</span>
<span id="cb1-3"><a href="#cb1-3"></a> &lt;<span class="kw">template</span><span class="ot"> class=</span><span class="st">&quot;TfeAlert&quot;</span><span class="ot"> parent=</span><span class="st">&quot;GtkWindow&quot;</span>&gt;</span>
<span id="cb1-4"><a href="#cb1-4"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;resizable&quot;</span>&gt;FALSE&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-5"><a href="#cb1-5"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;modal&quot;</span>&gt;TRUE&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-6"><a href="#cb1-6"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;titlebar&quot;</span>&gt;</span>
<span id="cb1-7"><a href="#cb1-7"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkHeaderBar&quot;</span>&gt;</span>
<span id="cb1-8"><a href="#cb1-8"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;show-title-buttons&quot;</span>&gt;FALSE&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-9"><a href="#cb1-9"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;title-widget&quot;</span>&gt;</span>
<span id="cb1-10"><a href="#cb1-10"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span><span class="ot"> id=</span><span class="st">&quot;lb_title&quot;</span>&gt;</span>
<span id="cb1-11"><a href="#cb1-11"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;Are you sure?&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-12"><a href="#cb1-12"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;single-line-mode&quot;</span>&gt;True&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-13"><a href="#cb1-13"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-14"><a href="#cb1-14"></a> &lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-15"><a href="#cb1-15"></a> &lt;<span class="kw">child</span><span class="ot"> type=</span><span class="st">&quot;start&quot;</span>&gt;</span>
<span id="cb1-16"><a href="#cb1-16"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkButton&quot;</span><span class="ot"> id=</span><span class="st">&quot;btn_cancel&quot;</span>&gt;</span>
<span id="cb1-17"><a href="#cb1-17"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;Cancel&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-18"><a href="#cb1-18"></a> &lt;<span class="kw">style</span>&gt;</span>
<span id="cb1-19"><a href="#cb1-19"></a> &lt;<span class="kw">class</span><span class="ot"> name=</span><span class="st">&quot;suggested-action&quot;</span>/&gt;</span>
<span id="cb1-20"><a href="#cb1-20"></a> &lt;/<span class="kw">style</span>&gt;</span>
<span id="cb1-21"><a href="#cb1-21"></a> &lt;<span class="kw">signal</span><span class="ot"> name=</span><span class="st">&quot;clicked&quot;</span><span class="ot"> handler=</span><span class="st">&quot;cancel_cb&quot;</span><span class="ot"> swapped=</span><span class="st">&quot;TRUE&quot;</span><span class="ot"> object=</span><span class="st">&quot;TfeAlert&quot;</span>&gt;&lt;/<span class="kw">signal</span>&gt;</span>
<span id="cb1-22"><a href="#cb1-22"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-23"><a href="#cb1-23"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb1-24"><a href="#cb1-24"></a> &lt;<span class="kw">child</span><span class="ot"> type=</span><span class="st">&quot;end&quot;</span>&gt;</span>
<span id="cb1-25"><a href="#cb1-25"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkButton&quot;</span><span class="ot"> id=</span><span class="st">&quot;btn_accept&quot;</span>&gt;</span>
<span id="cb1-26"><a href="#cb1-26"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span>&gt;Close&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-27"><a href="#cb1-27"></a> &lt;<span class="kw">style</span>&gt;</span>
<span id="cb1-28"><a href="#cb1-28"></a> &lt;<span class="kw">class</span><span class="ot"> name=</span><span class="st">&quot;destructive-action&quot;</span>/&gt;</span>
<span id="cb1-29"><a href="#cb1-29"></a> &lt;/<span class="kw">style</span>&gt;</span>
<span id="cb1-30"><a href="#cb1-30"></a> &lt;<span class="kw">signal</span><span class="ot"> name=</span><span class="st">&quot;clicked&quot;</span><span class="ot"> handler=</span><span class="st">&quot;accept_cb&quot;</span><span class="ot"> swapped=</span><span class="st">&quot;TRUE&quot;</span><span class="ot"> object=</span><span class="st">&quot;TfeAlert&quot;</span>&gt;&lt;/<span class="kw">signal</span>&gt;</span>
<span id="cb1-31"><a href="#cb1-31"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-32"><a href="#cb1-32"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb1-33"><a href="#cb1-33"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-34"><a href="#cb1-34"></a> &lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-35"><a href="#cb1-35"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb1-36"><a href="#cb1-36"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkBox&quot;</span>&gt;</span>
<span id="cb1-37"><a href="#cb1-37"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;orientation&quot;</span>&gt;GTK_ORIENTATION_HORIZONTAL&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-38"><a href="#cb1-38"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;spacing&quot;</span>&gt;12&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-39"><a href="#cb1-39"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;margin-top&quot;</span>&gt;12&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-40"><a href="#cb1-40"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;margin-bottom&quot;</span>&gt;12&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-41"><a href="#cb1-41"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;margin-start&quot;</span>&gt;12&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-42"><a href="#cb1-42"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;margin-end&quot;</span>&gt;12&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-43"><a href="#cb1-43"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb1-44"><a href="#cb1-44"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkImage&quot;</span>&gt;</span>
<span id="cb1-45"><a href="#cb1-45"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;icon-name&quot;</span>&gt;dialog-warning&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-46"><a href="#cb1-46"></a> &lt;<span class="kw">property</span><span class="ot"> name=</span><span class="st">&quot;icon-size&quot;</span>&gt;GTK_ICON_SIZE_LARGE&lt;/<span class="kw">property</span>&gt;</span>
<span id="cb1-47"><a href="#cb1-47"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-48"><a href="#cb1-48"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb1-49"><a href="#cb1-49"></a> &lt;<span class="kw">child</span>&gt;</span>
<span id="cb1-50"><a href="#cb1-50"></a> &lt;<span class="kw">object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span><span class="ot"> id=</span><span class="st">&quot;lb_message&quot;</span>&gt;</span>
<span id="cb1-51"><a href="#cb1-51"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-52"><a href="#cb1-52"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb1-53"><a href="#cb1-53"></a> &lt;/<span class="kw">object</span>&gt;</span>
<span id="cb1-54"><a href="#cb1-54"></a> &lt;/<span class="kw">child</span>&gt;</span>
<span id="cb1-55"><a href="#cb1-55"></a> &lt;/<span class="kw">template</span>&gt;</span>
<span id="cb1-56"><a href="#cb1-56"></a>&lt;/<span class="kw">interface</span>&gt;</span></code></pre></div>
2023-01-03 07:30:06 +01:00
<ul>
<li>3: A template tag defines a composite widget. The class attribute
tells the class name of the composite widget. The parent attribute tells
the parent class of the composite widget. So, TfeAlert is a child class
of GtkWindow. A parent attribute is an option and you can leave it out.
But it is recommended to write it in the template tag.</li>
<li>4-6: Its three properties are defined. These properties are
inherited from GtkWindow. The titlebar property has a widget for a
custom title bar. The typical widget is GtkHeaderBar.</li>
<li>8: If the property “show-title-buttons” is TRUE, the title buttons
like close, minimize and maximize are shown. Otherwise it is not shown.
The TfeAlert object is not resizable. It is closed when either of the
two buttons, cancel or accept, is clicked. Therefore the title buttons
are not necessary and this property is set to FALSE.</li>
<li>9-14: The bar has a title, which is a GtkLabel widget. The default
title is “Are you sure?” but it can be replaced by an instance
method.</li>
<li>15-32: The bar has two buttons, cancel and accept. The cancel button
is on the left so the child tag has <code>type="start"</code> attribute.
The accept button is on the right so the child tag has
<code>type="end"</code> attribute. The dialog is shown when the user
clicked the close button or the quit menu without saving the data.
Therefore, it is safer for the user to click on the cancel button of the
alert dialog. So, the cancel button has a “suggested-action” CSS class.
Ubuntu colors the button green but the color can be blue or other
appropriate one defined by the system. In the same way the accept button
has a “destructive-action” CSS class and is colored red. Two buttons
have signals which are defined by the signal tags.</li>
<li>35-54: A horizontal box has an image icon and a label.</li>
<li>44-47: The GtkImage widget displays an image. The “icon-name”
property is an icon name in the icon theme. The theme depends on your
system. You can check it with an icon browser.</li>
</ul>
<pre><code>$ gtk4-icon-browser</code></pre>
2023-01-03 07:30:06 +01:00
<p>The “dialog-warning” icon is something like this.</p>
<figure>
<img src="image/dialog_warning.png"
alt="dialog-warning icon is like …" />
<figcaption aria-hidden="true">dialog-warning icon is like
</figcaption>
</figure>
<p>These are made by my hand. The real image on the alert dialog is
nicer.</p>
<p>It is possible to define the alert widget as a child of GtkDialog.
But GtkDialog is deprecated since GTK version 4.10. And users should use
GtkWindow instead of GtkDialog.</p>
<h2 id="the-header-file">The header file</h2>
<p>The header file is similar to the one of TfeTextView.</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a><span class="pp">#pragma once</span></span>
<span id="cb3-2"><a href="#cb3-2"></a></span>
<span id="cb3-3"><a href="#cb3-3"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb3-4"><a href="#cb3-4"></a></span>
<span id="cb3-5"><a href="#cb3-5"></a><span class="pp">#define TFE_TYPE_ALERT tfe_alert_get_type ()</span></span>
<span id="cb3-6"><a href="#cb3-6"></a>G_DECLARE_FINAL_TYPE <span class="op">(</span>TfeAlert<span class="op">,</span> tfe_alert<span class="op">,</span> TFE<span class="op">,</span> ALERT<span class="op">,</span> GtkWindow<span class="op">)</span></span>
<span id="cb3-7"><a href="#cb3-7"></a></span>
<span id="cb3-8"><a href="#cb3-8"></a><span class="co">/* &quot;response&quot; signal id */</span></span>
<span id="cb3-9"><a href="#cb3-9"></a><span class="kw">enum</span> TfeAlertResponseType</span>
<span id="cb3-10"><a href="#cb3-10"></a><span class="op">{</span></span>
<span id="cb3-11"><a href="#cb3-11"></a> TFE_ALERT_RESPONSE_ACCEPT<span class="op">,</span></span>
<span id="cb3-12"><a href="#cb3-12"></a> TFE_ALERT_RESPONSE_CANCEL</span>
<span id="cb3-13"><a href="#cb3-13"></a><span class="op">};</span></span>
<span id="cb3-14"><a href="#cb3-14"></a></span>
<span id="cb3-15"><a href="#cb3-15"></a><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span></span>
<span id="cb3-16"><a href="#cb3-16"></a>tfe_alert_get_title <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">);</span></span>
<span id="cb3-17"><a href="#cb3-17"></a></span>
<span id="cb3-18"><a href="#cb3-18"></a><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span></span>
<span id="cb3-19"><a href="#cb3-19"></a>tfe_alert_get_message <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">);</span></span>
<span id="cb3-20"><a href="#cb3-20"></a></span>
<span id="cb3-21"><a href="#cb3-21"></a><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span></span>
<span id="cb3-22"><a href="#cb3-22"></a>tfe_alert_get_button_label <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">);</span></span>
<span id="cb3-23"><a href="#cb3-23"></a></span>
<span id="cb3-24"><a href="#cb3-24"></a><span class="dt">void</span></span>
<span id="cb3-25"><a href="#cb3-25"></a>tfe_alert_set_title <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>title<span class="op">);</span></span>
<span id="cb3-26"><a href="#cb3-26"></a></span>
<span id="cb3-27"><a href="#cb3-27"></a><span class="dt">void</span></span>
<span id="cb3-28"><a href="#cb3-28"></a>tfe_alert_set_message <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>message<span class="op">);</span></span>
<span id="cb3-29"><a href="#cb3-29"></a></span>
<span id="cb3-30"><a href="#cb3-30"></a><span class="dt">void</span></span>
<span id="cb3-31"><a href="#cb3-31"></a>tfe_alert_set_button_label <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>btn_label<span class="op">);</span></span>
<span id="cb3-32"><a href="#cb3-32"></a></span>
<span id="cb3-33"><a href="#cb3-33"></a>GtkWidget <span class="op">*</span></span>
<span id="cb3-34"><a href="#cb3-34"></a>tfe_alert_new <span class="op">(</span><span class="dt">void</span><span class="op">);</span></span>
<span id="cb3-35"><a href="#cb3-35"></a></span>
<span id="cb3-36"><a href="#cb3-36"></a>GtkWidget <span class="op">*</span></span>
<span id="cb3-37"><a href="#cb3-37"></a>tfe_alert_new_with_data <span class="op">(</span><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>title<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>message<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span><span class="op">*</span> btn_label<span class="op">);</span></span></code></pre></div>
2023-01-03 07:30:06 +01:00
<ul>
<li>5-6: These two lines are always needed to define a new object.
<code>TFE_TYPE_ALERT</code> is the type of TfeAlert object and it is a
macro expanded into <code>tfe_alert_get_type ()</code>.
G_DECLARE_FINAL_TYPE macro is expanded into:
2023-01-03 07:30:06 +01:00
<ul>
<li>The declaration of the function <code>tfe_alert_get_type</code></li>
<li><code>TfeAlert</code> is defined as a typedef of
<code>struct _TfeAlert</code>, which is defined in the C file.</li>
<li><code>TFE_ALERT</code> and <code>TFE_IS_ALERT</code> macro is
defined as a cast and type check function.</li>
<li><code>TfeAlertClass</code> structure is defined as a final
class.</li>
</ul></li>
<li>8-13: The TfeAlert class has a “response” signal. It has a parameter
and the parameter type is defined as a <code>TfeAlertResponseType</code>
enumerative constant.</li>
<li>15-31: Getter and setter methods.</li>
<li>33-37: Functions to create a instance. The function
<code>tfe_alert_new_with_data</code> is a convenience function, which
creates an instance and sets data at once.</li>
2023-01-03 07:30:06 +01:00
</ul>
<h2 id="the-c-file">The C file</h2>
<h3 id="functions-for-composite-widgets">Functions for composite
widgets</h3>
<p>The following codes are extracted from <code>tfealert.c</code>.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&quot;tfealert.h&quot;</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> _TfeAlert <span class="op">{</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a> GtkWindow parent<span class="op">;</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a> GtkLabel <span class="op">*</span>lb_title<span class="op">;</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a> GtkLabel <span class="op">*</span>lb_message<span class="op">;</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a> GtkButton <span class="op">*</span>btn_accept<span class="op">;</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a> GtkButton <span class="op">*</span>btn_cancel<span class="op">;</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>G_DEFINE_FINAL_TYPE <span class="op">(</span>TfeAlert<span class="op">,</span> tfe_alert<span class="op">,</span> GTK_TYPE_WINDOW<span class="op">);</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>cancel_cb <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a>accept_cb <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-25"><a href="#cb4-25" aria-hidden="true" tabindex="-1"></a>tfe_alert_dispose <span class="op">(</span>GObject <span class="op">*</span>gobject<span class="op">)</span> <span class="op">{</span> <span class="co">// gobject is actually a TfeAlert instance.</span></span>
<span id="cb4-26"><a href="#cb4-26" aria-hidden="true" tabindex="-1"></a> gtk_widget_dispose_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>gobject<span class="op">),</span> TFE_TYPE_ALERT<span class="op">);</span></span>
<span id="cb4-27"><a href="#cb4-27" aria-hidden="true" tabindex="-1"></a> G_OBJECT_CLASS <span class="op">(</span>tfe_alert_parent_class<span class="op">)-&gt;</span>dispose <span class="op">(</span>gobject<span class="op">);</span></span>
<span id="cb4-28"><a href="#cb4-28" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb4-29"><a href="#cb4-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-30"><a href="#cb4-30" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-31"><a href="#cb4-31" aria-hidden="true" tabindex="-1"></a>tfe_alert_init <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-32"><a href="#cb4-32" aria-hidden="true" tabindex="-1"></a> gtk_widget_init_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>alert<span class="op">));</span></span>
<span id="cb4-33"><a href="#cb4-33" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb4-34"><a href="#cb4-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-35"><a href="#cb4-35" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-36"><a href="#cb4-36" aria-hidden="true" tabindex="-1"></a>tfe_alert_class_init <span class="op">(</span>TfeAlertClass <span class="op">*</span>class<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-37"><a href="#cb4-37" aria-hidden="true" tabindex="-1"></a> G_OBJECT_CLASS <span class="op">(</span>class<span class="op">)-&gt;</span>dispose <span class="op">=</span> tfe_alert_dispose<span class="op">;</span></span>
<span id="cb4-38"><a href="#cb4-38" aria-hidden="true" tabindex="-1"></a> gtk_widget_class_set_template_from_resource <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> <span class="st">&quot;/com/github/ToshioCP/tfe/tfealert.ui&quot;</span><span class="op">);</span></span>
<span id="cb4-39"><a href="#cb4-39" aria-hidden="true" tabindex="-1"></a> gtk_widget_class_bind_template_child <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> TfeAlert<span class="op">,</span> lb_title<span class="op">);</span></span>
<span id="cb4-40"><a href="#cb4-40" aria-hidden="true" tabindex="-1"></a> gtk_widget_class_bind_template_child <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> TfeAlert<span class="op">,</span> lb_message<span class="op">);</span></span>
<span id="cb4-41"><a href="#cb4-41" aria-hidden="true" tabindex="-1"></a> gtk_widget_class_bind_template_child <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> TfeAlert<span class="op">,</span> btn_accept<span class="op">);</span></span>
<span id="cb4-42"><a href="#cb4-42" aria-hidden="true" tabindex="-1"></a> gtk_widget_class_bind_template_child <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> TfeAlert<span class="op">,</span> btn_cancel<span class="op">);</span></span>
<span id="cb4-43"><a href="#cb4-43" aria-hidden="true" tabindex="-1"></a> gtk_widget_class_bind_template_callback <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> cancel_cb<span class="op">);</span></span>
<span id="cb4-44"><a href="#cb4-44" aria-hidden="true" tabindex="-1"></a> gtk_widget_class_bind_template_callback <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> accept_cb<span class="op">);</span></span>
<span id="cb4-45"><a href="#cb4-45" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span>
<span id="cb4-46"><a href="#cb4-46" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb4-47"><a href="#cb4-47" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-48"><a href="#cb4-48" aria-hidden="true" tabindex="-1"></a>GtkWidget <span class="op">*</span></span>
<span id="cb4-49"><a href="#cb4-49" aria-hidden="true" tabindex="-1"></a>tfe_alert_new <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-50"><a href="#cb4-50" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> GTK_WIDGET <span class="op">(</span>g_object_new <span class="op">(</span>TFE_TYPE_ALERT<span class="op">,</span> NULL<span class="op">));</span></span>
<span id="cb4-51"><a href="#cb4-51" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
2023-01-03 07:30:06 +01:00
<ul>
<li>The macro <code>G_DEFINE_FINAL_TYPE</code> is available since GLib
version 2.70. It is used only for a final type class. You can use
<code>G_DEFINE_TYPE</code> macro instead. They are expanded into:
<ul>
<li>The declaration of the functions <code>tfe_alert_init</code> and
<code>tfe_alert_class_init</code>. They are defined in the following
part of the C program.</li>
<li>The definition of the variable
<code>tfe_alert_parent_class</code>.</li>
<li>The definition of the function <code>tfe_alert_get_type</code>.</li>
</ul></li>
<li>The names of the members of <code>_TfeAlert</code>, which are
<code>lb_title</code>, <code>lb_message</code>, <code>btn_accept</code>
and <code>btn_cancel</code>, must be the same as the id attribute in the
XML file <code>tfealert.ui</code>.</li>
<li>The function <code>tfe_alert_class_init</code> initializes the
composite widget class.
<ul>
<li>The function
<code>gtk_widget_class_set_template_from_resource</code> sets the
template of the class. The template is built from the XML resource
“tfealert.ui”. At this moment no instance is created. It just makes the
class recognize the structure of the object. Thats why the top level
tag is not object but template in the XML file.</li>
<li>The function macro <code>gtk_widget_class_bind_template_child</code>
connects the member of TfeAlert and the object class in the template.
So, for example, you can access to <code>lb_title</code> GtkLabel
instance via <code>alert-&gt;lb_title</code> where <code>alert</code> is
an instance of TfeAlert class.</li>
<li>The function <code>gtk_widget_class_bind_template_callback</code>
connects the callback function and the <code>handler</code> attribute of
the signal tag in the XML. For example, the “clicked” signal on the
cancel button has a handler named “cancel_cb” in the signal tag. And the
function <code>cancel_cb</code> exists in the C file above. These two
are connected so when the signal is emitted the function
<code>cancel_cb</code> is called. You can add <code>static</code>
storage class to the callback function thanks to this connection.</li>
</ul></li>
<li>The function <code>tfe_alert_init</code> initializes the newly
created instance. You need to call <code>gtk_widget_init_template</code>
to create and initialize the child widgets in the template.</li>
<li>The function <code>tfe_alert_despose</code> releases objects. The
function <code>gtk_widget_despose_template</code> clears the template
children.</li>
<li>The function <code>tfe_alert_new</code> creates the composite widget
TfeAlert instance. It creates not only TfeAlert itself but also all the
child widgets that the composite widget has.</li>
</ul>
<h3 id="other-functions">Other functions</h3>
<p>The following is the full codes of <code>tfealert.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="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="pp">#include </span><span class="im">&quot;tfealert.h&quot;</span></span>
<span id="cb5-3"><a href="#cb5-3"></a></span>
<span id="cb5-4"><a href="#cb5-4"></a><span class="kw">struct</span> _TfeAlert <span class="op">{</span></span>
<span id="cb5-5"><a href="#cb5-5"></a> GtkWindow parent<span class="op">;</span></span>
<span id="cb5-6"><a href="#cb5-6"></a> GtkLabel <span class="op">*</span>lb_title<span class="op">;</span></span>
<span id="cb5-7"><a href="#cb5-7"></a> GtkLabel <span class="op">*</span>lb_message<span class="op">;</span></span>
<span id="cb5-8"><a href="#cb5-8"></a> GtkButton <span class="op">*</span>btn_accept<span class="op">;</span></span>
<span id="cb5-9"><a href="#cb5-9"></a> GtkButton <span class="op">*</span>btn_cancel<span class="op">;</span></span>
<span id="cb5-10"><a href="#cb5-10"></a><span class="op">};</span></span>
<span id="cb5-11"><a href="#cb5-11"></a></span>
<span id="cb5-12"><a href="#cb5-12"></a>G_DEFINE_FINAL_TYPE <span class="op">(</span>TfeAlert<span class="op">,</span> tfe_alert<span class="op">,</span> GTK_TYPE_WINDOW<span class="op">);</span></span>
<span id="cb5-13"><a href="#cb5-13"></a></span>
<span id="cb5-14"><a href="#cb5-14"></a><span class="kw">enum</span> <span class="op">{</span></span>
<span id="cb5-15"><a href="#cb5-15"></a> RESPONSE<span class="op">,</span></span>
<span id="cb5-16"><a href="#cb5-16"></a> NUMBER_OF_SIGNALS</span>
<span id="cb5-17"><a href="#cb5-17"></a><span class="op">};</span></span>
<span id="cb5-18"><a href="#cb5-18"></a></span>
<span id="cb5-19"><a href="#cb5-19"></a><span class="dt">static</span> guint tfe_alert_signals<span class="op">[</span>NUMBER_OF_SIGNALS<span class="op">];</span></span>
<span id="cb5-20"><a href="#cb5-20"></a></span>
<span id="cb5-21"><a href="#cb5-21"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb5-22"><a href="#cb5-22"></a>cancel_cb <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-23"><a href="#cb5-23"></a> g_signal_emit <span class="op">(</span>alert<span class="op">,</span> tfe_alert_signals<span class="op">[</span>RESPONSE<span class="op">],</span> <span class="dv">0</span><span class="op">,</span> TFE_ALERT_RESPONSE_CANCEL<span class="op">);</span></span>
<span id="cb5-24"><a href="#cb5-24"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>alert<span class="op">));</span></span>
<span id="cb5-25"><a href="#cb5-25"></a><span class="op">}</span></span>
<span id="cb5-26"><a href="#cb5-26"></a></span>
<span id="cb5-27"><a href="#cb5-27"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb5-28"><a href="#cb5-28"></a>accept_cb <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-29"><a href="#cb5-29"></a> g_signal_emit <span class="op">(</span>alert<span class="op">,</span> tfe_alert_signals<span class="op">[</span>RESPONSE<span class="op">],</span> <span class="dv">0</span><span class="op">,</span> TFE_ALERT_RESPONSE_ACCEPT<span class="op">);</span></span>
<span id="cb5-30"><a href="#cb5-30"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>alert<span class="op">));</span></span>
<span id="cb5-31"><a href="#cb5-31"></a><span class="op">}</span></span>
<span id="cb5-32"><a href="#cb5-32"></a></span>
<span id="cb5-33"><a href="#cb5-33"></a><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span></span>
<span id="cb5-34"><a href="#cb5-34"></a>tfe_alert_get_title <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-35"><a href="#cb5-35"></a> <span class="cf">return</span> gtk_label_get_text <span class="op">(</span>alert<span class="op">-&gt;</span>lb_title<span class="op">);</span></span>
<span id="cb5-36"><a href="#cb5-36"></a><span class="op">}</span></span>
<span id="cb5-37"><a href="#cb5-37"></a></span>
<span id="cb5-38"><a href="#cb5-38"></a><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span></span>
<span id="cb5-39"><a href="#cb5-39"></a>tfe_alert_get_message <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-40"><a href="#cb5-40"></a> <span class="cf">return</span> gtk_label_get_text <span class="op">(</span>alert<span class="op">-&gt;</span>lb_message<span class="op">);</span></span>
<span id="cb5-41"><a href="#cb5-41"></a><span class="op">}</span></span>
<span id="cb5-42"><a href="#cb5-42"></a></span>
<span id="cb5-43"><a href="#cb5-43"></a><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span></span>
<span id="cb5-44"><a href="#cb5-44"></a>tfe_alert_get_button_label <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-45"><a href="#cb5-45"></a> <span class="cf">return</span> gtk_button_get_label <span class="op">(</span>alert<span class="op">-&gt;</span>btn_accept<span class="op">);</span></span>
<span id="cb5-46"><a href="#cb5-46"></a><span class="op">}</span></span>
<span id="cb5-47"><a href="#cb5-47"></a></span>
<span id="cb5-48"><a href="#cb5-48"></a><span class="dt">void</span></span>
<span id="cb5-49"><a href="#cb5-49"></a>tfe_alert_set_title <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>title<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-50"><a href="#cb5-50"></a> gtk_label_set_text <span class="op">(</span>alert<span class="op">-&gt;</span>lb_title<span class="op">,</span> title<span class="op">);</span></span>
<span id="cb5-51"><a href="#cb5-51"></a><span class="op">}</span></span>
<span id="cb5-52"><a href="#cb5-52"></a></span>
<span id="cb5-53"><a href="#cb5-53"></a><span class="dt">void</span></span>
<span id="cb5-54"><a href="#cb5-54"></a>tfe_alert_set_message <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>message<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-55"><a href="#cb5-55"></a> gtk_label_set_text <span class="op">(</span>alert<span class="op">-&gt;</span>lb_message<span class="op">,</span> message<span class="op">);</span></span>
<span id="cb5-56"><a href="#cb5-56"></a><span class="op">}</span></span>
<span id="cb5-57"><a href="#cb5-57"></a></span>
<span id="cb5-58"><a href="#cb5-58"></a><span class="dt">void</span></span>
<span id="cb5-59"><a href="#cb5-59"></a>tfe_alert_set_button_label <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>btn_label<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-60"><a href="#cb5-60"></a> gtk_button_set_label <span class="op">(</span>alert<span class="op">-&gt;</span>btn_accept<span class="op">,</span> btn_label<span class="op">);</span></span>
<span id="cb5-61"><a href="#cb5-61"></a><span class="op">}</span></span>
<span id="cb5-62"><a href="#cb5-62"></a></span>
<span id="cb5-63"><a href="#cb5-63"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb5-64"><a href="#cb5-64"></a>tfe_alert_dispose <span class="op">(</span>GObject <span class="op">*</span>gobject<span class="op">)</span> <span class="op">{</span> <span class="co">// gobject is actually a TfeAlert instance.</span></span>
<span id="cb5-65"><a href="#cb5-65"></a> gtk_widget_dispose_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>gobject<span class="op">),</span> TFE_TYPE_ALERT<span class="op">);</span></span>
<span id="cb5-66"><a href="#cb5-66"></a> G_OBJECT_CLASS <span class="op">(</span>tfe_alert_parent_class<span class="op">)-&gt;</span>dispose <span class="op">(</span>gobject<span class="op">);</span></span>
<span id="cb5-67"><a href="#cb5-67"></a><span class="op">}</span></span>
<span id="cb5-68"><a href="#cb5-68"></a></span>
<span id="cb5-69"><a href="#cb5-69"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb5-70"><a href="#cb5-70"></a>tfe_alert_init <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-71"><a href="#cb5-71"></a> gtk_widget_init_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>alert<span class="op">));</span></span>
<span id="cb5-72"><a href="#cb5-72"></a><span class="op">}</span></span>
<span id="cb5-73"><a href="#cb5-73"></a></span>
<span id="cb5-74"><a href="#cb5-74"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb5-75"><a href="#cb5-75"></a>tfe_alert_class_init <span class="op">(</span>TfeAlertClass <span class="op">*</span>class<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-76"><a href="#cb5-76"></a> G_OBJECT_CLASS <span class="op">(</span>class<span class="op">)-&gt;</span>dispose <span class="op">=</span> tfe_alert_dispose<span class="op">;</span></span>
<span id="cb5-77"><a href="#cb5-77"></a> gtk_widget_class_set_template_from_resource <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> <span class="st">&quot;/com/github/ToshioCP/tfe/tfealert.ui&quot;</span><span class="op">);</span></span>
<span id="cb5-78"><a href="#cb5-78"></a> gtk_widget_class_bind_template_child <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> TfeAlert<span class="op">,</span> lb_title<span class="op">);</span></span>
<span id="cb5-79"><a href="#cb5-79"></a> gtk_widget_class_bind_template_child <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> TfeAlert<span class="op">,</span> lb_message<span class="op">);</span></span>
<span id="cb5-80"><a href="#cb5-80"></a> gtk_widget_class_bind_template_child <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> TfeAlert<span class="op">,</span> btn_accept<span class="op">);</span></span>
<span id="cb5-81"><a href="#cb5-81"></a> gtk_widget_class_bind_template_child <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> TfeAlert<span class="op">,</span> btn_cancel<span class="op">);</span></span>
<span id="cb5-82"><a href="#cb5-82"></a> gtk_widget_class_bind_template_callback <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> cancel_cb<span class="op">);</span></span>
<span id="cb5-83"><a href="#cb5-83"></a> gtk_widget_class_bind_template_callback <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> accept_cb<span class="op">);</span></span>
<span id="cb5-84"><a href="#cb5-84"></a></span>
<span id="cb5-85"><a href="#cb5-85"></a> tfe_alert_signals<span class="op">[</span>RESPONSE<span class="op">]</span> <span class="op">=</span> g_signal_new <span class="op">(</span><span class="st">&quot;response&quot;</span><span class="op">,</span></span>
<span id="cb5-86"><a href="#cb5-86"></a> G_TYPE_FROM_CLASS <span class="op">(</span>class<span class="op">),</span></span>
<span id="cb5-87"><a href="#cb5-87"></a> G_SIGNAL_RUN_LAST <span class="op">|</span> G_SIGNAL_NO_RECURSE <span class="op">|</span> G_SIGNAL_NO_HOOKS<span class="op">,</span></span>
<span id="cb5-88"><a href="#cb5-88"></a> <span class="dv">0</span> <span class="co">/* class offset */</span><span class="op">,</span></span>
<span id="cb5-89"><a href="#cb5-89"></a> NULL <span class="co">/* accumulator */</span><span class="op">,</span></span>
<span id="cb5-90"><a href="#cb5-90"></a> NULL <span class="co">/* accumulator data */</span><span class="op">,</span></span>
<span id="cb5-91"><a href="#cb5-91"></a> NULL <span class="co">/* C marshaller */</span><span class="op">,</span></span>
<span id="cb5-92"><a href="#cb5-92"></a> G_TYPE_NONE <span class="co">/* return_type */</span><span class="op">,</span></span>
<span id="cb5-93"><a href="#cb5-93"></a> <span class="dv">1</span> <span class="co">/* n_params */</span><span class="op">,</span></span>
<span id="cb5-94"><a href="#cb5-94"></a> G_TYPE_INT</span>
<span id="cb5-95"><a href="#cb5-95"></a> <span class="op">);</span></span>
<span id="cb5-96"><a href="#cb5-96"></a><span class="op">}</span></span>
<span id="cb5-97"><a href="#cb5-97"></a></span>
<span id="cb5-98"><a href="#cb5-98"></a>GtkWidget <span class="op">*</span></span>
<span id="cb5-99"><a href="#cb5-99"></a>tfe_alert_new <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-100"><a href="#cb5-100"></a> <span class="cf">return</span> GTK_WIDGET <span class="op">(</span>g_object_new <span class="op">(</span>TFE_TYPE_ALERT<span class="op">,</span> NULL<span class="op">));</span></span>
<span id="cb5-101"><a href="#cb5-101"></a><span class="op">}</span></span>
<span id="cb5-102"><a href="#cb5-102"></a></span>
<span id="cb5-103"><a href="#cb5-103"></a>GtkWidget <span class="op">*</span></span>
<span id="cb5-104"><a href="#cb5-104"></a>tfe_alert_new_with_data <span class="op">(</span><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>title<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>message<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span><span class="op">*</span> btn_label<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-105"><a href="#cb5-105"></a> GtkWidget <span class="op">*</span>alert <span class="op">=</span> tfe_alert_new <span class="op">();</span></span>
<span id="cb5-106"><a href="#cb5-106"></a> tfe_alert_set_title <span class="op">(</span>TFE_ALERT <span class="op">(</span>alert<span class="op">),</span> title<span class="op">);</span></span>
<span id="cb5-107"><a href="#cb5-107"></a> tfe_alert_set_message <span class="op">(</span>TFE_ALERT <span class="op">(</span>alert<span class="op">),</span> message<span class="op">);</span></span>
<span id="cb5-108"><a href="#cb5-108"></a> tfe_alert_set_button_label <span class="op">(</span>TFE_ALERT <span class="op">(</span>alert<span class="op">),</span> btn_label<span class="op">);</span></span>
<span id="cb5-109"><a href="#cb5-109"></a> <span class="cf">return</span> alert<span class="op">;</span></span>
<span id="cb5-110"><a href="#cb5-110"></a><span class="op">}</span></span></code></pre></div>
<p>The function <code>tfe_alert_new_with_data</code> is used more often
than <code>tfe_alert_new</code> to create a new instance. It creates the
instance and sets three data at the same time. The following is the
common process when you use the TfeAlert class.</p>
2023-01-03 07:30:06 +01:00
<ul>
<li>Call <code>tfe_alert_new_with_data</code> and create an
instance.</li>
<li>Call <code>gtk_window_set_transient_for</code> to set the transient
parent window.</li>
<li>Call <code>gtk_window_present</code> to show the TfeAlert
dialog.</li>
<li>Connect “response” signal and a handler.</li>
<li>The user clicks on the cancel or accept button. Then the dialog
emits the “response” signal and destroy itself.</li>
<li>The user catches the signal and do something.</li>
</ul>
<p>The rest of the program is:</p>
<ul>
<li>14-19: An array for a signal id. You can use a variable instead of
an array because the class has only one signal. But using an array is a
common way.</li>
<li>21-31: Signal handlers. They emits the “response” signal and destroy
the instance itself.</li>
<li>33-61: Getters and setters.</li>
<li>85-95: Creates the “response” signal.</li>
<li>103-110: A convenience function <code>tfe_alert_new_with_data</code>
creates an instance and sets labels.</li>
</ul>
<h2 id="an-example">An example</h2>
<p>Theres an example in the <code>src/tfe6/example</code> directory. It
shows how to use TfeAlert. The program is
<code>src/example/ex_alert.c</code>.</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2"></a><span class="pp">#include </span><span class="im">&quot;../tfealert.h&quot;</span></span>
<span id="cb6-3"><a href="#cb6-3"></a></span>
<span id="cb6-4"><a href="#cb6-4"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb6-5"><a href="#cb6-5"></a>alert_response_cb <span class="op">(</span>TfeAlert <span class="op">*</span>alert<span class="op">,</span> <span class="dt">int</span> response<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-6"><a href="#cb6-6"></a> <span class="cf">if</span> <span class="op">(</span>response <span class="op">==</span> TFE_ALERT_RESPONSE_ACCEPT<span class="op">)</span></span>
<span id="cb6-7"><a href="#cb6-7"></a> g_print <span class="op">(</span><span class="st">&quot;%s</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">,</span> tfe_alert_get_button_label <span class="op">(</span>alert<span class="op">));</span></span>
<span id="cb6-8"><a href="#cb6-8"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>response <span class="op">==</span> TFE_ALERT_RESPONSE_CANCEL<span class="op">)</span></span>
<span id="cb6-9"><a href="#cb6-9"></a> g_print <span class="op">(</span><span class="st">&quot;Cancel</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span>
<span id="cb6-10"><a href="#cb6-10"></a> <span class="cf">else</span></span>
<span id="cb6-11"><a href="#cb6-11"></a> g_print <span class="op">(</span><span class="st">&quot;Unexpected error</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span>
<span id="cb6-12"><a href="#cb6-12"></a><span class="op">}</span></span>
<span id="cb6-13"><a href="#cb6-13"></a></span>
<span id="cb6-14"><a href="#cb6-14"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb6-15"><a href="#cb6-15"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-16"><a href="#cb6-16"></a> GtkWidget <span class="op">*</span>alert<span class="op">;</span></span>
<span id="cb6-17"><a href="#cb6-17"></a> <span class="dt">char</span> <span class="op">*</span>title<span class="op">,</span> <span class="op">*</span>message<span class="op">,</span> <span class="op">*</span>btn_label<span class="op">;</span></span>
<span id="cb6-18"><a href="#cb6-18"></a></span>
<span id="cb6-19"><a href="#cb6-19"></a> title <span class="op">=</span> <span class="st">&quot;Example for TfeAlert&quot;</span><span class="op">;</span> message <span class="op">=</span> <span class="st">&quot;Click on Cancel or Accept button&quot;</span><span class="op">;</span> btn_label <span class="op">=</span> <span class="st">&quot;Accept&quot;</span><span class="op">;</span></span>
<span id="cb6-20"><a href="#cb6-20"></a> alert <span class="op">=</span> tfe_alert_new_with_data <span class="op">(</span>title<span class="op">,</span> message<span class="op">,</span> btn_label<span class="op">);</span></span>
<span id="cb6-21"><a href="#cb6-21"></a> g_signal_connect <span class="op">(</span>TFE_ALERT <span class="op">(</span>alert<span class="op">),</span> <span class="st">&quot;response&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>alert_response_cb<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb6-22"><a href="#cb6-22"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>alert<span class="op">),</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">));</span></span>
<span id="cb6-23"><a href="#cb6-23"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>alert<span class="op">));</span></span>
<span id="cb6-24"><a href="#cb6-24"></a><span class="op">}</span></span>
<span id="cb6-25"><a href="#cb6-25"></a></span>
<span id="cb6-26"><a href="#cb6-26"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb6-27"><a href="#cb6-27"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-28"><a href="#cb6-28"></a><span class="op">}</span></span>
<span id="cb6-29"><a href="#cb6-29"></a></span>
<span id="cb6-30"><a href="#cb6-30"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.example_tfe_alert&quot;</span></span>
<span id="cb6-31"><a href="#cb6-31"></a></span>
<span id="cb6-32"><a href="#cb6-32"></a><span class="dt">int</span></span>
<span id="cb6-33"><a href="#cb6-33"></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="cb6-34"><a href="#cb6-34"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb6-35"><a href="#cb6-35"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb6-36"><a href="#cb6-36"></a></span>
<span id="cb6-37"><a href="#cb6-37"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_DEFAULT_FLAGS<span class="op">);</span></span>
<span id="cb6-38"><a href="#cb6-38"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;startup&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb6-39"><a href="#cb6-39"></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="cb6-40"><a href="#cb6-40"></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="cb6-41"><a href="#cb6-41"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb6-42"><a href="#cb6-42"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb6-43"><a href="#cb6-43"></a><span class="op">}</span></span></code></pre></div>
<p>The “activate” signal handler <code>app_activate</code> initializes
the alert dialog.</p>
<ul>
<li>A TfeAlert instance is created.</li>
<li>Its “response” signal is connected to the handler
<code>alert_response_cb</code>.</li>
<li>TfeAlert class is a sub class of GtkWindow so it can be a top level
window that is connected to an application instance. The function
<code>gtk_window_set_application</code> does that.</li>
<li>The dialog is shown.</li>
</ul>
<p>A user clicks on either the cancel button or the accept button. Then,
the “response” signal is emitted and the dialog is destroyed. The signal
handler <code>alert_response_cb</code> checks the response and prints
“Accept” or “Cancel”. If an error happens, it prints “Unexpected
error”.</p>
<p>You can compile it with meson and ninja.</p>
<pre><code>$ cd src/tfe6/example
$ meson setup _build
$ ninja -C _build
$ _build/ex_alert
Accept #&lt;= if you clicked on the accept button</code></pre>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</body>
</html>