/
evo
/
Gtk4-tutorial
Обзор
Документация
Войти
/
evo
/
Gtk4-tutorial
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
v0.85
docs/sec21.html
1 073 строки
112 KB
Toshio Sekiya
Update section 17 to 21.
03 янв 2023, 09:30
03 янв 2023, 09:30
d4317f1
Код
Авторство
О чём код?
<!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="sec20.html">Prev: section20</a> </li> <li class="nav-item"> <a class="nav-link" href="sec22.html">Next: section22</a> </li> </ul> </div> </div> </nav> <h1 id="template-xml-and-composite-widget">Template XML and composite widget</h1> <p>The tfe program in the previous section is not so good because many things are crammed into <code>tfepplication.c</code>. And many static variables in <code>tfepplication.c</code>. The file <code>tfeapplication.c</code> should be divided into several files.</p> <ul> <li><code>tfeapplication.c</code> only has codes related to the application.</li> <li>A file for the main window</li> <li>A file for a preference dialog</li> <li>A file for an alert dialog</li> </ul> <p>The preference dialog is defined by a ui file. And it has GtkBox, GtkLabel and GtkFontButton in it. Such widget can be defined as a composite widget. Composite widget is:</p> <ul> <li>a child object (not child widget) of a widget. For example, the preference composite widget is a child object of GtkDialog.</li> <li>Composite widget can be built from template XML. The widget is defined with template tag, not object tag.</li> </ul> <p>Next subsection shows how to build a preference dialog.</p> <h2 id="preference-dialog">Preference dialog</h2> <p>First, write a template XML file.</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"><?xml</span><span class="ot"> version=</span><span class="st">"1.0"</span><span class="ot"> encoding=</span><span class="st">"UTF-8"</span><span class="fu">?></span></span> <span id="cb1-2"><a href="#cb1-2"></a><<span class="kw">interface</span>></span> <span id="cb1-3"><a href="#cb1-3"></a> <<span class="kw">template</span><span class="ot"> class=</span><span class="st">"TfePref"</span><span class="ot"> parent=</span><span class="st">"GtkDialog"</span>></span> <span id="cb1-4"><a href="#cb1-4"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"title"</span>>Preferences</<span class="kw">property</span>></span> <span id="cb1-5"><a href="#cb1-5"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"resizable"</span>>FALSE</<span class="kw">property</span>></span> <span id="cb1-6"><a href="#cb1-6"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"modal"</span>>TRUE</<span class="kw">property</span>></span> <span id="cb1-7"><a href="#cb1-7"></a> <<span class="kw">child</span><span class="ot"> internal-child=</span><span class="st">"content_area"</span>></span> <span id="cb1-8"><a href="#cb1-8"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkBox"</span><span class="ot"> id=</span><span class="st">"content_area"</span>></span> <span id="cb1-9"><a href="#cb1-9"></a> <<span class="kw">child</span>></span> <span id="cb1-10"><a href="#cb1-10"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkBox"</span><span class="ot"> id=</span><span class="st">"pref_boxh"</span>></span> <span id="cb1-11"><a href="#cb1-11"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"orientation"</span>>GTK_ORIENTATION_HORIZONTAL</<span class="kw">property</span>></span> <span id="cb1-12"><a href="#cb1-12"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"spacing"</span>>12</<span class="kw">property</span>></span> <span id="cb1-13"><a href="#cb1-13"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"margin-start"</span>>12</<span class="kw">property</span>></span> <span id="cb1-14"><a href="#cb1-14"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"margin-end"</span>>12</<span class="kw">property</span>></span> <span id="cb1-15"><a href="#cb1-15"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"margin-top"</span>>12</<span class="kw">property</span>></span> <span id="cb1-16"><a href="#cb1-16"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"margin-bottom"</span>>12</<span class="kw">property</span>></span> <span id="cb1-17"><a href="#cb1-17"></a> <<span class="kw">child</span>></span> <span id="cb1-18"><a href="#cb1-18"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span><span class="ot"> id=</span><span class="st">"fontlabel"</span>></span> <span id="cb1-19"><a href="#cb1-19"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>Font:</<span class="kw">property</span>></span> <span id="cb1-20"><a href="#cb1-20"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"xalign"</span>>1</<span class="kw">property</span>></span> <span id="cb1-21"><a href="#cb1-21"></a> </<span class="kw">object</span>></span> <span id="cb1-22"><a href="#cb1-22"></a> </<span class="kw">child</span>></span> <span id="cb1-23"><a href="#cb1-23"></a> <<span class="kw">child</span>></span> <span id="cb1-24"><a href="#cb1-24"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkFontButton"</span><span class="ot"> id=</span><span class="st">"fontbtn"</span>></span> <span id="cb1-25"><a href="#cb1-25"></a> </<span class="kw">object</span>></span> <span id="cb1-26"><a href="#cb1-26"></a> </<span class="kw">child</span>></span> <span id="cb1-27"><a href="#cb1-27"></a> </<span class="kw">object</span>></span> <span id="cb1-28"><a href="#cb1-28"></a> </<span class="kw">child</span>></span> <span id="cb1-29"><a href="#cb1-29"></a> </<span class="kw">object</span>></span> <span id="cb1-30"><a href="#cb1-30"></a> </<span class="kw">child</span>></span> <span id="cb1-31"><a href="#cb1-31"></a> </<span class="kw">template</span>></span> <span id="cb1-32"><a href="#cb1-32"></a></<span class="kw">interface</span>></span></code></pre></div> <p>Template tag specifies a composite widget. The value of a class attribute is the object name. It is “TfePref”. A parent attribute specifies the direct parent class of the composite widget. Therefore. <code>TfePref</code> is a child class of <code>GtkDialog</code>. A parent attribute is optional. But it is recommended to specify it. Other lines are the same as before.</p> <p>The class <code>TfePref</code> is defined like TfeTextView. There are two files <code>tfepref.h</code> and <code>tfepref.c</code>.</p> <p>The file <code>tfepref.h</code> defines types and declares public functions. The definitions are public and open to any C files.</p> <div class="sourceCode" id="cb2"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1"></a><span class="pp">#ifndef __TFE_PREF_H__</span></span> <span id="cb2-2"><a href="#cb2-2"></a><span class="pp">#define __TFE_PREF_H__</span></span> <span id="cb2-3"><a href="#cb2-3"></a></span> <span id="cb2-4"><a href="#cb2-4"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span> <span id="cb2-5"><a href="#cb2-5"></a></span> <span id="cb2-6"><a href="#cb2-6"></a><span class="pp">#define TFE_TYPE_PREF tfe_pref_get_type ()</span></span> <span id="cb2-7"><a href="#cb2-7"></a>G_DECLARE_FINAL_TYPE <span class="op">(</span>TfePref<span class="op">,</span> tfe_pref<span class="op">,</span> TFE<span class="op">,</span> PREF<span class="op">,</span> GtkDialog<span class="op">)</span></span> <span id="cb2-8"><a href="#cb2-8"></a></span> <span id="cb2-9"><a href="#cb2-9"></a>GtkWidget <span class="op">*</span></span> <span id="cb2-10"><a href="#cb2-10"></a>tfe_pref_new <span class="op">(</span><span class="dt">void</span><span class="op">);</span></span> <span id="cb2-11"><a href="#cb2-11"></a></span> <span id="cb2-12"><a href="#cb2-12"></a><span class="pp">#endif </span><span class="co">/* __TFE_PREF_H__ */</span></span></code></pre></div> <ul> <li>6: Defines a type <code>TFE_TYPE_PREF</code>, which is a macro replaced by <code>tfe_pref_get_type ()</code>.</li> <li>7: The macro <code>G_DECLAER_FINAL_TYPE</code> expands to: <ul> <li>The function <code>tfe_pref_get_type ()</code> is declared.</li> <li>TfePrep type is defined as a typedef of <code>struct _TfePrep</code>.</li> <li>TfePrepClass type is defined as a typedef of <code>struct {GtkDialogClass *parent;}</code>.</li> <li>Two functions <code>TFE_PREF ()</code> and <code>TFE_IS_PREF ()</code> is defined.</li> </ul></li> <li>9-10: <code>tfe_pref_new</code> creates a new TfePref object.</li> </ul> <p>The file <code>tfepref.c</code> includes:</p> <ul> <li><code>struct _TfePrep</code> structure</li> <li><code>G_DEFINE_TYPE</code> macro</li> <li>Initialize and dispose functions</li> <li>public functions</li> </ul> <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">#include </span><span class="im"><gtk/gtk.h></span></span> <span id="cb3-2"><a href="#cb3-2"></a><span class="pp">#include </span><span class="im">"tfepref.h"</span></span> <span id="cb3-3"><a href="#cb3-3"></a></span> <span id="cb3-4"><a href="#cb3-4"></a><span class="kw">struct</span> _TfePref</span> <span id="cb3-5"><a href="#cb3-5"></a><span class="op">{</span></span> <span id="cb3-6"><a href="#cb3-6"></a> GtkDialog parent<span class="op">;</span></span> <span id="cb3-7"><a href="#cb3-7"></a> GSettings <span class="op">*</span>settings<span class="op">;</span></span> <span id="cb3-8"><a href="#cb3-8"></a> GtkFontButton <span class="op">*</span>fontbtn<span class="op">;</span></span> <span id="cb3-9"><a href="#cb3-9"></a><span class="op">};</span></span> <span id="cb3-10"><a href="#cb3-10"></a></span> <span id="cb3-11"><a href="#cb3-11"></a>G_DEFINE_TYPE <span class="op">(</span>TfePref<span class="op">,</span> tfe_pref<span class="op">,</span> GTK_TYPE_DIALOG<span class="op">);</span></span> <span id="cb3-12"><a href="#cb3-12"></a></span> <span id="cb3-13"><a href="#cb3-13"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb3-14"><a href="#cb3-14"></a>tfe_pref_dispose <span class="op">(</span>GObject <span class="op">*</span>gobject<span class="op">)</span> <span class="op">{</span></span> <span id="cb3-15"><a href="#cb3-15"></a> TfePref <span class="op">*</span>pref <span class="op">=</span> TFE_PREF <span class="op">(</span>gobject<span class="op">);</span></span> <span id="cb3-16"><a href="#cb3-16"></a></span> <span id="cb3-17"><a href="#cb3-17"></a> g_clear_object <span class="op">(&</span>pref<span class="op">-></span>settings<span class="op">);</span></span> <span id="cb3-18"><a href="#cb3-18"></a> G_OBJECT_CLASS <span class="op">(</span>tfe_pref_parent_class<span class="op">)-></span>dispose <span class="op">(</span>gobject<span class="op">);</span></span> <span id="cb3-19"><a href="#cb3-19"></a><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">static</span> <span class="dt">void</span></span> <span id="cb3-22"><a href="#cb3-22"></a>tfe_pref_init <span class="op">(</span>TfePref <span class="op">*</span>pref<span class="op">)</span> <span class="op">{</span></span> <span id="cb3-23"><a href="#cb3-23"></a> gtk_widget_init_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>pref<span class="op">));</span></span> <span id="cb3-24"><a href="#cb3-24"></a> pref<span class="op">-></span>settings <span class="op">=</span> g_settings_new <span class="op">(</span><span class="st">"com.github.ToshioCP.tfe"</span><span class="op">);</span></span> <span id="cb3-25"><a href="#cb3-25"></a> g_settings_bind <span class="op">(</span>pref<span class="op">-></span>settings<span class="op">,</span> <span class="st">"font"</span><span class="op">,</span> pref<span class="op">-></span>fontbtn<span class="op">,</span> <span class="st">"font"</span><span class="op">,</span> G_SETTINGS_BIND_DEFAULT<span class="op">);</span></span> <span id="cb3-26"><a href="#cb3-26"></a><span class="op">}</span></span> <span id="cb3-27"><a href="#cb3-27"></a></span> <span id="cb3-28"><a href="#cb3-28"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb3-29"><a href="#cb3-29"></a>tfe_pref_class_init <span class="op">(</span>TfePrefClass <span class="op">*</span>class<span class="op">)</span> <span class="op">{</span></span> <span id="cb3-30"><a href="#cb3-30"></a> GObjectClass <span class="op">*</span>object_class <span class="op">=</span> G_OBJECT_CLASS <span class="op">(</span>class<span class="op">);</span></span> <span id="cb3-31"><a href="#cb3-31"></a></span> <span id="cb3-32"><a href="#cb3-32"></a> object_class<span class="op">-></span>dispose <span class="op">=</span> tfe_pref_dispose<span class="op">;</span></span> <span id="cb3-33"><a href="#cb3-33"></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">"/com/github/ToshioCP/tfe/tfepref.ui"</span><span class="op">);</span></span> <span id="cb3-34"><a href="#cb3-34"></a> gtk_widget_class_bind_template_child <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> TfePref<span class="op">,</span> fontbtn<span class="op">);</span></span> <span id="cb3-35"><a href="#cb3-35"></a><span class="op">}</span></span> <span id="cb3-36"><a href="#cb3-36"></a></span> <span id="cb3-37"><a href="#cb3-37"></a>GtkWidget <span class="op">*</span></span> <span id="cb3-38"><a href="#cb3-38"></a>tfe_pref_new <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span> <span id="cb3-39"><a href="#cb3-39"></a> <span class="cf">return</span> GTK_WIDGET <span class="op">(</span>g_object_new <span class="op">(</span>TFE_TYPE_PREF<span class="op">,</span> NULL<span class="op">));</span></span> <span id="cb3-40"><a href="#cb3-40"></a><span class="op">}</span></span></code></pre></div> <ul> <li>4-9: The structure <code>struct _TfePref</code> is defined. Every TfePref instance has its own data of the structure. The structure has references to: <ul> <li>a GSettings instance</li> <li>a FontButton instance</li> </ul></li> <li>11: <code>G_DEFINE_TYPE</code> macro. The macro expands to: <ul> <li>the declaration of the class initialization function <code>tfe_pref_class_init</code></li> <li>the declaration of the instance initialization function <code>tfe_pref_init</code></li> <li>a static variable <code>tfe_pref_parent_class</code> that points the parent class (GtkDialogClass) structure.</li> <li>a definition of <code>tfe_pref_get_type ()</code> function</li> </ul></li> <li>13-19: <code>tfe_pref_dispose</code> function. It is called in the destruction process and releases all the reference to other objects. For further information about destruction process, refer to <a href="sec11.html">Section 11</a>.</li> <li>17: g_clear_object is often used in dispose handlers. <code>g_clear_object (&pref->gsettings)</code> does: <ul> <li><code>g_object_unref (pref->gsettings)</code></li> <li><code>pref->settings = NULL</code></li> </ul></li> <li>21-26: Instance initialization function. The argument <code>pref</code> points a newly created TfePref instance.</li> <li>23: The function <code>gtk_widget_init_template</code> creates and initializes the child widgets. The widgets are created based on the template which is created in the <code>gtk_widget_class_set_template_from_resource</code> function.</li> <li>24: Creates GSettings instance and assigns the pointer to it into <code>pref->settings</code>. The instance refers to a GSetting id <code>com.github.ToshioCP.tfe</code>.</li> <li>25: Binds the GSettings data <code>font</code> and the <code>font</code> property of <code>pref->fontbtn</code> (GtkFontButton). The element <code>pref->fontbtn</code> points the GtkFontButton, which is the instance of <code>fontbtn</code> in the ui file. The relation was made by the <code>gtk_widget_class_bind_template_child</code> function.</li> <li>28-35: Class initialization function.</li> <li>32: Sets the dispose handler.</li> <li>33: <code>gtk_widget_class_set_template_from_resource</code> function associates the description in the XML file (<code>tfepref.ui</code>) with the widget. At this moment no instance is created. It just makes the class recognize the structure of the object. That’s why the top level tag is not <code><object></code> but <code><template></code> in the XML file. The instance will be created in the <code>gtk_widget_init_template</code> function later.</li> <li>34: <code>gtk_widget_class_bind_template_child</code> macro binds the structure member (<code>fontbtn</code> in <code>struct _TfePref</code>) and the id <code>fontbtn</code> in the XML file. The two names must be the same. This binding is between the member and the template (not an instance).</li> <li>37-40: The function <code>tfe_pref_new</code> creates a TfePref instance.</li> </ul> <p>Now, It is very simple to use this dialog. A caller just creates this object and shows it.</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>TfePref <span class="op">*</span>pref<span class="op">;</span></span> <span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>pref <span class="op">=</span> tfe_pref_new <span class="op">();</span></span> <span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>gtk_window_set_transient_for <span class="op">(</span>GTK_WINDOW <span class="op">(</span>pref<span class="op">),</span> win<span class="op">);</span> <span class="co">/* win is the main window */</span></span> <span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>pref<span class="op">));</span></span></code></pre></div> <p>This instance is automatically destroyed when a user clicks on the close button. That’s all. If you want to show the dialog again, just create and show it.</p> <figure> <img src="image/pref_dialog.png" alt="Preference dialog" /> <figcaption aria-hidden="true">Preference dialog</figcaption> </figure> <h2 id="alert-dialog">Alert dialog</h2> <p>It is almost same as preference dialog.</p> <p>Its ui file is:</p> <div class="sourceCode" id="cb5"><pre class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb5-1"><a href="#cb5-1"></a><span class="fu"><?xml</span><span class="ot"> version=</span><span class="st">"1.0"</span><span class="ot"> encoding=</span><span class="st">"UTF-8"</span><span class="fu">?></span></span> <span id="cb5-2"><a href="#cb5-2"></a><<span class="kw">interface</span>></span> <span id="cb5-3"><a href="#cb5-3"></a> <<span class="kw">template</span><span class="ot"> class=</span><span class="st">"TfeAlert"</span><span class="ot"> parent=</span><span class="st">"GtkDialog"</span>></span> <span id="cb5-4"><a href="#cb5-4"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"title"</span>>Are you sure?</<span class="kw">property</span>></span> <span id="cb5-5"><a href="#cb5-5"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"resizable"</span>>FALSE</<span class="kw">property</span>></span> <span id="cb5-6"><a href="#cb5-6"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"modal"</span>>TRUE</<span class="kw">property</span>></span> <span id="cb5-7"><a href="#cb5-7"></a> <<span class="kw">child</span><span class="ot"> internal-child=</span><span class="st">"content_area"</span>></span> <span id="cb5-8"><a href="#cb5-8"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkBox"</span>></span> <span id="cb5-9"><a href="#cb5-9"></a> <<span class="kw">child</span>></span> <span id="cb5-10"><a href="#cb5-10"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkBox"</span>></span> <span id="cb5-11"><a href="#cb5-11"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"orientation"</span>>GTK_ORIENTATION_HORIZONTAL</<span class="kw">property</span>></span> <span id="cb5-12"><a href="#cb5-12"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"spacing"</span>>12</<span class="kw">property</span>></span> <span id="cb5-13"><a href="#cb5-13"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"margin-start"</span>>12</<span class="kw">property</span>></span> <span id="cb5-14"><a href="#cb5-14"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"margin-end"</span>>12</<span class="kw">property</span>></span> <span id="cb5-15"><a href="#cb5-15"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"margin-top"</span>>12</<span class="kw">property</span>></span> <span id="cb5-16"><a href="#cb5-16"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"margin-bottom"</span>>12</<span class="kw">property</span>></span> <span id="cb5-17"><a href="#cb5-17"></a> <<span class="kw">child</span>></span> <span id="cb5-18"><a href="#cb5-18"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkImage"</span>></span> <span id="cb5-19"><a href="#cb5-19"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"icon-name"</span>>dialog-warning</<span class="kw">property</span>></span> <span id="cb5-20"><a href="#cb5-20"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"icon-size"</span>>GTK_ICON_SIZE_LARGE</<span class="kw">property</span>></span> <span id="cb5-21"><a href="#cb5-21"></a> </<span class="kw">object</span>></span> <span id="cb5-22"><a href="#cb5-22"></a> </<span class="kw">child</span>></span> <span id="cb5-23"><a href="#cb5-23"></a> <<span class="kw">child</span>></span> <span id="cb5-24"><a href="#cb5-24"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span><span class="ot"> id=</span><span class="st">"lb_alert"</span>></span> <span id="cb5-25"><a href="#cb5-25"></a> </<span class="kw">object</span>></span> <span id="cb5-26"><a href="#cb5-26"></a> </<span class="kw">child</span>></span> <span id="cb5-27"><a href="#cb5-27"></a> </<span class="kw">object</span>></span> <span id="cb5-28"><a href="#cb5-28"></a> </<span class="kw">child</span>></span> <span id="cb5-29"><a href="#cb5-29"></a> </<span class="kw">object</span>></span> <span id="cb5-30"><a href="#cb5-30"></a> </<span class="kw">child</span>></span> <span id="cb5-31"><a href="#cb5-31"></a> <<span class="kw">child</span><span class="ot"> type=</span><span class="st">"action"</span>></span> <span id="cb5-32"><a href="#cb5-32"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span><span class="ot"> id=</span><span class="st">"btn_cancel"</span>></span> <span id="cb5-33"><a href="#cb5-33"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>Cancel</<span class="kw">property</span>></span> <span id="cb5-34"><a href="#cb5-34"></a> </<span class="kw">object</span>></span> <span id="cb5-35"><a href="#cb5-35"></a> </<span class="kw">child</span>></span> <span id="cb5-36"><a href="#cb5-36"></a> <<span class="kw">child</span><span class="ot"> type=</span><span class="st">"action"</span>></span> <span id="cb5-37"><a href="#cb5-37"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span><span class="ot"> id=</span><span class="st">"btn_accept"</span>></span> <span id="cb5-38"><a href="#cb5-38"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>Close</<span class="kw">property</span>></span> <span id="cb5-39"><a href="#cb5-39"></a> </<span class="kw">object</span>></span> <span id="cb5-40"><a href="#cb5-40"></a> </<span class="kw">child</span>></span> <span id="cb5-41"><a href="#cb5-41"></a> <<span class="kw">action-widgets</span>></span> <span id="cb5-42"><a href="#cb5-42"></a> <<span class="kw">action-widget</span><span class="ot"> response=</span><span class="st">"cancel"</span><span class="ot"> default=</span><span class="st">"true"</span>>btn_cancel</<span class="kw">action-widget</span>></span> <span id="cb5-43"><a href="#cb5-43"></a> <<span class="kw">action-widget</span><span class="ot"> response=</span><span class="st">"accept"</span>>btn_accept</<span class="kw">action-widget</span>></span> <span id="cb5-44"><a href="#cb5-44"></a> </<span class="kw">action-widgets</span>></span> <span id="cb5-45"><a href="#cb5-45"></a> </<span class="kw">template</span>></span> <span id="cb5-46"><a href="#cb5-46"></a></<span class="kw">interface</span>></span></code></pre></div> <p>The header file is:</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">#ifndef __TFE_ALERT_H__</span></span> <span id="cb6-2"><a href="#cb6-2"></a><span class="pp">#define __TFE_ALERT_H__</span></span> <span id="cb6-3"><a href="#cb6-3"></a></span> <span id="cb6-4"><a href="#cb6-4"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span> <span id="cb6-5"><a href="#cb6-5"></a></span> <span id="cb6-6"><a href="#cb6-6"></a><span class="pp">#define TFE_TYPE_ALERT tfe_alert_get_type ()</span></span> <span id="cb6-7"><a href="#cb6-7"></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> GtkDialog<span class="op">)</span></span> <span id="cb6-8"><a href="#cb6-8"></a></span> <span id="cb6-9"><a href="#cb6-9"></a><span class="dt">void</span></span> <span id="cb6-10"><a href="#cb6-10"></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="cb6-11"><a href="#cb6-11"></a></span> <span id="cb6-12"><a href="#cb6-12"></a><span class="dt">void</span></span> <span id="cb6-13"><a href="#cb6-13"></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>label<span class="op">);</span></span> <span id="cb6-14"><a href="#cb6-14"></a></span> <span id="cb6-15"><a href="#cb6-15"></a>GtkWidget <span class="op">*</span></span> <span id="cb6-16"><a href="#cb6-16"></a>tfe_alert_new <span class="op">(</span><span class="dt">void</span><span class="op">);</span></span> <span id="cb6-17"><a href="#cb6-17"></a></span> <span id="cb6-18"><a href="#cb6-18"></a><span class="pp">#endif </span><span class="co">/* __TFE_ALERT_H__ */</span></span></code></pre></div> <p>There are three public functions. The functions <code>tfe_alert_set_message</code> and <code>tfe_alert_set_button_label</code> sets the label and button name of the alert dialog. For example, if you want to show an alert that the user tries to close without saving the content, set them like:</p> <div class="sourceCode" id="cb7"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>tfe_alert_set_message <span class="op">(</span>alert<span class="op">,</span> <span class="st">"Contents aren't saved yet.</span><span class="sc">\n</span><span class="st">Are you sure to close?"</span><span class="op">);</span></span> <span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>tfe_alert_set_button_label <span class="op">(</span>alert<span class="op">,</span> <span class="st">"Close"</span><span class="op">);</span></span></code></pre></div> <p>The function <code>tfe_alert_new</code> creates a TfeAlert dialog.</p> <figure> <img src="image/alert_dialog.png" alt="Alert dialog" /> <figcaption aria-hidden="true">Alert dialog</figcaption> </figure> <p>The C source file is:</p> <div class="sourceCode" id="cb8"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span> <span id="cb8-2"><a href="#cb8-2"></a><span class="pp">#include </span><span class="im">"tfealert.h"</span></span> <span id="cb8-3"><a href="#cb8-3"></a></span> <span id="cb8-4"><a href="#cb8-4"></a><span class="kw">struct</span> _TfeAlert</span> <span id="cb8-5"><a href="#cb8-5"></a><span class="op">{</span></span> <span id="cb8-6"><a href="#cb8-6"></a> GtkDialog parent<span class="op">;</span></span> <span id="cb8-7"><a href="#cb8-7"></a> GtkLabel <span class="op">*</span>lb_alert<span class="op">;</span></span> <span id="cb8-8"><a href="#cb8-8"></a> GtkButton <span class="op">*</span>btn_accept<span class="op">;</span></span> <span id="cb8-9"><a href="#cb8-9"></a><span class="op">};</span></span> <span id="cb8-10"><a href="#cb8-10"></a></span> <span id="cb8-11"><a href="#cb8-11"></a>G_DEFINE_TYPE <span class="op">(</span>TfeAlert<span class="op">,</span> tfe_alert<span class="op">,</span> GTK_TYPE_DIALOG<span class="op">);</span></span> <span id="cb8-12"><a href="#cb8-12"></a></span> <span id="cb8-13"><a href="#cb8-13"></a><span class="dt">void</span></span> <span id="cb8-14"><a href="#cb8-14"></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="cb8-15"><a href="#cb8-15"></a> gtk_label_set_text <span class="op">(</span>alert<span class="op">-></span>lb_alert<span class="op">,</span> message<span class="op">);</span></span> <span id="cb8-16"><a href="#cb8-16"></a><span class="op">}</span></span> <span id="cb8-17"><a href="#cb8-17"></a></span> <span id="cb8-18"><a href="#cb8-18"></a><span class="dt">void</span></span> <span id="cb8-19"><a href="#cb8-19"></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>label<span class="op">)</span> <span class="op">{</span></span> <span id="cb8-20"><a href="#cb8-20"></a> gtk_button_set_label <span class="op">(</span>alert<span class="op">-></span>btn_accept<span class="op">,</span> label<span class="op">);</span></span> <span id="cb8-21"><a href="#cb8-21"></a><span class="op">}</span></span> <span id="cb8-22"><a href="#cb8-22"></a></span> <span id="cb8-23"><a href="#cb8-23"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb8-24"><a href="#cb8-24"></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="cb8-25"><a href="#cb8-25"></a> gtk_widget_init_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>alert<span class="op">));</span></span> <span id="cb8-26"><a href="#cb8-26"></a><span class="op">}</span></span> <span id="cb8-27"><a href="#cb8-27"></a></span> <span id="cb8-28"><a href="#cb8-28"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb8-29"><a href="#cb8-29"></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="cb8-30"><a href="#cb8-30"></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">"/com/github/ToshioCP/tfe/tfealert.ui"</span><span class="op">);</span></span> <span id="cb8-31"><a href="#cb8-31"></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_alert<span class="op">);</span></span> <span id="cb8-32"><a href="#cb8-32"></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="cb8-33"><a href="#cb8-33"></a><span class="op">}</span></span> <span id="cb8-34"><a href="#cb8-34"></a></span> <span id="cb8-35"><a href="#cb8-35"></a>GtkWidget <span class="op">*</span></span> <span id="cb8-36"><a href="#cb8-36"></a>tfe_alert_new <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span> <span id="cb8-37"><a href="#cb8-37"></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="cb8-38"><a href="#cb8-38"></a><span class="op">}</span></span></code></pre></div> <p>The program is almost same as <code>tfepref.c</code>.</p> <p>The Usage of the alert object is as follows.</p> <ol type="1"> <li>Write the “response” signal handler.</li> <li>Create a TfeAlert object.</li> <li>Connect “response” signal to a handler</li> <li>Show the dialog</li> <li>In the signal handler, do something with regard to the response-id and destroy the dialog.</li> </ol> <h2 id="top-level-window">Top-level window</h2> <p><code>TfeWindow</code> is a child class of GtkApplicationWindow.</p> <div class="sourceCode" id="cb9"><pre class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb9-1"><a href="#cb9-1"></a><span class="fu"><?xml</span><span class="ot"> version=</span><span class="st">"1.0"</span><span class="ot"> encoding=</span><span class="st">"UTF-8"</span><span class="fu">?></span></span> <span id="cb9-2"><a href="#cb9-2"></a><<span class="kw">interface</span>></span> <span id="cb9-3"><a href="#cb9-3"></a> <<span class="kw">template</span><span class="ot"> class=</span><span class="st">"TfeWindow"</span><span class="ot"> parent=</span><span class="st">"GtkApplicationWindow"</span>></span> <span id="cb9-4"><a href="#cb9-4"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"title"</span>>file editor</<span class="kw">property</span>></span> <span id="cb9-5"><a href="#cb9-5"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"default-width"</span>>600</<span class="kw">property</span>></span> <span id="cb9-6"><a href="#cb9-6"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"default-height"</span>>400</<span class="kw">property</span>></span> <span id="cb9-7"><a href="#cb9-7"></a> <<span class="kw">child</span>></span> <span id="cb9-8"><a href="#cb9-8"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkBox"</span><span class="ot"> id=</span><span class="st">"boxv"</span>></span> <span id="cb9-9"><a href="#cb9-9"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"orientation"</span>>GTK_ORIENTATION_VERTICAL</<span class="kw">property</span>></span> <span id="cb9-10"><a href="#cb9-10"></a> <<span class="kw">child</span>></span> <span id="cb9-11"><a href="#cb9-11"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkBox"</span><span class="ot"> id=</span><span class="st">"boxh"</span>></span> <span id="cb9-12"><a href="#cb9-12"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"orientation"</span>>GTK_ORIENTATION_HORIZONTAL</<span class="kw">property</span>></span> <span id="cb9-13"><a href="#cb9-13"></a> <<span class="kw">child</span>></span> <span id="cb9-14"><a href="#cb9-14"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span><span class="ot"> id=</span><span class="st">"dmy1"</span>></span> <span id="cb9-15"><a href="#cb9-15"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"width-chars"</span>>10</<span class="kw">property</span>></span> <span id="cb9-16"><a href="#cb9-16"></a> </<span class="kw">object</span>></span> <span id="cb9-17"><a href="#cb9-17"></a> </<span class="kw">child</span>></span> <span id="cb9-18"><a href="#cb9-18"></a> <<span class="kw">child</span>></span> <span id="cb9-19"><a href="#cb9-19"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span><span class="ot"> id=</span><span class="st">"btno"</span>></span> <span id="cb9-20"><a href="#cb9-20"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>Open</<span class="kw">property</span>></span> <span id="cb9-21"><a href="#cb9-21"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"action-name"</span>>win.open</<span class="kw">property</span>></span> <span id="cb9-22"><a href="#cb9-22"></a> </<span class="kw">object</span>></span> <span id="cb9-23"><a href="#cb9-23"></a> </<span class="kw">child</span>></span> <span id="cb9-24"><a href="#cb9-24"></a> <<span class="kw">child</span>></span> <span id="cb9-25"><a href="#cb9-25"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span><span class="ot"> id=</span><span class="st">"btns"</span>></span> <span id="cb9-26"><a href="#cb9-26"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>Save</<span class="kw">property</span>></span> <span id="cb9-27"><a href="#cb9-27"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"action-name"</span>>win.save</<span class="kw">property</span>></span> <span id="cb9-28"><a href="#cb9-28"></a> </<span class="kw">object</span>></span> <span id="cb9-29"><a href="#cb9-29"></a> </<span class="kw">child</span>></span> <span id="cb9-30"><a href="#cb9-30"></a> <<span class="kw">child</span>></span> <span id="cb9-31"><a href="#cb9-31"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span><span class="ot"> id=</span><span class="st">"dmy2"</span>></span> <span id="cb9-32"><a href="#cb9-32"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"hexpand"</span>>TRUE</<span class="kw">property</span>></span> <span id="cb9-33"><a href="#cb9-33"></a> </<span class="kw">object</span>></span> <span id="cb9-34"><a href="#cb9-34"></a> </<span class="kw">child</span>></span> <span id="cb9-35"><a href="#cb9-35"></a> <<span class="kw">child</span>></span> <span id="cb9-36"><a href="#cb9-36"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span><span class="ot"> id=</span><span class="st">"btnc"</span>></span> <span id="cb9-37"><a href="#cb9-37"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>Close</<span class="kw">property</span>></span> <span id="cb9-38"><a href="#cb9-38"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"action-name"</span>>win.close</<span class="kw">property</span>></span> <span id="cb9-39"><a href="#cb9-39"></a> </<span class="kw">object</span>></span> <span id="cb9-40"><a href="#cb9-40"></a> </<span class="kw">child</span>></span> <span id="cb9-41"><a href="#cb9-41"></a> <<span class="kw">child</span>></span> <span id="cb9-42"><a href="#cb9-42"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkMenuButton"</span><span class="ot"> id=</span><span class="st">"btnm"</span>></span> <span id="cb9-43"><a href="#cb9-43"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"direction"</span>>down</<span class="kw">property</span>></span> <span id="cb9-44"><a href="#cb9-44"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"halign"</span>>start</<span class="kw">property</span>></span> <span id="cb9-45"><a href="#cb9-45"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"icon-name"</span>>open-menu-symbolic</<span class="kw">property</span>></span> <span id="cb9-46"><a href="#cb9-46"></a> </<span class="kw">object</span>></span> <span id="cb9-47"><a href="#cb9-47"></a> </<span class="kw">child</span>></span> <span id="cb9-48"><a href="#cb9-48"></a> <<span class="kw">child</span>></span> <span id="cb9-49"><a href="#cb9-49"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span><span class="ot"> id=</span><span class="st">"dmy3"</span>></span> <span id="cb9-50"><a href="#cb9-50"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"width-chars"</span>>10</<span class="kw">property</span>></span> <span id="cb9-51"><a href="#cb9-51"></a> </<span class="kw">object</span>></span> <span id="cb9-52"><a href="#cb9-52"></a> </<span class="kw">child</span>></span> <span id="cb9-53"><a href="#cb9-53"></a> </<span class="kw">object</span>></span> <span id="cb9-54"><a href="#cb9-54"></a> </<span class="kw">child</span>></span> <span id="cb9-55"><a href="#cb9-55"></a> <<span class="kw">child</span>></span> <span id="cb9-56"><a href="#cb9-56"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkNotebook"</span><span class="ot"> id=</span><span class="st">"nb"</span>></span> <span id="cb9-57"><a href="#cb9-57"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"scrollable"</span>>TRUE</<span class="kw">property</span>></span> <span id="cb9-58"><a href="#cb9-58"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"hexpand"</span>>TRUE</<span class="kw">property</span>></span> <span id="cb9-59"><a href="#cb9-59"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"vexpand"</span>>TRUE</<span class="kw">property</span>></span> <span id="cb9-60"><a href="#cb9-60"></a> </<span class="kw">object</span>></span> <span id="cb9-61"><a href="#cb9-61"></a> </<span class="kw">child</span>></span> <span id="cb9-62"><a href="#cb9-62"></a> </<span class="kw">object</span>></span> <span id="cb9-63"><a href="#cb9-63"></a> </<span class="kw">child</span>></span> <span id="cb9-64"><a href="#cb9-64"></a> </<span class="kw">template</span>></span> <span id="cb9-65"><a href="#cb9-65"></a></<span class="kw">interface</span>></span></code></pre></div> <p>This XML file is almost same as before except template tag and “action-name” property in buttons.</p> <p>GtkButton implements GtkActionable interface, which has “action-name” property. If this property is set, GtkButton activates the action when it is clicked. For example, if an open button is clicked, “win.open” action will be activated and <code>open_activated</code> handler will be invoked.</p> <p>This action is also used by “<Control>o” accelerator (See <code>tfeapplication.c</code>). If you used “clicked” signal for the button, you would need its signal handler. Then, there would be two handlers:</p> <ul> <li>a handler for the “clicked” signal on the button</li> <li>a handler for the “activate” signal on the “win.open” action, to which “<Control>o” accelerator is connected</li> </ul> <p>These two handlers are almost same. It is inefficient. Connecting buttons to actions is a good way to reduce unnecessary codes.</p> <div class="sourceCode" id="cb10"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1"></a><span class="pp">#ifndef __TFE_WINDOW_H__</span></span> <span id="cb10-2"><a href="#cb10-2"></a><span class="pp">#define __TFE_WINDOW_H__</span></span> <span id="cb10-3"><a href="#cb10-3"></a></span> <span id="cb10-4"><a href="#cb10-4"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span> <span id="cb10-5"><a href="#cb10-5"></a></span> <span id="cb10-6"><a href="#cb10-6"></a><span class="pp">#define TFE_TYPE_WINDOW tfe_window_get_type ()</span></span> <span id="cb10-7"><a href="#cb10-7"></a>G_DECLARE_FINAL_TYPE <span class="op">(</span>TfeWindow<span class="op">,</span> tfe_window<span class="op">,</span> TFE<span class="op">,</span> WINDOW<span class="op">,</span> GtkApplicationWindow<span class="op">)</span></span> <span id="cb10-8"><a href="#cb10-8"></a></span> <span id="cb10-9"><a href="#cb10-9"></a><span class="dt">void</span></span> <span id="cb10-10"><a href="#cb10-10"></a>tfe_window_notebook_page_new <span class="op">(</span>TfeWindow <span class="op">*</span>win<span class="op">);</span></span> <span id="cb10-11"><a href="#cb10-11"></a></span> <span id="cb10-12"><a href="#cb10-12"></a><span class="dt">void</span></span> <span id="cb10-13"><a href="#cb10-13"></a>tfe_window_notebook_page_new_with_files <span class="op">(</span>TfeWindow <span class="op">*</span>win<span class="op">,</span> GFile <span class="op">**</span>files<span class="op">,</span> <span class="dt">int</span> n_files<span class="op">);</span></span> <span id="cb10-14"><a href="#cb10-14"></a></span> <span id="cb10-15"><a href="#cb10-15"></a>GtkWidget <span class="op">*</span></span> <span id="cb10-16"><a href="#cb10-16"></a>tfe_window_new <span class="op">(</span>GtkApplication <span class="op">*</span>app<span class="op">);</span></span> <span id="cb10-17"><a href="#cb10-17"></a></span> <span id="cb10-18"><a href="#cb10-18"></a><span class="pp">#endif </span><span class="co">/* __TFE_WINDOW_H__ */</span></span></code></pre></div> <p>There are three public functions. The function <code>tfe_window_notebook_page_new</code> creates a new notebook page. This is a wrapper function for <code>notebook_page_new</code>. It is called by TfeApplication object. The function <code>tfe_window_notebook_page_new_with_files</code> creates notebook pages with a contents read from the given files. The function <code>tfe_window_new</code> creates a TfeWindow instance.</p> <div class="sourceCode" id="cb11"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb11-1"><a href="#cb11-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span> <span id="cb11-2"><a href="#cb11-2"></a><span class="pp">#include </span><span class="im">"tfewindow.h"</span></span> <span id="cb11-3"><a href="#cb11-3"></a><span class="pp">#include </span><span class="im">"tfenotebook.h"</span></span> <span id="cb11-4"><a href="#cb11-4"></a><span class="pp">#include </span><span class="im">"tfepref.h"</span></span> <span id="cb11-5"><a href="#cb11-5"></a><span class="pp">#include </span><span class="im">"tfealert.h"</span></span> <span id="cb11-6"><a href="#cb11-6"></a></span> <span id="cb11-7"><a href="#cb11-7"></a><span class="kw">struct</span> _TfeWindow <span class="op">{</span></span> <span id="cb11-8"><a href="#cb11-8"></a> GtkApplicationWindow parent<span class="op">;</span></span> <span id="cb11-9"><a href="#cb11-9"></a> GtkMenuButton <span class="op">*</span>btnm<span class="op">;</span></span> <span id="cb11-10"><a href="#cb11-10"></a> GtkNotebook <span class="op">*</span>nb<span class="op">;</span></span> <span id="cb11-11"><a href="#cb11-11"></a> gboolean is_quit<span class="op">;</span></span> <span id="cb11-12"><a href="#cb11-12"></a><span class="op">};</span></span> <span id="cb11-13"><a href="#cb11-13"></a></span> <span id="cb11-14"><a href="#cb11-14"></a>G_DEFINE_TYPE <span class="op">(</span>TfeWindow<span class="op">,</span> tfe_window<span class="op">,</span> GTK_TYPE_APPLICATION_WINDOW<span class="op">);</span></span> <span id="cb11-15"><a href="#cb11-15"></a></span> <span id="cb11-16"><a href="#cb11-16"></a><span class="co">/* alert response signal handler */</span></span> <span id="cb11-17"><a href="#cb11-17"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb11-18"><a href="#cb11-18"></a>alert_response_cb <span class="op">(</span>GtkDialog <span class="op">*</span>alert<span class="op">,</span> <span class="dt">int</span> response_id<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-19"><a href="#cb11-19"></a> TfeWindow <span class="op">*</span>win <span class="op">=</span> TFE_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span> <span id="cb11-20"><a href="#cb11-20"></a></span> <span id="cb11-21"><a href="#cb11-21"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>alert<span class="op">));</span></span> <span id="cb11-22"><a href="#cb11-22"></a> <span class="cf">if</span> <span class="op">(</span>response_id <span class="op">==</span> GTK_RESPONSE_ACCEPT<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-23"><a href="#cb11-23"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>is_quit<span class="op">)</span></span> <span id="cb11-24"><a href="#cb11-24"></a> gtk_window_destroy<span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span> <span id="cb11-25"><a href="#cb11-25"></a> <span class="cf">else</span></span> <span id="cb11-26"><a href="#cb11-26"></a> notebook_page_close <span class="op">(</span>win<span class="op">-></span>nb<span class="op">);</span></span> <span id="cb11-27"><a href="#cb11-27"></a> <span class="op">}</span></span> <span id="cb11-28"><a href="#cb11-28"></a><span class="op">}</span></span> <span id="cb11-29"><a href="#cb11-29"></a></span> <span id="cb11-30"><a href="#cb11-30"></a><span class="dt">static</span> gboolean</span> <span id="cb11-31"><a href="#cb11-31"></a>close_request_cb <span class="op">(</span>TfeWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-32"><a href="#cb11-32"></a> TfeAlert <span class="op">*</span>alert<span class="op">;</span></span> <span id="cb11-33"><a href="#cb11-33"></a></span> <span id="cb11-34"><a href="#cb11-34"></a> <span class="cf">if</span> <span class="op">(</span>has_saved_all <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>win<span class="op">-></span>nb<span class="op">)))</span></span> <span id="cb11-35"><a href="#cb11-35"></a> <span class="cf">return</span> false<span class="op">;</span></span> <span id="cb11-36"><a href="#cb11-36"></a> <span class="cf">else</span> <span class="op">{</span></span> <span id="cb11-37"><a href="#cb11-37"></a> win<span class="op">-></span>is_quit <span class="op">=</span> true<span class="op">;</span></span> <span id="cb11-38"><a href="#cb11-38"></a> alert <span class="op">=</span> TFE_ALERT <span class="op">(</span>tfe_alert_new <span class="op">());</span></span> <span id="cb11-39"><a href="#cb11-39"></a> gtk_window_set_transient_for <span class="op">(</span>GTK_WINDOW <span class="op">(</span>alert<span class="op">),</span> GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span> <span id="cb11-40"><a href="#cb11-40"></a> tfe_alert_set_message <span class="op">(</span>alert<span class="op">,</span> <span class="st">"Contents aren't saved yet.</span><span class="sc">\n</span><span class="st">Are you sure to quit?"</span><span class="op">);</span></span> <span id="cb11-41"><a href="#cb11-41"></a> tfe_alert_set_button_label <span class="op">(</span>alert<span class="op">,</span> <span class="st">"Quit"</span><span class="op">);</span></span> <span id="cb11-42"><a href="#cb11-42"></a> g_signal_connect <span class="op">(</span>GTK_DIALOG <span class="op">(</span>alert<span class="op">),</span> <span class="st">"response"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>alert_response_cb<span class="op">),</span> win<span class="op">);</span></span> <span id="cb11-43"><a href="#cb11-43"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>alert<span class="op">));</span></span> <span id="cb11-44"><a href="#cb11-44"></a> <span class="cf">return</span> true<span class="op">;</span></span> <span id="cb11-45"><a href="#cb11-45"></a> <span class="op">}</span></span> <span id="cb11-46"><a href="#cb11-46"></a><span class="op">}</span></span> <span id="cb11-47"><a href="#cb11-47"></a></span> <span id="cb11-48"><a href="#cb11-48"></a><span class="co">/* ----- action activated handlers ----- */</span></span> <span id="cb11-49"><a href="#cb11-49"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb11-50"><a href="#cb11-50"></a>open_activated <span class="op">(</span>GSimpleAction <span class="op">*</span>action<span class="op">,</span> GVariant <span class="op">*</span>parameter<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-51"><a href="#cb11-51"></a> TfeWindow <span class="op">*</span>win <span class="op">=</span> TFE_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span> <span id="cb11-52"><a href="#cb11-52"></a></span> <span id="cb11-53"><a href="#cb11-53"></a> notebook_page_open <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>win<span class="op">-></span>nb<span class="op">));</span></span> <span id="cb11-54"><a href="#cb11-54"></a><span class="op">}</span></span> <span id="cb11-55"><a href="#cb11-55"></a></span> <span id="cb11-56"><a href="#cb11-56"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb11-57"><a href="#cb11-57"></a>save_activated <span class="op">(</span>GSimpleAction <span class="op">*</span>action<span class="op">,</span> GVariant <span class="op">*</span>parameter<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-58"><a href="#cb11-58"></a> TfeWindow <span class="op">*</span>win <span class="op">=</span> TFE_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span> <span id="cb11-59"><a href="#cb11-59"></a></span> <span id="cb11-60"><a href="#cb11-60"></a> notebook_page_save <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>win<span class="op">-></span>nb<span class="op">));</span></span> <span id="cb11-61"><a href="#cb11-61"></a><span class="op">}</span></span> <span id="cb11-62"><a href="#cb11-62"></a></span> <span id="cb11-63"><a href="#cb11-63"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb11-64"><a href="#cb11-64"></a>close_activated <span class="op">(</span>GSimpleAction <span class="op">*</span>action<span class="op">,</span> GVariant <span class="op">*</span>parameter<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-65"><a href="#cb11-65"></a> TfeWindow <span class="op">*</span>win <span class="op">=</span> TFE_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span> <span id="cb11-66"><a href="#cb11-66"></a> TfeAlert <span class="op">*</span>alert<span class="op">;</span></span> <span id="cb11-67"><a href="#cb11-67"></a></span> <span id="cb11-68"><a href="#cb11-68"></a> <span class="cf">if</span> <span class="op">(</span>has_saved <span class="op">(</span>win<span class="op">-></span>nb<span class="op">))</span></span> <span id="cb11-69"><a href="#cb11-69"></a> notebook_page_close <span class="op">(</span>win<span class="op">-></span>nb<span class="op">);</span></span> <span id="cb11-70"><a href="#cb11-70"></a> <span class="cf">else</span> <span class="op">{</span></span> <span id="cb11-71"><a href="#cb11-71"></a> win<span class="op">-></span>is_quit <span class="op">=</span> false<span class="op">;</span></span> <span id="cb11-72"><a href="#cb11-72"></a> alert <span class="op">=</span> TFE_ALERT <span class="op">(</span>tfe_alert_new <span class="op">());</span></span> <span id="cb11-73"><a href="#cb11-73"></a> gtk_window_set_transient_for <span class="op">(</span>GTK_WINDOW <span class="op">(</span>alert<span class="op">),</span> GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span> <span id="cb11-74"><a href="#cb11-74"></a> tfe_alert_set_message <span class="op">(</span>alert<span class="op">,</span> <span class="st">"Contents aren't saved yet.</span><span class="sc">\n</span><span class="st">Are you sure to close?"</span><span class="op">);</span></span> <span id="cb11-75"><a href="#cb11-75"></a> tfe_alert_set_button_label <span class="op">(</span>alert<span class="op">,</span> <span class="st">"Close"</span><span class="op">);</span></span> <span id="cb11-76"><a href="#cb11-76"></a> g_signal_connect <span class="op">(</span>GTK_DIALOG <span class="op">(</span>alert<span class="op">),</span> <span class="st">"response"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>alert_response_cb<span class="op">),</span> win<span class="op">);</span></span> <span id="cb11-77"><a href="#cb11-77"></a> gtk_widget_show <span class="op">(</span>GTK_WIDGET <span class="op">(</span>alert<span class="op">));</span></span> <span id="cb11-78"><a href="#cb11-78"></a> <span class="op">}</span></span> <span id="cb11-79"><a href="#cb11-79"></a><span class="op">}</span></span> <span id="cb11-80"><a href="#cb11-80"></a></span> <span id="cb11-81"><a href="#cb11-81"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb11-82"><a href="#cb11-82"></a>new_activated <span class="op">(</span>GSimpleAction <span class="op">*</span>action<span class="op">,</span> GVariant <span class="op">*</span>parameter<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-83"><a href="#cb11-83"></a> TfeWindow <span class="op">*</span>win <span class="op">=</span> TFE_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span> <span id="cb11-84"><a href="#cb11-84"></a></span> <span id="cb11-85"><a href="#cb11-85"></a> notebook_page_new <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>win<span class="op">-></span>nb<span class="op">));</span></span> <span id="cb11-86"><a href="#cb11-86"></a><span class="op">}</span></span> <span id="cb11-87"><a href="#cb11-87"></a></span> <span id="cb11-88"><a href="#cb11-88"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb11-89"><a href="#cb11-89"></a>saveas_activated <span class="op">(</span>GSimpleAction <span class="op">*</span>action<span class="op">,</span> GVariant <span class="op">*</span>parameter<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-90"><a href="#cb11-90"></a> TfeWindow <span class="op">*</span>win <span class="op">=</span> TFE_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span> <span id="cb11-91"><a href="#cb11-91"></a></span> <span id="cb11-92"><a href="#cb11-92"></a> notebook_page_saveas <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>win<span class="op">-></span>nb<span class="op">));</span></span> <span id="cb11-93"><a href="#cb11-93"></a><span class="op">}</span></span> <span id="cb11-94"><a href="#cb11-94"></a></span> <span id="cb11-95"><a href="#cb11-95"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb11-96"><a href="#cb11-96"></a>pref_activated <span class="op">(</span>GSimpleAction <span class="op">*</span>action<span class="op">,</span> GVariant <span class="op">*</span>parameter<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-97"><a href="#cb11-97"></a> TfeWindow <span class="op">*</span>win <span class="op">=</span> TFE_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span> <span id="cb11-98"><a href="#cb11-98"></a> GtkWidget <span class="op">*</span>pref<span class="op">;</span></span> <span id="cb11-99"><a href="#cb11-99"></a></span> <span id="cb11-100"><a href="#cb11-100"></a> pref <span class="op">=</span> tfe_pref_new <span class="op">();</span></span> <span id="cb11-101"><a href="#cb11-101"></a> gtk_window_set_transient_for <span class="op">(</span>GTK_WINDOW <span class="op">(</span>pref<span class="op">),</span> GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span> <span id="cb11-102"><a href="#cb11-102"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>pref<span class="op">));</span></span> <span id="cb11-103"><a href="#cb11-103"></a><span class="op">}</span></span> <span id="cb11-104"><a href="#cb11-104"></a></span> <span id="cb11-105"><a href="#cb11-105"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb11-106"><a href="#cb11-106"></a>close_all_activated <span class="op">(</span>GSimpleAction <span class="op">*</span>action<span class="op">,</span> GVariant <span class="op">*</span>parameter<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-107"><a href="#cb11-107"></a> TfeWindow <span class="op">*</span>win <span class="op">=</span> TFE_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span> <span id="cb11-108"><a href="#cb11-108"></a></span> <span id="cb11-109"><a href="#cb11-109"></a> <span class="cf">if</span> <span class="op">(</span>close_request_cb <span class="op">(</span>win<span class="op">)</span> <span class="op">==</span> false<span class="op">)</span></span> <span id="cb11-110"><a href="#cb11-110"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span> <span id="cb11-111"><a href="#cb11-111"></a><span class="op">}</span></span> <span id="cb11-112"><a href="#cb11-112"></a></span> <span id="cb11-113"><a href="#cb11-113"></a><span class="co">/* --- public functions --- */</span></span> <span id="cb11-114"><a href="#cb11-114"></a></span> <span id="cb11-115"><a href="#cb11-115"></a><span class="dt">void</span></span> <span id="cb11-116"><a href="#cb11-116"></a>tfe_window_notebook_page_new <span class="op">(</span>TfeWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-117"><a href="#cb11-117"></a> notebook_page_new <span class="op">(</span>win<span class="op">-></span>nb<span class="op">);</span></span> <span id="cb11-118"><a href="#cb11-118"></a><span class="op">}</span></span> <span id="cb11-119"><a href="#cb11-119"></a></span> <span id="cb11-120"><a href="#cb11-120"></a><span class="dt">void</span></span> <span id="cb11-121"><a href="#cb11-121"></a>tfe_window_notebook_page_new_with_files <span class="op">(</span>TfeWindow <span class="op">*</span>win<span class="op">,</span> GFile <span class="op">**</span>files<span class="op">,</span> <span class="dt">int</span> n_files<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-122"><a href="#cb11-122"></a> <span class="dt">int</span> i<span class="op">;</span></span> <span id="cb11-123"><a href="#cb11-123"></a></span> <span id="cb11-124"><a href="#cb11-124"></a> <span class="cf">for</span> <span class="op">(</span>i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op"><</span> n_files<span class="op">;</span> i<span class="op">++)</span></span> <span id="cb11-125"><a href="#cb11-125"></a> notebook_page_new_with_file <span class="op">(</span>win<span class="op">-></span>nb<span class="op">,</span> files<span class="op">[</span>i<span class="op">]);</span></span> <span id="cb11-126"><a href="#cb11-126"></a> <span class="cf">if</span> <span class="op">(</span>gtk_notebook_get_n_pages <span class="op">(</span>win<span class="op">-></span>nb<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span> <span id="cb11-127"><a href="#cb11-127"></a> notebook_page_new <span class="op">(</span>win<span class="op">-></span>nb<span class="op">);</span></span> <span id="cb11-128"><a href="#cb11-128"></a><span class="op">}</span></span> <span id="cb11-129"><a href="#cb11-129"></a></span> <span id="cb11-130"><a href="#cb11-130"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb11-131"><a href="#cb11-131"></a>tfe_window_init <span class="op">(</span>TfeWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-132"><a href="#cb11-132"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span> <span id="cb11-133"><a href="#cb11-133"></a> GMenuModel <span class="op">*</span>menu<span class="op">;</span></span> <span id="cb11-134"><a href="#cb11-134"></a></span> <span id="cb11-135"><a href="#cb11-135"></a> gtk_widget_init_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>win<span class="op">));</span></span> <span id="cb11-136"><a href="#cb11-136"></a></span> <span id="cb11-137"><a href="#cb11-137"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">"/com/github/ToshioCP/tfe/menu.ui"</span><span class="op">);</span></span> <span id="cb11-138"><a href="#cb11-138"></a> menu <span class="op">=</span> G_MENU_MODEL <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"menu"</span><span class="op">));</span></span> <span id="cb11-139"><a href="#cb11-139"></a> gtk_menu_button_set_menu_model <span class="op">(</span>win<span class="op">-></span>btnm<span class="op">,</span> menu<span class="op">);</span></span> <span id="cb11-140"><a href="#cb11-140"></a> g_object_unref<span class="op">(</span>build<span class="op">);</span></span> <span id="cb11-141"><a href="#cb11-141"></a></span> <span id="cb11-142"><a href="#cb11-142"></a><span class="co">/* ----- action ----- */</span></span> <span id="cb11-143"><a href="#cb11-143"></a> <span class="dt">const</span> GActionEntry win_entries<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span></span> <span id="cb11-144"><a href="#cb11-144"></a> <span class="op">{</span> <span class="st">"open"</span><span class="op">,</span> open_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span> <span id="cb11-145"><a href="#cb11-145"></a> <span class="op">{</span> <span class="st">"save"</span><span class="op">,</span> save_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span> <span id="cb11-146"><a href="#cb11-146"></a> <span class="op">{</span> <span class="st">"close"</span><span class="op">,</span> close_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span> <span id="cb11-147"><a href="#cb11-147"></a> <span class="op">{</span> <span class="st">"new"</span><span class="op">,</span> new_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span> <span id="cb11-148"><a href="#cb11-148"></a> <span class="op">{</span> <span class="st">"saveas"</span><span class="op">,</span> saveas_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span> <span id="cb11-149"><a href="#cb11-149"></a> <span class="op">{</span> <span class="st">"pref"</span><span class="op">,</span> pref_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">},</span></span> <span id="cb11-150"><a href="#cb11-150"></a> <span class="op">{</span> <span class="st">"close-all"</span><span class="op">,</span> close_all_activated<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">,</span> NULL <span class="op">}</span></span> <span id="cb11-151"><a href="#cb11-151"></a> <span class="op">};</span></span> <span id="cb11-152"><a href="#cb11-152"></a> g_action_map_add_action_entries <span class="op">(</span>G_ACTION_MAP <span class="op">(</span>win<span class="op">),</span> win_entries<span class="op">,</span> G_N_ELEMENTS <span class="op">(</span>win_entries<span class="op">),</span> win<span class="op">);</span></span> <span id="cb11-153"><a href="#cb11-153"></a></span> <span id="cb11-154"><a href="#cb11-154"></a> g_signal_connect <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="st">"close-request"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>close_request_cb<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb11-155"><a href="#cb11-155"></a><span class="op">}</span></span> <span id="cb11-156"><a href="#cb11-156"></a></span> <span id="cb11-157"><a href="#cb11-157"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb11-158"><a href="#cb11-158"></a>tfe_window_class_init <span class="op">(</span>TfeWindowClass <span class="op">*</span>class<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-159"><a href="#cb11-159"></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">"/com/github/ToshioCP/tfe/tfewindow.ui"</span><span class="op">);</span></span> <span id="cb11-160"><a href="#cb11-160"></a> gtk_widget_class_bind_template_child <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> TfeWindow<span class="op">,</span> btnm<span class="op">);</span></span> <span id="cb11-161"><a href="#cb11-161"></a> gtk_widget_class_bind_template_child <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> TfeWindow<span class="op">,</span> nb<span class="op">);</span></span> <span id="cb11-162"><a href="#cb11-162"></a><span class="op">}</span></span> <span id="cb11-163"><a href="#cb11-163"></a></span> <span id="cb11-164"><a href="#cb11-164"></a>GtkWidget <span class="op">*</span></span> <span id="cb11-165"><a href="#cb11-165"></a>tfe_window_new <span class="op">(</span>GtkApplication <span class="op">*</span>app<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-166"><a href="#cb11-166"></a> <span class="cf">return</span> GTK_WIDGET <span class="op">(</span>g_object_new <span class="op">(</span>TFE_TYPE_WINDOW<span class="op">,</span> <span class="st">"application"</span><span class="op">,</span> app<span class="op">,</span> NULL<span class="op">));</span></span> <span id="cb11-167"><a href="#cb11-167"></a><span class="op">}</span></span></code></pre></div> <ul> <li>7-12: <code>_TfeWindow</code> structure. A TfeWindow instance points the structure.</li> <li>14: <code>G_DEFINE_TYPE</code> macro.</li> <li>17-28: <code>alert_response_cb</code> is a call back function for the “response” signal of TfeAlert dialog.</li> <li>21: Destroys the alert dialog.</li> <li>22-27: If the user has clicked on the accept button, it destroys the main window or closes the current notebook page.</li> <li>30-46: A “close-request” signal handler on the TfeWindow. When a user clicked on the close button (top right x-shaped button), the handler is called before the window closes. If the handler returns true, the default handler isn’t called and the window doesn’t close. If the handler returns false, the default handler is called and the window closes.</li> <li>34: If <code>has_saved_all</code> returns true, the handler returns false and the window will close. Otherwise, it shows an alert dialog.</li> <li>48-111: Handlers of action activated signal. The <code>user_data</code> is a pointer to the TfeWindow instance.</li> <li>115-128: Public functions.</li> <li>130-155: Instance initialization function.</li> <li>135: The function <code>gtk_widget_init_template</code> creates a child widgets and initializes them.</li> <li>137-140: Builds and inserts <code>menu</code>. It is inserted to the menu button.</li> <li>143-152: Creates actions and inserts them to the window. The scope of the actions is “win”.</li> <li>154: Connects the “close-request” signal and a handler.</li> <li>157-162: Class initialization function.</li> <li>159: Sets the composite widget template</li> <li>160-161: Binds private variables with child class templates.</li> <li>164-167: <code>tfe_window_new</code>. This function creates TfeWindow instance.</li> </ul> <h2 id="tfeapplication">TfeApplication</h2> <p>The file <code>tfeaplication.h</code> and <code>tfeapplication.c</code> are now very simple. The following is the header file.</p> <div class="sourceCode" id="cb12"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb12-1"><a href="#cb12-1"></a><span class="pp">#pragma once</span></span> <span id="cb12-2"><a href="#cb12-2"></a></span> <span id="cb12-3"><a href="#cb12-3"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span> <span id="cb12-4"><a href="#cb12-4"></a></span> <span id="cb12-5"><a href="#cb12-5"></a><span class="pp">#define TFE_TYPE_APPLICATION tfe_application_get_type ()</span></span> <span id="cb12-6"><a href="#cb12-6"></a>G_DECLARE_FINAL_TYPE <span class="op">(</span>TfeApplication<span class="op">,</span> tfe_application<span class="op">,</span> TFE<span class="op">,</span> APPLICATION<span class="op">,</span> GtkApplication<span class="op">)</span></span> <span id="cb12-7"><a href="#cb12-7"></a></span> <span id="cb12-8"><a href="#cb12-8"></a>TfeApplication <span class="op">*</span></span> <span id="cb12-9"><a href="#cb12-9"></a>tfe_application_new <span class="op">(</span><span class="dt">const</span> <span class="dt">char</span><span class="op">*</span> application_id<span class="op">,</span> GApplicationFlags flags<span class="op">);</span></span></code></pre></div> <ul> <li>1: <code>#pragma once</code> isn’t an official pre-processor command, but widely used. It makes the header file be read only once.</li> <li>5-6: <code>TFE_TYPE_APPLICATION</code> is defined as the type of TfeApplication. <code>G_DECLARE_FINAL_TYPE</code> is a macro used in the header file to define a new object.</li> <li>8-9: The function <code>tfe_application_new</code> creates a new TfeApplication instance.</li> </ul> <p>The following is <code>tfeapplication.c</code>. It defines the application and supports:</p> <ul> <li>GSettings</li> <li>CSS</li> </ul> <div class="sourceCode" id="cb13"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb13-1"><a href="#cb13-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span> <span id="cb13-2"><a href="#cb13-2"></a><span class="pp">#include </span><span class="im">"tfeapplication.h"</span></span> <span id="cb13-3"><a href="#cb13-3"></a><span class="pp">#include </span><span class="im">"tfewindow.h"</span></span> <span id="cb13-4"><a href="#cb13-4"></a><span class="pp">#include </span><span class="im">"pfd2css.h"</span></span> <span id="cb13-5"><a href="#cb13-5"></a></span> <span id="cb13-6"><a href="#cb13-6"></a><span class="kw">struct</span> _TfeApplication <span class="op">{</span></span> <span id="cb13-7"><a href="#cb13-7"></a> GtkApplication parent<span class="op">;</span></span> <span id="cb13-8"><a href="#cb13-8"></a> TfeWindow <span class="op">*</span>win<span class="op">;</span></span> <span id="cb13-9"><a href="#cb13-9"></a> GSettings <span class="op">*</span>settings<span class="op">;</span></span> <span id="cb13-10"><a href="#cb13-10"></a> GtkCssProvider <span class="op">*</span>provider<span class="op">;</span></span> <span id="cb13-11"><a href="#cb13-11"></a><span class="op">};</span></span> <span id="cb13-12"><a href="#cb13-12"></a></span> <span id="cb13-13"><a href="#cb13-13"></a>G_DEFINE_TYPE <span class="op">(</span>TfeApplication<span class="op">,</span> tfe_application<span class="op">,</span> GTK_TYPE_APPLICATION<span class="op">);</span></span> <span id="cb13-14"><a href="#cb13-14"></a></span> <span id="cb13-15"><a href="#cb13-15"></a><span class="co">/* gsettings changed::font signal handler */</span></span> <span id="cb13-16"><a href="#cb13-16"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb13-17"><a href="#cb13-17"></a>changed_font_cb <span class="op">(</span>GSettings <span class="op">*</span>settings<span class="op">,</span> <span class="dt">char</span> <span class="op">*</span>key<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb13-18"><a href="#cb13-18"></a> TfeApplication <span class="op">*</span>app <span class="op">=</span> TFE_APPLICATION <span class="op">(</span>user_data<span class="op">);</span></span> <span id="cb13-19"><a href="#cb13-19"></a> <span class="dt">char</span> <span class="op">*</span>font<span class="op">,</span> <span class="op">*</span>s<span class="op">,</span> <span class="op">*</span>css<span class="op">;</span></span> <span id="cb13-20"><a href="#cb13-20"></a> PangoFontDescription <span class="op">*</span>pango_font_desc<span class="op">;</span></span> <span id="cb13-21"><a href="#cb13-21"></a></span> <span id="cb13-22"><a href="#cb13-22"></a> font <span class="op">=</span> g_settings_get_string <span class="op">(</span>app<span class="op">-></span>settings<span class="op">,</span> <span class="st">"font"</span><span class="op">);</span></span> <span id="cb13-23"><a href="#cb13-23"></a> pango_font_desc <span class="op">=</span> pango_font_description_from_string <span class="op">(</span>font<span class="op">);</span></span> <span id="cb13-24"><a href="#cb13-24"></a> g_free <span class="op">(</span>font<span class="op">);</span></span> <span id="cb13-25"><a href="#cb13-25"></a> s <span class="op">=</span> pfd2css <span class="op">(</span>pango_font_desc<span class="op">);</span> <span class="co">// converts Pango Font Description into CSS style string</span></span> <span id="cb13-26"><a href="#cb13-26"></a> css <span class="op">=</span> g_strdup_printf <span class="op">(</span><span class="st">"textview {%s}"</span><span class="op">,</span> s<span class="op">);</span></span> <span id="cb13-27"><a href="#cb13-27"></a> gtk_css_provider_load_from_data <span class="op">(</span>app<span class="op">-></span>provider<span class="op">,</span> css<span class="op">,</span> <span class="op">-</span><span class="dv">1</span><span class="op">);</span></span> <span id="cb13-28"><a href="#cb13-28"></a> g_free <span class="op">(</span>s<span class="op">);</span></span> <span id="cb13-29"><a href="#cb13-29"></a> g_free <span class="op">(</span>css<span class="op">);</span></span> <span id="cb13-30"><a href="#cb13-30"></a><span class="op">}</span></span> <span id="cb13-31"><a href="#cb13-31"></a></span> <span id="cb13-32"><a href="#cb13-32"></a><span class="co">/* ----- activate, open, startup handlers ----- */</span></span> <span id="cb13-33"><a href="#cb13-33"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb13-34"><a href="#cb13-34"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span> <span id="cb13-35"><a href="#cb13-35"></a> TfeApplication <span class="op">*</span>app <span class="op">=</span> TFE_APPLICATION <span class="op">(</span>application<span class="op">);</span></span> <span id="cb13-36"><a href="#cb13-36"></a></span> <span id="cb13-37"><a href="#cb13-37"></a> tfe_window_notebook_page_new <span class="op">(</span>app<span class="op">-></span>win<span class="op">);</span></span> <span id="cb13-38"><a href="#cb13-38"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>app<span class="op">-></span>win<span class="op">));</span></span> <span id="cb13-39"><a href="#cb13-39"></a><span class="op">}</span></span> <span id="cb13-40"><a href="#cb13-40"></a></span> <span id="cb13-41"><a href="#cb13-41"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb13-42"><a href="#cb13-42"></a>app_open <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">,</span> GFile <span class="op">**</span> files<span class="op">,</span> gint n_files<span class="op">,</span> <span class="dt">const</span> gchar <span class="op">*</span>hint<span class="op">)</span> <span class="op">{</span></span> <span id="cb13-43"><a href="#cb13-43"></a> TfeApplication <span class="op">*</span>app <span class="op">=</span> TFE_APPLICATION <span class="op">(</span>application<span class="op">);</span></span> <span id="cb13-44"><a href="#cb13-44"></a></span> <span id="cb13-45"><a href="#cb13-45"></a> tfe_window_notebook_page_new_with_files <span class="op">(</span>app<span class="op">-></span>win<span class="op">,</span> files<span class="op">,</span> n_files<span class="op">);</span></span> <span id="cb13-46"><a href="#cb13-46"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>app<span class="op">-></span>win<span class="op">));</span></span> <span id="cb13-47"><a href="#cb13-47"></a><span class="op">}</span></span> <span id="cb13-48"><a href="#cb13-48"></a></span> <span id="cb13-49"><a href="#cb13-49"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb13-50"><a href="#cb13-50"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span> <span id="cb13-51"><a href="#cb13-51"></a> TfeApplication <span class="op">*</span>app <span class="op">=</span> TFE_APPLICATION <span class="op">(</span>application<span class="op">);</span></span> <span id="cb13-52"><a href="#cb13-52"></a> GtkCssProvider <span class="op">*</span>provider0<span class="op">;</span></span> <span id="cb13-53"><a href="#cb13-53"></a> GdkDisplay <span class="op">*</span>display<span class="op">;</span></span> <span id="cb13-54"><a href="#cb13-54"></a> <span class="dt">int</span> i<span class="op">;</span></span> <span id="cb13-55"><a href="#cb13-55"></a></span> <span id="cb13-56"><a href="#cb13-56"></a> app<span class="op">-></span>win <span class="op">=</span> TFE_WINDOW <span class="op">(</span>tfe_window_new <span class="op">(</span>GTK_APPLICATION <span class="op">(</span>app<span class="op">)));</span></span> <span id="cb13-57"><a href="#cb13-57"></a> provider0 <span class="op">=</span> gtk_css_provider_new <span class="op">();</span></span> <span id="cb13-58"><a href="#cb13-58"></a> gtk_css_provider_load_from_data <span class="op">(</span>provider0<span class="op">,</span> <span class="st">"textview {padding: 10px;}"</span><span class="op">,</span> <span class="op">-</span><span class="dv">1</span><span class="op">);</span></span> <span id="cb13-59"><a href="#cb13-59"></a> display <span class="op">=</span> gdk_display_get_default <span class="op">();</span></span> <span id="cb13-60"><a href="#cb13-60"></a> gtk_style_context_add_provider_for_display <span class="op">(</span>display<span class="op">,</span> GTK_STYLE_PROVIDER <span class="op">(</span>provider0<span class="op">),</span></span> <span id="cb13-61"><a href="#cb13-61"></a> GTK_STYLE_PROVIDER_PRIORITY_APPLICATION<span class="op">);</span></span> <span id="cb13-62"><a href="#cb13-62"></a> g_object_unref <span class="op">(</span>provider0<span class="op">);</span></span> <span id="cb13-63"><a href="#cb13-63"></a> app<span class="op">-></span>provider <span class="op">=</span> gtk_css_provider_new <span class="op">();</span></span> <span id="cb13-64"><a href="#cb13-64"></a> gtk_style_context_add_provider_for_display <span class="op">(</span>display<span class="op">,</span> GTK_STYLE_PROVIDER <span class="op">(</span>app<span class="op">-></span>provider<span class="op">),</span></span> <span id="cb13-65"><a href="#cb13-65"></a> GTK_STYLE_PROVIDER_PRIORITY_APPLICATION<span class="op">);</span></span> <span id="cb13-66"><a href="#cb13-66"></a> app<span class="op">-></span>settings <span class="op">=</span> g_settings_new <span class="op">(</span><span class="st">"com.github.ToshioCP.tfe"</span><span class="op">);</span></span> <span id="cb13-67"><a href="#cb13-67"></a> g_signal_connect <span class="op">(</span>app<span class="op">-></span>settings<span class="op">,</span> <span class="st">"changed::font"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>changed_font_cb<span class="op">),</span> app<span class="op">);</span></span> <span id="cb13-68"><a href="#cb13-68"></a> changed_font_cb<span class="op">(</span>app<span class="op">-></span>settings<span class="op">,</span> <span class="st">"font"</span><span class="op">,</span> app<span class="op">);</span></span> <span id="cb13-69"><a href="#cb13-69"></a></span> <span id="cb13-70"><a href="#cb13-70"></a><span class="co">/* ----- accelerator ----- */</span> </span> <span id="cb13-71"><a href="#cb13-71"></a> <span class="kw">struct</span> <span class="op">{</span></span> <span id="cb13-72"><a href="#cb13-72"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>action<span class="op">;</span></span> <span id="cb13-73"><a href="#cb13-73"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>accels<span class="op">[</span><span class="dv">2</span><span class="op">];</span></span> <span id="cb13-74"><a href="#cb13-74"></a> <span class="op">}</span> action_accels<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span></span> <span id="cb13-75"><a href="#cb13-75"></a> <span class="op">{</span> <span class="st">"win.open"</span><span class="op">,</span> <span class="op">{</span> <span class="st">"<Control>o"</span><span class="op">,</span> NULL <span class="op">}</span> <span class="op">},</span></span> <span id="cb13-76"><a href="#cb13-76"></a> <span class="op">{</span> <span class="st">"win.save"</span><span class="op">,</span> <span class="op">{</span> <span class="st">"<Control>s"</span><span class="op">,</span> NULL <span class="op">}</span> <span class="op">},</span></span> <span id="cb13-77"><a href="#cb13-77"></a> <span class="op">{</span> <span class="st">"win.close"</span><span class="op">,</span> <span class="op">{</span> <span class="st">"<Control>w"</span><span class="op">,</span> NULL <span class="op">}</span> <span class="op">},</span></span> <span id="cb13-78"><a href="#cb13-78"></a> <span class="op">{</span> <span class="st">"win.new"</span><span class="op">,</span> <span class="op">{</span> <span class="st">"<Control>n"</span><span class="op">,</span> NULL <span class="op">}</span> <span class="op">},</span></span> <span id="cb13-79"><a href="#cb13-79"></a> <span class="op">{</span> <span class="st">"win.saveas"</span><span class="op">,</span> <span class="op">{</span> <span class="st">"<Shift><Control>s"</span><span class="op">,</span> NULL <span class="op">}</span> <span class="op">},</span></span> <span id="cb13-80"><a href="#cb13-80"></a> <span class="op">{</span> <span class="st">"win.close-all"</span><span class="op">,</span> <span class="op">{</span> <span class="st">"<Control>q"</span><span class="op">,</span> NULL <span class="op">}</span> <span class="op">},</span></span> <span id="cb13-81"><a href="#cb13-81"></a> <span class="op">};</span></span> <span id="cb13-82"><a href="#cb13-82"></a></span> <span id="cb13-83"><a href="#cb13-83"></a> <span class="cf">for</span> <span class="op">(</span>i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op"><</span> G_N_ELEMENTS<span class="op">(</span>action_accels<span class="op">);</span> i<span class="op">++)</span></span> <span id="cb13-84"><a href="#cb13-84"></a> gtk_application_set_accels_for_action<span class="op">(</span>GTK_APPLICATION<span class="op">(</span>app<span class="op">),</span> action_accels<span class="op">[</span>i<span class="op">].</span>action<span class="op">,</span> action_accels<span class="op">[</span>i<span class="op">].</span>accels<span class="op">);</span></span> <span id="cb13-85"><a href="#cb13-85"></a><span class="op">}</span></span> <span id="cb13-86"><a href="#cb13-86"></a></span> <span id="cb13-87"><a href="#cb13-87"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb13-88"><a href="#cb13-88"></a>tfe_application_dispose <span class="op">(</span>GObject <span class="op">*</span>gobject<span class="op">)</span> <span class="op">{</span></span> <span id="cb13-89"><a href="#cb13-89"></a> TfeApplication <span class="op">*</span>app <span class="op">=</span> TFE_APPLICATION <span class="op">(</span>gobject<span class="op">);</span></span> <span id="cb13-90"><a href="#cb13-90"></a></span> <span id="cb13-91"><a href="#cb13-91"></a> g_clear_object <span class="op">(&</span>app<span class="op">-></span>settings<span class="op">);</span></span> <span id="cb13-92"><a href="#cb13-92"></a> g_clear_object <span class="op">(&</span>app<span class="op">-></span>provider<span class="op">);</span></span> <span id="cb13-93"><a href="#cb13-93"></a> G_OBJECT_CLASS <span class="op">(</span>tfe_application_parent_class<span class="op">)-></span>dispose <span class="op">(</span>gobject<span class="op">);</span></span> <span id="cb13-94"><a href="#cb13-94"></a><span class="op">}</span></span> <span id="cb13-95"><a href="#cb13-95"></a></span> <span id="cb13-96"><a href="#cb13-96"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb13-97"><a href="#cb13-97"></a>tfe_application_init <span class="op">(</span>TfeApplication <span class="op">*</span>app<span class="op">)</span> <span class="op">{</span></span> <span id="cb13-98"><a href="#cb13-98"></a> g_signal_connect <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> <span class="st">"startup"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb13-99"><a href="#cb13-99"></a> g_signal_connect <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> <span class="st">"activate"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb13-100"><a href="#cb13-100"></a> g_signal_connect <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> <span class="st">"open"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_open<span class="op">),</span> NULL<span class="op">);</span></span> <span id="cb13-101"><a href="#cb13-101"></a><span class="op">}</span></span> <span id="cb13-102"><a href="#cb13-102"></a></span> <span id="cb13-103"><a href="#cb13-103"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb13-104"><a href="#cb13-104"></a>tfe_application_class_init <span class="op">(</span>TfeApplicationClass <span class="op">*</span>class<span class="op">)</span> <span class="op">{</span></span> <span id="cb13-105"><a href="#cb13-105"></a> GObjectClass <span class="op">*</span>object_class <span class="op">=</span> G_OBJECT_CLASS <span class="op">(</span>class<span class="op">);</span></span> <span id="cb13-106"><a href="#cb13-106"></a></span> <span id="cb13-107"><a href="#cb13-107"></a> object_class<span class="op">-></span>dispose <span class="op">=</span> tfe_application_dispose<span class="op">;</span></span> <span id="cb13-108"><a href="#cb13-108"></a><span class="op">}</span></span> <span id="cb13-109"><a href="#cb13-109"></a></span> <span id="cb13-110"><a href="#cb13-110"></a>TfeApplication <span class="op">*</span></span> <span id="cb13-111"><a href="#cb13-111"></a>tfe_application_new <span class="op">(</span><span class="dt">const</span> <span class="dt">char</span><span class="op">*</span> application_id<span class="op">,</span> GApplicationFlags flags<span class="op">)</span> <span class="op">{</span></span> <span id="cb13-112"><a href="#cb13-112"></a> <span class="cf">return</span> TFE_APPLICATION <span class="op">(</span>g_object_new <span class="op">(</span>TFE_TYPE_APPLICATION<span class="op">,</span> <span class="st">"application-id"</span><span class="op">,</span> application_id<span class="op">,</span> <span class="st">"flags"</span><span class="op">,</span> flags<span class="op">,</span> NULL<span class="op">));</span></span> <span id="cb13-113"><a href="#cb13-113"></a><span class="op">}</span></span></code></pre></div> <ul> <li>6-11: Defines <code>_TfeApplication</code> structure. The members are: <ul> <li>win: main window instance</li> <li>settings: GSettings instance.it is bound to “font” item in the GSettings</li> <li>provider: a provider for the font of the textview.</li> </ul></li> <li><code>G_DEFINE_TYPE</code> macro.</li> <li>16-30: <code>changed_font_cb</code> is a handler for “changed::font” signal on the GSettings instance. The signal name is “changed” and “font” is a key name. When the valeu of “font” key is changed, the signal is emitted. So, this handler doesn’t directly relate to the font button, but through the GSettings database. A user changes the font in the font button => GSettings font key data is changed => the handler is called.</li> <li>22-24: Retrieves a string from the GSetting database and converts it into a pango font description.</li> <li>25-29: Sets the css provider with the font data. The provider has been inserted to the current display in advance.</li> <li>33-39: Activate signal handler. It uses <code>tfe_window_notebook_page_new</code> instead of <code>notebook_page_new</code>.</li> <li>41-47: Open signal handler. It just calls <code>tfe_window_notebook_page_new_with_files</code> and shows the main window. Be careful that the activate and open handlers don’t create a new window. They just create a new notebook page. Therefore, even if the second application runs, no new window appears. Just a new notebook page is inserted to the same main window.</li> <li>49-85: Startup signal handler.</li> <li>56: Creates a new window (main window) and assigns it to <code>app->win</code>.</li> <li>57-61: Creates a css provider (<code>provider0</code>). It includes only the padding data for the textview. The provider is inserted to the default display.</li> <li>63-65: Another css provider is created (<code>app->provider</code>) and inserted to the default display. It will include the font data for the textview.</li> <li>66-68: Creates a new GSettings instance. If the GSettings data is changed, the “changed” signal is emitted. The signal can have a key name like “changed::font”. This style (“changed::font”) is called detailed signal. The detailed signal is emitted only if the font data is changed. The handler <code>changed_font_cb</code> is called to set the CSS with the font data. The handler gets the font data from the GSettings data which is the last font in the previous run of the application.</li> <li>71-84: Defines accelerators.</li> <li>87-94: A dispose handler. It releases references to the instances of GSettings and GtkCssProvider.</li> <li>96-101: An initialization for the instance. It connects three signals (activate, open and startup) and their handlers.</li> <li>183-188: An initialization for the class. It overrides the dispose class method.</li> <li>110-113: <code>tfe_application_new</code> creates a new TfeApplication instance. The parameters are an application-id and flags.</li> </ul> <h2 id="other-files">Other files</h2> <p>main.c</p> <div class="sourceCode" id="cb14"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb14-1"><a href="#cb14-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span> <span id="cb14-2"><a href="#cb14-2"></a><span class="pp">#include </span><span class="im">"tfeapplication.h"</span></span> <span id="cb14-3"><a href="#cb14-3"></a></span> <span id="cb14-4"><a href="#cb14-4"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.tfe"</span></span> <span id="cb14-5"><a href="#cb14-5"></a></span> <span id="cb14-6"><a href="#cb14-6"></a><span class="dt">int</span></span> <span id="cb14-7"><a href="#cb14-7"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span> <span id="cb14-8"><a href="#cb14-8"></a> TfeApplication <span class="op">*</span>app<span class="op">;</span></span> <span id="cb14-9"><a href="#cb14-9"></a> <span class="dt">int</span> stat<span class="op">;</span></span> <span id="cb14-10"><a href="#cb14-10"></a></span> <span id="cb14-11"><a href="#cb14-11"></a> app <span class="op">=</span> tfe_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_HANDLES_OPEN<span class="op">);</span></span> <span id="cb14-12"><a href="#cb14-12"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span> <span id="cb14-13"><a href="#cb14-13"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span> <span id="cb14-14"><a href="#cb14-14"></a> <span class="cf">return</span> stat<span class="op">;</span></span> <span id="cb14-15"><a href="#cb14-15"></a><span class="op">}</span></span></code></pre></div> <p>CSS related files <code>pfd2css.h</code> and <code>pfd2css.c</code> are the same as the previous section.</p> <p>Resource XML file.</p> <div class="sourceCode" id="cb15"><pre class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb15-1"><a href="#cb15-1"></a><span class="fu"><?xml</span><span class="ot"> version=</span><span class="st">"1.0"</span><span class="ot"> encoding=</span><span class="st">"UTF-8"</span><span class="fu">?></span></span> <span id="cb15-2"><a href="#cb15-2"></a><<span class="kw">gresources</span>></span> <span id="cb15-3"><a href="#cb15-3"></a> <<span class="kw">gresource</span><span class="ot"> prefix=</span><span class="st">"/com/github/ToshioCP/tfe"</span>></span> <span id="cb15-4"><a href="#cb15-4"></a> <<span class="kw">file</span>>tfewindow.ui</<span class="kw">file</span>></span> <span id="cb15-5"><a href="#cb15-5"></a> <<span class="kw">file</span>>tfepref.ui</<span class="kw">file</span>></span> <span id="cb15-6"><a href="#cb15-6"></a> <<span class="kw">file</span>>tfealert.ui</<span class="kw">file</span>></span> <span id="cb15-7"><a href="#cb15-7"></a> <<span class="kw">file</span>>menu.ui</<span class="kw">file</span>></span> <span id="cb15-8"><a href="#cb15-8"></a> </<span class="kw">gresource</span>></span> <span id="cb15-9"><a href="#cb15-9"></a></<span class="kw">gresources</span>></span></code></pre></div> <p>GSchema XML file</p> <div class="sourceCode" id="cb16"><pre class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb16-1"><a href="#cb16-1"></a><span class="fu"><?xml</span><span class="ot"> version=</span><span class="st">"1.0"</span><span class="ot"> encoding=</span><span class="st">"UTF-8"</span><span class="fu">?></span></span> <span id="cb16-2"><a href="#cb16-2"></a><<span class="kw">schemalist</span>></span> <span id="cb16-3"><a href="#cb16-3"></a> <<span class="kw">schema</span><span class="ot"> path=</span><span class="st">"/com/github/ToshioCP/tfe/"</span><span class="ot"> id=</span><span class="st">"com.github.ToshioCP.tfe"</span>></span> <span id="cb16-4"><a href="#cb16-4"></a> <<span class="kw">key</span><span class="ot"> name=</span><span class="st">"font"</span><span class="ot"> type=</span><span class="st">"s"</span>></span> <span id="cb16-5"><a href="#cb16-5"></a> <<span class="kw">default</span>>'Monospace 12'</<span class="kw">default</span>></span> <span id="cb16-6"><a href="#cb16-6"></a> <<span class="kw">summary</span>>Font</<span class="kw">summary</span>></span> <span id="cb16-7"><a href="#cb16-7"></a> <<span class="kw">description</span>>A font to be used for textview.</<span class="kw">description</span>></span> <span id="cb16-8"><a href="#cb16-8"></a> </<span class="kw">key</span>></span> <span id="cb16-9"><a href="#cb16-9"></a> </<span class="kw">schema</span>></span> <span id="cb16-10"><a href="#cb16-10"></a></<span class="kw">schemalist</span>></span></code></pre></div> <p>Meson.build</p> <div class="sourceCode" id="cb17"><pre class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb17-1"><a href="#cb17-1"></a>project('tfe', 'c')</span> <span id="cb17-2"><a href="#cb17-2"></a></span> <span id="cb17-3"><a href="#cb17-3"></a>gtkdep = dependency('gtk4')</span> <span id="cb17-4"><a href="#cb17-4"></a></span> <span id="cb17-5"><a href="#cb17-5"></a>gnome=import('gnome')</span> <span id="cb17-6"><a href="#cb17-6"></a>resources = gnome.compile_resources('resources','tfe.gresource.xml')</span> <span id="cb17-7"><a href="#cb17-7"></a>gnome.compile_schemas(build_by_default: true, depend_files: 'com.github.ToshioCP.tfe.gschema.xml')</span> <span id="cb17-8"><a href="#cb17-8"></a></span> <span id="cb17-9"><a href="#cb17-9"></a>sourcefiles=files('main.c', 'tfeapplication.c', 'tfewindow.c', 'tfenotebook.c', 'tfepref.c', 'tfealert.c', 'pfd2css.c', '../tfetextview/tfetextview.c')</span> <span id="cb17-10"><a href="#cb17-10"></a></span> <span id="cb17-11"><a href="#cb17-11"></a>executable('tfe', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true, install: true)</span> <span id="cb17-12"><a href="#cb17-12"></a></span> <span id="cb17-13"><a href="#cb17-13"></a>schema_dir = get_option('prefix') / get_option('datadir') / 'glib-2.0/schemas/'</span> <span id="cb17-14"><a href="#cb17-14"></a>install_data('com.github.ToshioCP.tfe.gschema.xml', install_dir: schema_dir)</span> <span id="cb17-15"><a href="#cb17-15"></a>gnome.post_install (glib_compile_schemas: true)</span></code></pre></div> <h2 id="compilation-and-installation.">Compilation and installation.</h2> <p>If you want to install it to your local area, use <code>--prefix=$HOME/.local</code> or <code>--prefix=$HOME</code> option. If you want to install it to the system area, no option is needed. It will be installed under <code>/user/local</code> directory.</p> <pre><code>$ meson --prefix=$HOME/.local _build $ ninja -C _build $ ninja -C _build install</code></pre> <p>You need root privilege to install it to the system area..</p> <pre><code>$ meson _build $ ninja -C _build $ sudo ninja -C _build install</code></pre> <p>Source files are in src/tfe7 directory.</p> <p>Composite widgets give us two advantages.</p> <ul> <li>A set of widgets is better than individual widgets because of the simple coding.</li> <li>They hold instance variables (members of the object structure) so static variables are no longer necessary. It makes the program simpler.</li> </ul> <p>We made a very small text editor. You can add features to this editor. When you add a new feature, be careful about the structure of the program. Maybe you need to divide a file into several files like this section. It isn’t good to put many things into one file. And it is important to think about the relationship between source files and widget structures.</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>