/
evo
/
Gtk4-tutorial
Обзор
Документация
Войти
/
evo
/
Gtk4-tutorial
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
docs/sec22.html
1 084 строки
130 KB
Toshio Sekiya
Fixed typo in sec4.src.md.
03 дек 2025, 14:25
03 дек 2025, 14:25
b3d5aaf
Код
Авторство
О чём код?
<!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.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" 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="sec21.html">Prev: section21</a> </li> <li class="nav-item"> <a class="nav-link" href="sec23.html">Next: section23</a> </li> </ul> </div> </div> </nav> <div class="row justify-content-center"> <div class="col-xl-10 col-xxl-9"> <h1 id="tfewindow">TfeWindow</h1> <h2 id="the-tfe-window-and-xml-files">The Tfe window and XML files</h2> <p>The following is the window of Tfe.</p> <figure> <img src="image/tfe6.png" alt="tfe6" /> <figcaption aria-hidden="true">tfe6</figcaption> </figure> <ul> <li>Open, save and close buttons are placed on the toolbar. In addition, GtkMenuButton is added to the toolbar. This button shows a popup menu when clicked on. Here, popup means widely, including pull-down menu.</li> <li>New, save-as, preference and quit items are put into the menu.</li> </ul> <p>This makes the most frequently used operation bound to the tool bar buttons. And the others are stored in behind the menus. So, it is more practical.</p> <p>The window is a composite widget. The definition is described in the XML file <code>tfewindow.ui</code>.</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">"TfeWindow"</span><span class="ot"> parent=</span><span class="st">"GtkApplicationWindow"</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>>Text File Editor</<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">"default-width"</span>>600</<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">"default-height"</span>>400</<span class="kw">property</span>></span> <span id="cb1-7"><a href="#cb1-7"></a> <<span class="kw">child</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">"boxv"</span>></span> <span id="cb1-9"><a href="#cb1-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="cb1-10"><a href="#cb1-10"></a> <<span class="kw">child</span>></span> <span id="cb1-11"><a href="#cb1-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="cb1-12"><a href="#cb1-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="cb1-13"><a href="#cb1-13"></a> <<span class="kw">child</span>></span> <span id="cb1-14"><a href="#cb1-14"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span>></span> <span id="cb1-15"><a href="#cb1-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="cb1-16"><a href="#cb1-16"></a> </<span class="kw">object</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">child</span>></span> <span id="cb1-19"><a href="#cb1-19"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span>></span> <span id="cb1-20"><a href="#cb1-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="cb1-21"><a href="#cb1-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="cb1-22"><a href="#cb1-22"></a> </<span class="kw">object</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">child</span>></span> <span id="cb1-25"><a href="#cb1-25"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span>></span> <span id="cb1-26"><a href="#cb1-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="cb1-27"><a href="#cb1-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="cb1-28"><a href="#cb1-28"></a> </<span class="kw">object</span>></span> <span id="cb1-29"><a href="#cb1-29"></a> </<span class="kw">child</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">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span>></span> <span id="cb1-32"><a href="#cb1-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="cb1-33"><a href="#cb1-33"></a> </<span class="kw">object</span>></span> <span id="cb1-34"><a href="#cb1-34"></a> </<span class="kw">child</span>></span> <span id="cb1-35"><a href="#cb1-35"></a> <<span class="kw">child</span>></span> <span id="cb1-36"><a href="#cb1-36"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span>></span> <span id="cb1-37"><a href="#cb1-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="cb1-38"><a href="#cb1-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="cb1-39"><a href="#cb1-39"></a> </<span class="kw">object</span>></span> <span id="cb1-40"><a href="#cb1-40"></a> </<span class="kw">child</span>></span> <span id="cb1-41"><a href="#cb1-41"></a> <<span class="kw">child</span>></span> <span id="cb1-42"><a href="#cb1-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="cb1-43"><a href="#cb1-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="cb1-44"><a href="#cb1-44"></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="cb1-45"><a href="#cb1-45"></a> </<span class="kw">object</span>></span> <span id="cb1-46"><a href="#cb1-46"></a> </<span class="kw">child</span>></span> <span id="cb1-47"><a href="#cb1-47"></a> <<span class="kw">child</span>></span> <span id="cb1-48"><a href="#cb1-48"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span>></span> <span id="cb1-49"><a href="#cb1-49"></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="cb1-50"><a href="#cb1-50"></a> </<span class="kw">object</span>></span> <span id="cb1-51"><a href="#cb1-51"></a> </<span class="kw">child</span>></span> <span id="cb1-52"><a href="#cb1-52"></a> </<span class="kw">object</span>></span> <span id="cb1-53"><a href="#cb1-53"></a> </<span class="kw">child</span>></span> <span id="cb1-54"><a href="#cb1-54"></a> <<span class="kw">child</span>></span> <span id="cb1-55"><a href="#cb1-55"></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="cb1-56"><a href="#cb1-56"></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="cb1-57"><a href="#cb1-57"></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="cb1-58"><a href="#cb1-58"></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="cb1-59"><a href="#cb1-59"></a> </<span class="kw">object</span>></span> <span id="cb1-60"><a href="#cb1-60"></a> </<span class="kw">child</span>></span> <span id="cb1-61"><a href="#cb1-61"></a> </<span class="kw">object</span>></span> <span id="cb1-62"><a href="#cb1-62"></a> </<span class="kw">child</span>></span> <span id="cb1-63"><a href="#cb1-63"></a> </<span class="kw">template</span>></span> <span id="cb1-64"><a href="#cb1-64"></a></<span class="kw">interface</span>></span></code></pre></div> <ul> <li>Three buttons “Open”, “Save” and “Close” are defined. You can use two ways to catch the button click event. The one is “clicked” signal and the other is to register an action to the button. The first way is simple. You can connects the signal and your handler directly. The second way is like menu items. When the button is clicked, the corresponding action is activated. It is a bit complicated because you need to create an action and its “activate” handler in advance. But one advantage is you can connect two or more things to the action. For example, an accelerator can be connected to the action. Accelerators are keys that connects to actions. For example, Ctrl+O is often connected to a file open action. So, both open button and Ctrl+O activates an open action. The latter way is used in the XML file above.</li> <li>You can specify a theme icon to GtkMenuButton with “icon-name” poperty. The “open-menu-symbolic” is an image that is called hamburger menu.</li> </ul> <p>The <code>menu.ui</code> XML file defines the menu for GtkMenuButton.</p> <div class="sourceCode" id="cb2"><pre class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb2-1"><a href="#cb2-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="cb2-2"><a href="#cb2-2"></a><<span class="kw">interface</span>></span> <span id="cb2-3"><a href="#cb2-3"></a> <<span class="kw">menu</span><span class="ot"> id=</span><span class="st">"menu"</span>></span> <span id="cb2-4"><a href="#cb2-4"></a> <<span class="kw">section</span>></span> <span id="cb2-5"><a href="#cb2-5"></a> <<span class="kw">item</span>></span> <span id="cb2-6"><a href="#cb2-6"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>New</<span class="kw">attribute</span>></span> <span id="cb2-7"><a href="#cb2-7"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>win.new</<span class="kw">attribute</span>></span> <span id="cb2-8"><a href="#cb2-8"></a> </<span class="kw">item</span>></span> <span id="cb2-9"><a href="#cb2-9"></a> <<span class="kw">item</span>></span> <span id="cb2-10"><a href="#cb2-10"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>Save As…</<span class="kw">attribute</span>></span> <span id="cb2-11"><a href="#cb2-11"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>win.saveas</<span class="kw">attribute</span>></span> <span id="cb2-12"><a href="#cb2-12"></a> </<span class="kw">item</span>></span> <span id="cb2-13"><a href="#cb2-13"></a> </<span class="kw">section</span>></span> <span id="cb2-14"><a href="#cb2-14"></a> <<span class="kw">section</span>></span> <span id="cb2-15"><a href="#cb2-15"></a> <<span class="kw">item</span>></span> <span id="cb2-16"><a href="#cb2-16"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>Preference</<span class="kw">attribute</span>></span> <span id="cb2-17"><a href="#cb2-17"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>win.pref</<span class="kw">attribute</span>></span> <span id="cb2-18"><a href="#cb2-18"></a> </<span class="kw">item</span>></span> <span id="cb2-19"><a href="#cb2-19"></a> </<span class="kw">section</span>></span> <span id="cb2-20"><a href="#cb2-20"></a> <<span class="kw">section</span>></span> <span id="cb2-21"><a href="#cb2-21"></a> <<span class="kw">item</span>></span> <span id="cb2-22"><a href="#cb2-22"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"label"</span>>Quit</<span class="kw">attribute</span>></span> <span id="cb2-23"><a href="#cb2-23"></a> <<span class="kw">attribute</span><span class="ot"> name=</span><span class="st">"action"</span>>win.close-all</<span class="kw">attribute</span>></span> <span id="cb2-24"><a href="#cb2-24"></a> </<span class="kw">item</span>></span> <span id="cb2-25"><a href="#cb2-25"></a> </<span class="kw">section</span>></span> <span id="cb2-26"><a href="#cb2-26"></a> </<span class="kw">menu</span>></span> <span id="cb2-27"><a href="#cb2-27"></a></<span class="kw">interface</span>></span></code></pre></div> <p>There are four menu items and they are connected to actions.</p> <h2 id="the-header-file">The header file</h2> <p>The following is the codes of <code>tfewindow.h</code>.</p> <div class="sourceCode" id="cb3"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a><span class="pp">#pragma once</span></span> <span id="cb3-2"><a href="#cb3-2"></a></span> <span id="cb3-3"><a href="#cb3-3"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span> <span id="cb3-4"><a href="#cb3-4"></a></span> <span id="cb3-5"><a href="#cb3-5"></a><span class="pp">#define TFE_TYPE_WINDOW tfe_window_get_type </span><span class="op">()</span></span> <span id="cb3-6"><a href="#cb3-6"></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="cb3-7"><a href="#cb3-7"></a></span> <span id="cb3-8"><a href="#cb3-8"></a><span class="dt">void</span></span> <span id="cb3-9"><a href="#cb3-9"></a>tfe_window_notebook_page_new <span class="op">(</span>TfeWindow <span class="op">*</span>win<span class="op">);</span></span> <span id="cb3-10"><a href="#cb3-10"></a></span> <span id="cb3-11"><a href="#cb3-11"></a><span class="dt">void</span></span> <span id="cb3-12"><a href="#cb3-12"></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="cb3-13"><a href="#cb3-13"></a></span> <span id="cb3-14"><a href="#cb3-14"></a>GtkWidget <span class="op">*</span></span> <span id="cb3-15"><a href="#cb3-15"></a>tfe_window_new <span class="op">(</span>GtkApplication <span class="op">*</span>app<span class="op">);</span></span></code></pre></div> <ul> <li>5-6: <code>TFE_TYPE_WINDOW</code> definition and the <code>G_DECLARE_FINAL_TYPE</code> macro.</li> <li>8-15: Public functions. The first two functions creates a notebook page and the last function creates a window.</li> </ul> <h2 id="c-file">C file</h2> <h3 id="a-composite-widget">A composite widget</h3> <p>The following codes are extracted from <code>tfewindow.c</code>.</p> <div class="sourceCode" id="cb4"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span> <span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">"tfewindow.h"</span></span> <span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span> <span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> _TfeWindow <span class="op">{</span></span> <span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a> GtkApplicationWindow parent<span class="op">;</span></span> <span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a> GtkMenuButton <span class="op">*</span>btnm<span class="op">;</span></span> <span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a> GtkNotebook <span class="op">*</span>nb<span class="op">;</span></span> <span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a> gboolean is_quit<span class="op">;</span></span> <span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span> <span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a></span> <span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>G_DEFINE_FINAL_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="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a></span> <span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>tfe_window_dispose <span class="op">(</span>GObject <span class="op">*</span>gobject<span class="op">)</span> <span class="op">{</span></span> <span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a> gtk_widget_dispose_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>gobject<span class="op">),</span> TFE_TYPE_WINDOW<span class="op">);</span></span> <span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a> G_OBJECT_CLASS <span class="op">(</span>tfe_window_parent_class<span class="op">)-></span>dispose <span class="op">(</span>gobject<span class="op">);</span></span> <span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> <span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a></span> <span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a>tfe_window_init <span class="op">(</span>TfeWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span> <span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span> <span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a> GMenuModel <span class="op">*</span>menu<span class="op">;</span></span> <span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a></span> <span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a> gtk_widget_init_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>win<span class="op">));</span></span> <span id="cb4-25"><a href="#cb4-25" aria-hidden="true" tabindex="-1"></a></span> <span id="cb4-26"><a href="#cb4-26" aria-hidden="true" tabindex="-1"></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="cb4-27"><a href="#cb4-27" aria-hidden="true" tabindex="-1"></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="cb4-28"><a href="#cb4-28" aria-hidden="true" tabindex="-1"></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="cb4-29"><a href="#cb4-29" aria-hidden="true" tabindex="-1"></a> g_object_unref<span class="op">(</span>build<span class="op">);</span></span> <span id="cb4-30"><a href="#cb4-30" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span> <span id="cb4-31"><a href="#cb4-31" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> <span id="cb4-32"><a href="#cb4-32" aria-hidden="true" tabindex="-1"></a></span> <span id="cb4-33"><a href="#cb4-33" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb4-34"><a href="#cb4-34" aria-hidden="true" tabindex="-1"></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="cb4-35"><a href="#cb4-35" aria-hidden="true" tabindex="-1"></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="cb4-36"><a href="#cb4-36" aria-hidden="true" tabindex="-1"></a></span> <span id="cb4-37"><a href="#cb4-37" aria-hidden="true" tabindex="-1"></a> object_class<span class="op">-></span>dispose <span class="op">=</span> tfe_window_dispose<span class="op">;</span></span> <span id="cb4-38"><a href="#cb4-38" aria-hidden="true" tabindex="-1"></a> gtk_widget_class_set_template_from_resource <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> <span class="st">"/com/github/ToshioCP/tfe/tfewindow.ui"</span><span class="op">);</span></span> <span id="cb4-39"><a href="#cb4-39" aria-hidden="true" tabindex="-1"></a> gtk_widget_class_bind_template_child <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> TfeWindow<span class="op">,</span> btnm<span class="op">);</span></span> <span id="cb4-40"><a href="#cb4-40" aria-hidden="true" tabindex="-1"></a> gtk_widget_class_bind_template_child <span class="op">(</span>GTK_WIDGET_CLASS <span class="op">(</span>class<span class="op">),</span> TfeWindow<span class="op">,</span> nb<span class="op">);</span></span> <span id="cb4-41"><a href="#cb4-41" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span> <span id="cb4-42"><a href="#cb4-42" aria-hidden="true" tabindex="-1"></a></span> <span id="cb4-43"><a href="#cb4-43" aria-hidden="true" tabindex="-1"></a>GtkWidget <span class="op">*</span></span> <span id="cb4-44"><a href="#cb4-44" aria-hidden="true" tabindex="-1"></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="cb4-45"><a href="#cb4-45" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> GTK_WIDGET <span class="op">(</span>g_object_new <span class="op">(</span>TFE_TYPE_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="cb4-46"><a href="#cb4-46" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> <p>The program above is similar to <code>tfealert.c</code> and <code>tfepref.c</code>. It uses the same way to build a composite widget. But there’s one thing new. It is menu. The menu is built from the XML resource <code>menu.ui</code> and inserted into the menu button. It is done in the instance initialization function <code>tfe_window_init</code>.</p> <h3 id="actions">Actions</h3> <p>Actions can belong to an application or window. Tfe only has one top window and all the actions are registered in the window. For example, “close-all” action destroys the top level window and that brings the application to quit. You can make “app.quit” action instead of “win.close-all”. It’s your choice. If your application has two or more windows, both “app.quit” and “win:close-all”, which closes all the notebook pages on the window, may be necessary. Anyway, you need to consider that each action should belong to the application or a window.</p> <p>Actions are defined in the instance initialization function.</p> <div class="sourceCode" id="cb5"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></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="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span> <span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="co">/* ----- action ----- */</span></span> <span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">const</span> GActionEntry win_entries<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span></span> <span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></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="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></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="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></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="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></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="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></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="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></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="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></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="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span> <span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></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="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span> <span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div> <p>Two things are necessary, an array and the <code>g_action_map_add_action_entries</code> function.</p> <ul> <li>The element of the array is the GActionEntry structure. The structure has the following members: <ul> <li>an action name</li> <li>a handler for the activate signal</li> <li>the type of the parameter or NULL for no parameter</li> <li>the initial state for the action</li> <li>a handler for the change-state signal</li> </ul></li> <li>The actions above are stateless and have no parameters. So, the third parameter and after are all NULL.</li> <li>The function <code>g_action_map_add_action_entries</code> adds the actions in the <code>win_entries</code> array to the action map <code>win</code>. The last argument <code>win</code> is the user_data, which is the last argument of handlers.</li> <li>All the handlers are in <code>tfewindow.c</code> program and shown in the following subsections.</li> </ul> <h3 id="the-handlers-of-the-actions">The handlers of the actions</h3> <h4 id="open_activated">open_activated</h4> <p>The callback function <code>open_activated</code> is an activate signal handler on “open” action.</p> <div class="sourceCode" id="cb6"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb6-2"><a href="#cb6-2"></a>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="cb6-3"><a href="#cb6-3"></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="cb6-4"><a href="#cb6-4"></a> GtkWidget <span class="op">*</span>tv <span class="op">=</span> tfe_text_view_new <span class="op">();</span></span> <span id="cb6-5"><a href="#cb6-5"></a></span> <span id="cb6-6"><a href="#cb6-6"></a> g_signal_connect <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> <span class="st">"open-response"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>open_response_cb<span class="op">),</span> win<span class="op">);</span></span> <span id="cb6-7"><a href="#cb6-7"></a> tfe_text_view_open <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span> <span id="cb6-8"><a href="#cb6-8"></a><span class="op">}</span></span></code></pre></div> <p>It connects the “open-response” signal on the newly created TfeTextView instance and just calls <code>tfe_text_view_open</code>. It leaves the rest of the task to the signal handler <code>open_response_cb</code>.</p> <div class="sourceCode" id="cb7"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb7-2"><a href="#cb7-2"></a>open_response_cb <span class="op">(</span>TfeTextView <span class="op">*</span>tv<span class="op">,</span> <span class="dt">int</span> response<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb7-3"><a href="#cb7-3"></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="cb7-4"><a href="#cb7-4"></a> GFile <span class="op">*</span>file<span class="op">;</span></span> <span id="cb7-5"><a href="#cb7-5"></a> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">;</span></span> <span id="cb7-6"><a href="#cb7-6"></a></span> <span id="cb7-7"><a href="#cb7-7"></a> <span class="cf">if</span> <span class="op">(</span>response <span class="op">!=</span> TFE_OPEN_RESPONSE_SUCCESS<span class="op">)</span> <span class="op">{</span></span> <span id="cb7-8"><a href="#cb7-8"></a> g_object_ref_sink <span class="op">(</span>tv<span class="op">);</span></span> <span id="cb7-9"><a href="#cb7-9"></a> g_object_unref <span class="op">(</span>tv<span class="op">);</span></span> <span id="cb7-10"><a href="#cb7-10"></a> <span class="op">}</span><span class="cf">else</span> <span class="cf">if</span> <span class="op">(!</span> G_IS_FILE <span class="op">(</span>file <span class="op">=</span> tfe_text_view_get_file <span class="op">(</span>tv<span class="op">)))</span> <span class="op">{</span></span> <span id="cb7-11"><a href="#cb7-11"></a> g_object_ref_sink <span class="op">(</span>tv<span class="op">);</span></span> <span id="cb7-12"><a href="#cb7-12"></a> g_object_unref <span class="op">(</span>tv<span class="op">);</span></span> <span id="cb7-13"><a href="#cb7-13"></a> <span class="op">}</span><span class="cf">else</span> <span class="op">{</span></span> <span id="cb7-14"><a href="#cb7-14"></a> filename <span class="op">=</span> g_file_get_basename <span class="op">(</span>file<span class="op">);</span></span> <span id="cb7-15"><a href="#cb7-15"></a> g_object_unref <span class="op">(</span>file<span class="op">);</span></span> <span id="cb7-16"><a href="#cb7-16"></a> notebook_page_build <span class="op">(</span>win<span class="op">,</span> GTK_WIDGET <span class="op">(</span>tv<span class="op">),</span> filename<span class="op">);</span></span> <span id="cb7-17"><a href="#cb7-17"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb7-18"><a href="#cb7-18"></a> <span class="op">}</span></span> <span id="cb7-19"><a href="#cb7-19"></a><span class="op">}</span></span></code></pre></div> <p>If the TfeTextView instance failed to read a file, it destroys the instance with <code>g_object_ref_sink</code> and <code>g_object_unref</code>. Since newly created widgets are floating, you need to convert the floating reference to the normal reference before you release it. The conversion is done with <code>g_object_ref_sink</code>.</p> <p>If the instance successfully read the file, it calls <code>notebook_page_build</code> to build a notebook page and add it to the GtkNotebook object.</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="dt">static</span> <span class="dt">void</span></span> <span id="cb8-2"><a href="#cb8-2"></a>notebook_page_build <span class="op">(</span>TfeWindow <span class="op">*</span>win<span class="op">,</span> GtkWidget <span class="op">*</span>tv<span class="op">,</span> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">)</span> <span class="op">{</span></span> <span id="cb8-3"><a href="#cb8-3"></a> <span class="co">// The arguments win, tb and filename are owned by the caller.</span></span> <span id="cb8-4"><a href="#cb8-4"></a> <span class="co">// If tv has a floating reference, it is consumed by the function.</span></span> <span id="cb8-5"><a href="#cb8-5"></a> GtkWidget <span class="op">*</span>scr <span class="op">=</span> gtk_scrolled_window_new <span class="op">();</span></span> <span id="cb8-6"><a href="#cb8-6"></a> GtkTextBuffer <span class="op">*</span>tb <span class="op">=</span> gtk_text_view_get_buffer <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span> <span id="cb8-7"><a href="#cb8-7"></a> GtkNotebookPage <span class="op">*</span>nbp<span class="op">;</span></span> <span id="cb8-8"><a href="#cb8-8"></a> GtkWidget <span class="op">*</span>lab<span class="op">;</span></span> <span id="cb8-9"><a href="#cb8-9"></a> <span class="dt">int</span> i<span class="op">;</span></span> <span id="cb8-10"><a href="#cb8-10"></a></span> <span id="cb8-11"><a href="#cb8-11"></a> gtk_text_view_set_wrap_mode <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> GTK_WRAP_WORD_CHAR<span class="op">);</span></span> <span id="cb8-12"><a href="#cb8-12"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> tv<span class="op">);</span></span> <span id="cb8-13"><a href="#cb8-13"></a> lab <span class="op">=</span> gtk_label_new <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb8-14"><a href="#cb8-14"></a> i <span class="op">=</span> gtk_notebook_append_page <span class="op">(</span>win<span class="op">-></span>nb<span class="op">,</span> scr<span class="op">,</span> lab<span class="op">);</span></span> <span id="cb8-15"><a href="#cb8-15"></a> nbp <span class="op">=</span> gtk_notebook_get_page <span class="op">(</span>win<span class="op">-></span>nb<span class="op">,</span> scr<span class="op">);</span></span> <span id="cb8-16"><a href="#cb8-16"></a> g_object_set <span class="op">(</span>nbp<span class="op">,</span> <span class="st">"tab-expand"</span><span class="op">,</span> TRUE<span class="op">,</span> NULL<span class="op">);</span></span> <span id="cb8-17"><a href="#cb8-17"></a> gtk_notebook_set_current_page <span class="op">(</span>win<span class="op">-></span>nb<span class="op">,</span> i<span class="op">);</span></span> <span id="cb8-18"><a href="#cb8-18"></a> g_signal_connect <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> <span class="st">"change-file"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>file_changed_cb<span class="op">),</span> win<span class="op">-></span>nb<span class="op">);</span></span> <span id="cb8-19"><a href="#cb8-19"></a> g_signal_connect <span class="op">(</span>tb<span class="op">,</span> <span class="st">"modified-changed"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>modified_changed_cb<span class="op">),</span> tv<span class="op">);</span></span> <span id="cb8-20"><a href="#cb8-20"></a><span class="op">}</span></span></code></pre></div> <p>This function is a kind of library function and it is called from the different three places.</p> <p>This function creates a new GtkScrolledWindow instance and sets its child to <code>tv</code>. Then it appends it to the GtkNotebook instance <code>win->nb</code>. And it sets the tab label to the filename.</p> <p>After the building, it connects two signals and handlers.</p> <ul> <li>“change-file” signal and <code>file_changed_cb</code> handler. If the TfeTextView instance changes the file, the handler is called and the notebook page tab is updated.</li> <li>“modified-changed” signal and <code>modified_changed_cb</code> handler. If the text in the buffer of TfeTextView instance is modified, an asterisk is added at the beginning of the filename of the notebook page tab. If the text is saved to the file, the asterisk is removed. The asterisk tells the user that the text has been modified or not.</li> </ul> <div class="sourceCode" id="cb9"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb9-2"><a href="#cb9-2"></a>file_changed_cb <span class="op">(</span>TfeTextView <span class="op">*</span>tv<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb9-3"><a href="#cb9-3"></a> GtkNotebook <span class="op">*</span>nb <span class="op">=</span> GTK_NOTEBOOK <span class="op">(</span>user_data<span class="op">);</span></span> <span id="cb9-4"><a href="#cb9-4"></a> GtkWidget <span class="op">*</span>scr<span class="op">;</span></span> <span id="cb9-5"><a href="#cb9-5"></a> GtkWidget <span class="op">*</span>label<span class="op">;</span></span> <span id="cb9-6"><a href="#cb9-6"></a> GFile <span class="op">*</span>file<span class="op">;</span></span> <span id="cb9-7"><a href="#cb9-7"></a> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">;</span></span> <span id="cb9-8"><a href="#cb9-8"></a></span> <span id="cb9-9"><a href="#cb9-9"></a> file <span class="op">=</span> tfe_text_view_get_file <span class="op">(</span>tv<span class="op">);</span></span> <span id="cb9-10"><a href="#cb9-10"></a> scr <span class="op">=</span> gtk_widget_get_parent <span class="op">(</span>GTK_WIDGET <span class="op">(</span>tv<span class="op">));</span></span> <span id="cb9-11"><a href="#cb9-11"></a> <span class="cf">if</span> <span class="op">(</span>G_IS_FILE <span class="op">(</span>file<span class="op">))</span> <span class="op">{</span></span> <span id="cb9-12"><a href="#cb9-12"></a> filename <span class="op">=</span> g_file_get_basename <span class="op">(</span>file<span class="op">);</span></span> <span id="cb9-13"><a href="#cb9-13"></a> g_object_unref <span class="op">(</span>file<span class="op">);</span></span> <span id="cb9-14"><a href="#cb9-14"></a> <span class="op">}</span> <span class="cf">else</span></span> <span id="cb9-15"><a href="#cb9-15"></a> filename <span class="op">=</span> get_untitled <span class="op">();</span></span> <span id="cb9-16"><a href="#cb9-16"></a> label <span class="op">=</span> gtk_label_new <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb9-17"><a href="#cb9-17"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb9-18"><a href="#cb9-18"></a> gtk_notebook_set_tab_label <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">),</span> scr<span class="op">,</span> label<span class="op">);</span></span> <span id="cb9-19"><a href="#cb9-19"></a><span class="op">}</span></span> <span id="cb9-20"><a href="#cb9-20"></a></span> <span id="cb9-21"><a href="#cb9-21"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb9-22"><a href="#cb9-22"></a>modified_changed_cb <span class="op">(</span>GtkTextBuffer <span class="op">*</span>tb<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb9-23"><a href="#cb9-23"></a> TfeTextView <span class="op">*</span>tv <span class="op">=</span> TFE_TEXT_VIEW <span class="op">(</span>user_data<span class="op">);</span></span> <span id="cb9-24"><a href="#cb9-24"></a> GtkWidget <span class="op">*</span>scr <span class="op">=</span> gtk_widget_get_parent <span class="op">(</span>GTK_WIDGET <span class="op">(</span>tv<span class="op">));</span></span> <span id="cb9-25"><a href="#cb9-25"></a> GtkWidget <span class="op">*</span>nb <span class="op">=</span> gtk_widget_get_ancestor <span class="op">(</span>GTK_WIDGET <span class="op">(</span>tv<span class="op">),</span> GTK_TYPE_NOTEBOOK<span class="op">);</span></span> <span id="cb9-26"><a href="#cb9-26"></a> GtkWidget <span class="op">*</span>label<span class="op">;</span></span> <span id="cb9-27"><a href="#cb9-27"></a> GFile <span class="op">*</span>file<span class="op">;</span></span> <span id="cb9-28"><a href="#cb9-28"></a> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">;</span></span> <span id="cb9-29"><a href="#cb9-29"></a> <span class="dt">char</span> <span class="op">*</span>text<span class="op">;</span></span> <span id="cb9-30"><a href="#cb9-30"></a></span> <span id="cb9-31"><a href="#cb9-31"></a> file <span class="op">=</span> tfe_text_view_get_file <span class="op">(</span>tv<span class="op">);</span></span> <span id="cb9-32"><a href="#cb9-32"></a> filename <span class="op">=</span> g_file_get_basename <span class="op">(</span>file<span class="op">);</span></span> <span id="cb9-33"><a href="#cb9-33"></a> <span class="cf">if</span> <span class="op">(</span>gtk_text_buffer_get_modified <span class="op">(</span>tb<span class="op">))</span></span> <span id="cb9-34"><a href="#cb9-34"></a> text <span class="op">=</span> g_strdup_printf <span class="op">(</span><span class="st">"*</span><span class="sc">%s</span><span class="st">"</span><span class="op">,</span> filename<span class="op">);</span></span> <span id="cb9-35"><a href="#cb9-35"></a> <span class="cf">else</span></span> <span id="cb9-36"><a href="#cb9-36"></a> text <span class="op">=</span> g_strdup <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb9-37"><a href="#cb9-37"></a> g_object_unref <span class="op">(</span>file<span class="op">);</span></span> <span id="cb9-38"><a href="#cb9-38"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb9-39"><a href="#cb9-39"></a> label <span class="op">=</span> gtk_label_new <span class="op">(</span>text<span class="op">);</span></span> <span id="cb9-40"><a href="#cb9-40"></a> g_free <span class="op">(</span>text<span class="op">);</span></span> <span id="cb9-41"><a href="#cb9-41"></a> gtk_notebook_set_tab_label <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">),</span> scr<span class="op">,</span> label<span class="op">);</span></span> <span id="cb9-42"><a href="#cb9-42"></a><span class="op">}</span></span></code></pre></div> <h4 id="save_activated">save_activated</h4> <p>The callback function <code>save_activated</code> is an activate signal handler on “save” action.</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="dt">static</span> <span class="dt">void</span></span> <span id="cb10-2"><a href="#cb10-2"></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="cb10-3"><a href="#cb10-3"></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="cb10-4"><a href="#cb10-4"></a> TfeTextView <span class="op">*</span>tv <span class="op">=</span> get_current_textview <span class="op">(</span>win<span class="op">-></span>nb<span class="op">);</span></span> <span id="cb10-5"><a href="#cb10-5"></a></span> <span id="cb10-6"><a href="#cb10-6"></a> tfe_text_view_save <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span> <span id="cb10-7"><a href="#cb10-7"></a><span class="op">}</span></span></code></pre></div> <p>This function gets the current TfeTextView instance with the function <code>get_current_textview</code>. And it just calls <code>tfe_text_view_save</code>.</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="dt">static</span> TfeTextView <span class="op">*</span></span> <span id="cb11-2"><a href="#cb11-2"></a>get_current_textview <span class="op">(</span>GtkNotebook <span class="op">*</span>nb<span class="op">)</span> <span class="op">{</span></span> <span id="cb11-3"><a href="#cb11-3"></a> <span class="dt">int</span> i<span class="op">;</span></span> <span id="cb11-4"><a href="#cb11-4"></a> GtkWidget <span class="op">*</span>scr<span class="op">;</span></span> <span id="cb11-5"><a href="#cb11-5"></a> GtkWidget <span class="op">*</span>tv<span class="op">;</span></span> <span id="cb11-6"><a href="#cb11-6"></a></span> <span id="cb11-7"><a href="#cb11-7"></a> i <span class="op">=</span> gtk_notebook_get_current_page <span class="op">(</span>nb<span class="op">);</span></span> <span id="cb11-8"><a href="#cb11-8"></a> scr <span class="op">=</span> gtk_notebook_get_nth_page <span class="op">(</span>nb<span class="op">,</span> i<span class="op">);</span></span> <span id="cb11-9"><a href="#cb11-9"></a> tv <span class="op">=</span> gtk_scrolled_window_get_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">));</span></span> <span id="cb11-10"><a href="#cb11-10"></a> <span class="cf">return</span> TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">);</span></span> <span id="cb11-11"><a href="#cb11-11"></a><span class="op">}</span></span></code></pre></div> <h4 id="close_activated">close_activated</h4> <p>The callback function <code>close_activated</code> is an activate signal handler on “close” action. It closes the current notebook page.</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="dt">static</span> <span class="dt">void</span></span> <span id="cb12-2"><a href="#cb12-2"></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="cb12-3"><a href="#cb12-3"></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="cb12-4"><a href="#cb12-4"></a> TfeTextView <span class="op">*</span>tv<span class="op">;</span></span> <span id="cb12-5"><a href="#cb12-5"></a> GtkTextBuffer <span class="op">*</span>tb<span class="op">;</span></span> <span id="cb12-6"><a href="#cb12-6"></a> GtkWidget <span class="op">*</span>alert<span class="op">;</span></span> <span id="cb12-7"><a href="#cb12-7"></a></span> <span id="cb12-8"><a href="#cb12-8"></a> tv <span class="op">=</span> get_current_textview <span class="op">(</span>win<span class="op">-></span>nb<span class="op">);</span></span> <span id="cb12-9"><a href="#cb12-9"></a> tb <span class="op">=</span> gtk_text_view_get_buffer <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span> <span id="cb12-10"><a href="#cb12-10"></a> <span class="cf">if</span> <span class="op">(!</span> gtk_text_buffer_get_modified <span class="op">(</span>tb<span class="op">))</span> <span class="co">/* is saved? */</span></span> <span id="cb12-11"><a href="#cb12-11"></a> notebook_page_close <span class="op">(</span>win<span class="op">);</span></span> <span id="cb12-12"><a href="#cb12-12"></a> <span class="cf">else</span> <span class="op">{</span></span> <span id="cb12-13"><a href="#cb12-13"></a> win<span class="op">-></span>is_quit <span class="op">=</span> FALSE<span class="op">;</span></span> <span id="cb12-14"><a href="#cb12-14"></a> alert <span class="op">=</span> tfe_alert_new_with_data <span class="op">(</span><span class="st">"Are you sure?"</span><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 class="st">"Close"</span><span class="op">);</span></span> <span id="cb12-15"><a href="#cb12-15"></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="cb12-16"><a href="#cb12-16"></a> g_signal_connect <span class="op">(</span>TFE_ALERT <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="cb12-17"><a href="#cb12-17"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>alert<span class="op">));</span></span> <span id="cb12-18"><a href="#cb12-18"></a> <span class="op">}</span></span> <span id="cb12-19"><a href="#cb12-19"></a><span class="op">}</span></span></code></pre></div> <p>If the text in the current page has been saved, it calls <code>notebook_page_close</code> to close the page. Otherwise, it sets <code>win->is_quit</code> to FALSE and show the alert dialog. The “response” signal on the dialog is connected to the handler <code>alert_response_cb</code>.</p> <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="dt">static</span> <span class="dt">void</span></span> <span id="cb13-2"><a href="#cb13-2"></a>notebook_page_close <span class="op">(</span>TfeWindow <span class="op">*</span>win<span class="op">){</span></span> <span id="cb13-3"><a href="#cb13-3"></a> <span class="dt">int</span> i<span class="op">;</span></span> <span id="cb13-4"><a href="#cb13-4"></a></span> <span id="cb13-5"><a href="#cb13-5"></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">1</span><span class="op">)</span></span> <span id="cb13-6"><a href="#cb13-6"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span> <span id="cb13-7"><a href="#cb13-7"></a> <span class="cf">else</span> <span class="op">{</span></span> <span id="cb13-8"><a href="#cb13-8"></a> i <span class="op">=</span> gtk_notebook_get_current_page <span class="op">(</span>win<span class="op">-></span>nb<span class="op">);</span></span> <span id="cb13-9"><a href="#cb13-9"></a> gtk_notebook_remove_page <span class="op">(</span>win<span class="op">-></span>nb<span class="op">,</span> i<span class="op">);</span></span> <span id="cb13-10"><a href="#cb13-10"></a> <span class="op">}</span></span> <span id="cb13-11"><a href="#cb13-11"></a><span class="op">}</span></span></code></pre></div> <p>If the notebook has only one page, it destroys the window and the application quits. Otherwise, it removes the current page.</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="dt">static</span> <span class="dt">void</span></span> <span id="cb14-2"><a href="#cb14-2"></a>alert_response_cb <span class="op">(</span>TfeAlert <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="cb14-3"><a href="#cb14-3"></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="cb14-4"><a href="#cb14-4"></a></span> <span id="cb14-5"><a href="#cb14-5"></a> <span class="cf">if</span> <span class="op">(</span>response_id <span class="op">==</span> TFE_ALERT_RESPONSE_ACCEPT<span class="op">)</span> <span class="op">{</span></span> <span id="cb14-6"><a href="#cb14-6"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>is_quit<span class="op">)</span></span> <span id="cb14-7"><a href="#cb14-7"></a> gtk_window_destroy<span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span> <span id="cb14-8"><a href="#cb14-8"></a> <span class="cf">else</span></span> <span id="cb14-9"><a href="#cb14-9"></a> notebook_page_close <span class="op">(</span>win<span class="op">);</span></span> <span id="cb14-10"><a href="#cb14-10"></a> <span class="op">}</span></span> <span id="cb14-11"><a href="#cb14-11"></a><span class="op">}</span></span></code></pre></div> <p>If the user clicked on the cacel button, it does nothing. If the user clicked on the accept button, which is the same as close button, it calls <code>notebook_page_close</code>. Note that <code>win->is_quit</code> has been set to FALSE in the <code>close_activated</code> function.</p> <h4 id="new_activated">new_activated</h4> <p>The callback function <code>new_activated</code> is an activate signal handler on “new” action.</p> <div class="sourceCode" id="cb15"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb15-1"><a href="#cb15-1"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb15-2"><a href="#cb15-2"></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="cb15-3"><a href="#cb15-3"></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="cb15-4"><a href="#cb15-4"></a></span> <span id="cb15-5"><a href="#cb15-5"></a> tfe_window_notebook_page_new <span class="op">(</span>win<span class="op">);</span></span> <span id="cb15-6"><a href="#cb15-6"></a><span class="op">}</span></span></code></pre></div> <p>It just calls <code>tfe_window_notebook_page_new</code>, which is a public method of TfeWindow.</p> <div class="sourceCode" id="cb16"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb16-1"><a href="#cb16-1"></a><span class="dt">void</span></span> <span id="cb16-2"><a href="#cb16-2"></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="cb16-3"><a href="#cb16-3"></a> GtkWidget <span class="op">*</span>tv<span class="op">;</span></span> <span id="cb16-4"><a href="#cb16-4"></a> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">;</span></span> <span id="cb16-5"><a href="#cb16-5"></a></span> <span id="cb16-6"><a href="#cb16-6"></a> tv <span class="op">=</span> tfe_text_view_new <span class="op">();</span></span> <span id="cb16-7"><a href="#cb16-7"></a> filename <span class="op">=</span> get_untitled <span class="op">();</span></span> <span id="cb16-8"><a href="#cb16-8"></a> notebook_page_build <span class="op">(</span>win<span class="op">,</span> tv<span class="op">,</span> filename<span class="op">);</span></span> <span id="cb16-9"><a href="#cb16-9"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb16-10"><a href="#cb16-10"></a><span class="op">}</span></span></code></pre></div> <p>This function creates a new TfeTextView instance, “Untitled” family string and calls <code>notebook_page_build</code>.</p> <h4 id="saveas_activated">saveas_activated</h4> <p>The callback function <code>saveas_activated</code> is an activate signal handler on “saveas” action.</p> <div class="sourceCode" id="cb17"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb17-1"><a href="#cb17-1"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb17-2"><a href="#cb17-2"></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="cb17-3"><a href="#cb17-3"></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="cb17-4"><a href="#cb17-4"></a> TfeTextView <span class="op">*</span>tv <span class="op">=</span> get_current_textview <span class="op">(</span>win<span class="op">-></span>nb<span class="op">);</span></span> <span id="cb17-5"><a href="#cb17-5"></a></span> <span id="cb17-6"><a href="#cb17-6"></a> tfe_text_view_saveas <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span> <span id="cb17-7"><a href="#cb17-7"></a><span class="op">}</span></span></code></pre></div> <p>This function gets the current page TfeTextView instance and calls <code>tfe_text_view_saveas</code>.</p> <h4 id="pref_activated">pref_activated</h4> <p>The callback function <code>pref_activated</code> is an activate signal handler on “pref” action.</p> <div class="sourceCode" id="cb18"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb18-1"><a href="#cb18-1"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb18-2"><a href="#cb18-2"></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="cb18-3"><a href="#cb18-3"></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="cb18-4"><a href="#cb18-4"></a> GtkWidget <span class="op">*</span>pref<span class="op">;</span></span> <span id="cb18-5"><a href="#cb18-5"></a></span> <span id="cb18-6"><a href="#cb18-6"></a> pref <span class="op">=</span> tfe_pref_new <span class="op">();</span></span> <span id="cb18-7"><a href="#cb18-7"></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="cb18-8"><a href="#cb18-8"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>pref<span class="op">));</span></span> <span id="cb18-9"><a href="#cb18-9"></a><span class="op">}</span></span></code></pre></div> <p>This function creates a TfePref instance, which is a dialog, and sets the transient parent window to <code>win</code>. And it shows the dialog.</p> <h4 id="close_all_activated">close_all_activated</h4> <p>The callback function <code>close_all_activated</code> is an activate signal handler on “close_all” action.</p> <div class="sourceCode" id="cb19"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb19-1"><a href="#cb19-1"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb19-2"><a href="#cb19-2"></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="cb19-3"><a href="#cb19-3"></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="cb19-4"><a href="#cb19-4"></a></span> <span id="cb19-5"><a href="#cb19-5"></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="cb19-6"><a href="#cb19-6"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span> <span id="cb19-7"><a href="#cb19-7"></a><span class="op">}</span></span></code></pre></div> <p>It first calls the function <code>close_request_cb</code>. It is a callback function for the “close-request” signal on the top window. It returns FALSE if all the texts have been saved. Otherwise it returns TRUE.</p> <p>Therefore, function <code>close_all_activated</code> destroys the top window if all the texts have been saved. Otherwise it does nothing. But, the function <code>close_request_cb</code> shows an alert dialog and if the user clicks on the accept button, the window will be destroyed.</p> <h3 id="window-close-request-signal">Window “close-request” signal</h3> <p>GtkWindow has a “close-request” signal and it is emitted when the close button, which is x-shaped button at the top right corner, is clicked on. And the user handler is called before the default handler. If the user handler returns TRUE, the rest of the close process is skipped. If it returns FALSE, the rest will go on and the window will be destroyed.</p> <div class="sourceCode" id="cb20"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb20-1"><a href="#cb20-1"></a><span class="dt">static</span> gboolean</span> <span id="cb20-2"><a href="#cb20-2"></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="cb20-3"><a href="#cb20-3"></a> TfeAlert <span class="op">*</span>alert<span class="op">;</span></span> <span id="cb20-4"><a href="#cb20-4"></a></span> <span id="cb20-5"><a href="#cb20-5"></a> <span class="cf">if</span> <span class="op">(</span>is_saved_all <span class="op">(</span>win<span class="op">-></span>nb<span class="op">))</span></span> <span id="cb20-6"><a href="#cb20-6"></a> <span class="cf">return</span> FALSE<span class="op">;</span></span> <span id="cb20-7"><a href="#cb20-7"></a> <span class="cf">else</span> <span class="op">{</span></span> <span id="cb20-8"><a href="#cb20-8"></a> win<span class="op">-></span>is_quit <span class="op">=</span> TRUE<span class="op">;</span></span> <span id="cb20-9"><a href="#cb20-9"></a> alert <span class="op">=</span> TFE_ALERT <span class="op">(</span>tfe_alert_new_with_data <span class="op">(</span><span class="st">"Are you sure?"</span><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 class="st">"Quit"</span><span class="op">));</span></span> <span id="cb20-10"><a href="#cb20-10"></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="cb20-11"><a href="#cb20-11"></a> g_signal_connect <span class="op">(</span>TFE_ALERT <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="cb20-12"><a href="#cb20-12"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>alert<span class="op">));</span></span> <span id="cb20-13"><a href="#cb20-13"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span> <span id="cb20-14"><a href="#cb20-14"></a> <span class="op">}</span></span> <span id="cb20-15"><a href="#cb20-15"></a><span class="op">}</span></span></code></pre></div> <p>First, it calls <code>is_saved_all</code> and checks if the texts have been saved. If so, it returns FALSE and the close process continues. Otherwise, it sets <code>win->is_quit</code> to TRUE and shows an alert dialog. When the user clicks on the accept or cancel button, the dialog disappears and “response” signal is emitted. Then, the handler <code>alert_response_cb</code> is called. It destroys the top window if the user clicked on the accept button since <code>win->is_quit</code> is TRUE. Otherwise it does nothing.</p> <div class="sourceCode" id="cb21"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb21-1"><a href="#cb21-1"></a><span class="dt">static</span> gboolean</span> <span id="cb21-2"><a href="#cb21-2"></a>is_saved_all <span class="op">(</span>GtkNotebook <span class="op">*</span>nb<span class="op">)</span> <span class="op">{</span></span> <span id="cb21-3"><a href="#cb21-3"></a> <span class="dt">int</span> i<span class="op">,</span> n<span class="op">;</span></span> <span id="cb21-4"><a href="#cb21-4"></a> GtkWidget <span class="op">*</span>scr<span class="op">;</span></span> <span id="cb21-5"><a href="#cb21-5"></a> GtkWidget <span class="op">*</span>tv<span class="op">;</span></span> <span id="cb21-6"><a href="#cb21-6"></a> GtkTextBuffer <span class="op">*</span>tb<span class="op">;</span></span> <span id="cb21-7"><a href="#cb21-7"></a></span> <span id="cb21-8"><a href="#cb21-8"></a> n <span class="op">=</span> gtk_notebook_get_n_pages <span class="op">(</span>nb<span class="op">);</span></span> <span id="cb21-9"><a href="#cb21-9"></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<span class="op">;</span> <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span> <span id="cb21-10"><a href="#cb21-10"></a> scr <span class="op">=</span> gtk_notebook_get_nth_page <span class="op">(</span>nb<span class="op">,</span> i<span class="op">);</span></span> <span id="cb21-11"><a href="#cb21-11"></a> tv <span class="op">=</span> gtk_scrolled_window_get_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">));</span></span> <span id="cb21-12"><a href="#cb21-12"></a> tb <span class="op">=</span> gtk_text_view_get_buffer <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span> <span id="cb21-13"><a href="#cb21-13"></a> <span class="cf">if</span> <span class="op">(</span>gtk_text_buffer_get_modified <span class="op">(</span>tb<span class="op">))</span></span> <span id="cb21-14"><a href="#cb21-14"></a> <span class="cf">return</span> FALSE<span class="op">;</span></span> <span id="cb21-15"><a href="#cb21-15"></a> <span class="op">}</span></span> <span id="cb21-16"><a href="#cb21-16"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span> <span id="cb21-17"><a href="#cb21-17"></a><span class="op">}</span></span></code></pre></div> <h3 id="public-functions">Public functions</h3> <p>There are three public functions.</p> <ul> <li><code>void tfe_window_notebook_page_new (TfeWindow *win)</code></li> <li><code>void tfe_window_notebook_page_new_with_files (TfeWindow *win, GFile **files, int n_files)</code></li> <li><code>GtkWidget *tfe_window_new (GtkApplication *app)</code></li> </ul> <p>The first function is called when the application emits the “activate” signal. The second is for “open” signal. It is given three arguments and they are owned by the caller.</p> <div class="sourceCode" id="cb22"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb22-1"><a href="#cb22-1"></a><span class="dt">void</span></span> <span id="cb22-2"><a href="#cb22-2"></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="cb22-3"><a href="#cb22-3"></a> <span class="dt">int</span> i<span class="op">;</span></span> <span id="cb22-4"><a href="#cb22-4"></a> GtkWidget <span class="op">*</span>tv<span class="op">;</span></span> <span id="cb22-5"><a href="#cb22-5"></a> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">;</span></span> <span id="cb22-6"><a href="#cb22-6"></a></span> <span id="cb22-7"><a href="#cb22-7"></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="cb22-8"><a href="#cb22-8"></a> <span class="cf">if</span> <span class="op">((</span>tv <span class="op">=</span> tfe_text_view_new_with_file <span class="op">(*(</span>files<span class="op">+</span>i<span class="op">)))</span> <span class="op">!=</span> NULL<span class="op">)</span> <span class="op">{</span></span> <span id="cb22-9"><a href="#cb22-9"></a> filename <span class="op">=</span> g_file_get_basename <span class="op">(*(</span>files<span class="op">+</span>i<span class="op">));</span></span> <span id="cb22-10"><a href="#cb22-10"></a> notebook_page_build <span class="op">(</span>win<span class="op">,</span> tv<span class="op">,</span> filename<span class="op">);</span></span> <span id="cb22-11"><a href="#cb22-11"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb22-12"><a href="#cb22-12"></a> <span class="op">}</span></span> <span id="cb22-13"><a href="#cb22-13"></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="cb22-14"><a href="#cb22-14"></a> tfe_window_notebook_page_new <span class="op">(</span>win<span class="op">);</span></span> <span id="cb22-15"><a href="#cb22-15"></a><span class="op">}</span></span></code></pre></div> <p>This function has a loop for the array <code>files</code>. It creates TfeTextView instance with the text from each file. And build a page with it.</p> <p>If an error happens and no page is created, it creates a new empty page.</p> <h3 id="full-codes-of-tfewindow.c">Full codes of tfewindow.c</h3> <p>The following is the full source codes of <code>tfewindow.c</code>.</p> <div class="sourceCode" id="cb23"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb23-1"><a href="#cb23-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span> <span id="cb23-2"><a href="#cb23-2"></a><span class="pp">#include </span><span class="im">"tfewindow.h"</span></span> <span id="cb23-3"><a href="#cb23-3"></a><span class="pp">#include </span><span class="im">"tfepref.h"</span></span> <span id="cb23-4"><a href="#cb23-4"></a><span class="pp">#include </span><span class="im">"tfealert.h"</span></span> <span id="cb23-5"><a href="#cb23-5"></a><span class="pp">#include </span><span class="im">"../tfetextview/tfetextview.h"</span></span> <span id="cb23-6"><a href="#cb23-6"></a></span> <span id="cb23-7"><a href="#cb23-7"></a><span class="kw">struct</span> _TfeWindow <span class="op">{</span></span> <span id="cb23-8"><a href="#cb23-8"></a> GtkApplicationWindow parent<span class="op">;</span></span> <span id="cb23-9"><a href="#cb23-9"></a> GtkMenuButton <span class="op">*</span>btnm<span class="op">;</span></span> <span id="cb23-10"><a href="#cb23-10"></a> GtkNotebook <span class="op">*</span>nb<span class="op">;</span></span> <span id="cb23-11"><a href="#cb23-11"></a> gboolean is_quit<span class="op">;</span></span> <span id="cb23-12"><a href="#cb23-12"></a><span class="op">};</span></span> <span id="cb23-13"><a href="#cb23-13"></a></span> <span id="cb23-14"><a href="#cb23-14"></a>G_DEFINE_FINAL_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="cb23-15"><a href="#cb23-15"></a></span> <span id="cb23-16"><a href="#cb23-16"></a><span class="co">/* Low level functions */</span></span> <span id="cb23-17"><a href="#cb23-17"></a></span> <span id="cb23-18"><a href="#cb23-18"></a><span class="co">/* Create a new untitled string */</span></span> <span id="cb23-19"><a href="#cb23-19"></a><span class="co">/* The returned string should be freed with g_free() when no longer needed. */</span></span> <span id="cb23-20"><a href="#cb23-20"></a><span class="dt">static</span> <span class="dt">char</span><span class="op">*</span></span> <span id="cb23-21"><a href="#cb23-21"></a>get_untitled <span class="op">()</span> <span class="op">{</span></span> <span id="cb23-22"><a href="#cb23-22"></a> <span class="dt">static</span> <span class="dt">int</span> c <span class="op">=</span> <span class="op">-</span><span class="dv">1</span><span class="op">;</span></span> <span id="cb23-23"><a href="#cb23-23"></a> <span class="cf">if</span> <span class="op">(++</span>c <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> </span> <span id="cb23-24"><a href="#cb23-24"></a> <span class="cf">return</span> g_strdup_printf<span class="op">(</span><span class="st">"Untitled"</span><span class="op">);</span></span> <span id="cb23-25"><a href="#cb23-25"></a> <span class="cf">else</span></span> <span id="cb23-26"><a href="#cb23-26"></a> <span class="cf">return</span> g_strdup_printf <span class="op">(</span><span class="st">"Untitled</span><span class="sc">%u</span><span class="st">"</span><span class="op">,</span> c<span class="op">);</span></span> <span id="cb23-27"><a href="#cb23-27"></a><span class="op">}</span></span> <span id="cb23-28"><a href="#cb23-28"></a></span> <span id="cb23-29"><a href="#cb23-29"></a><span class="co">/* The returned object is owned by the scrolled window. */</span></span> <span id="cb23-30"><a href="#cb23-30"></a><span class="co">/* The caller won't get the ownership and mustn't release it. */</span></span> <span id="cb23-31"><a href="#cb23-31"></a><span class="dt">static</span> TfeTextView <span class="op">*</span></span> <span id="cb23-32"><a href="#cb23-32"></a>get_current_textview <span class="op">(</span>GtkNotebook <span class="op">*</span>nb<span class="op">)</span> <span class="op">{</span></span> <span id="cb23-33"><a href="#cb23-33"></a> <span class="dt">int</span> i<span class="op">;</span></span> <span id="cb23-34"><a href="#cb23-34"></a> GtkWidget <span class="op">*</span>scr<span class="op">;</span></span> <span id="cb23-35"><a href="#cb23-35"></a> GtkWidget <span class="op">*</span>tv<span class="op">;</span></span> <span id="cb23-36"><a href="#cb23-36"></a></span> <span id="cb23-37"><a href="#cb23-37"></a> i <span class="op">=</span> gtk_notebook_get_current_page <span class="op">(</span>nb<span class="op">);</span></span> <span id="cb23-38"><a href="#cb23-38"></a> scr <span class="op">=</span> gtk_notebook_get_nth_page <span class="op">(</span>nb<span class="op">,</span> i<span class="op">);</span></span> <span id="cb23-39"><a href="#cb23-39"></a> tv <span class="op">=</span> gtk_scrolled_window_get_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">));</span></span> <span id="cb23-40"><a href="#cb23-40"></a> <span class="cf">return</span> TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">);</span></span> <span id="cb23-41"><a href="#cb23-41"></a><span class="op">}</span></span> <span id="cb23-42"><a href="#cb23-42"></a></span> <span id="cb23-43"><a href="#cb23-43"></a><span class="co">/* This call back is called when a TfeTextView instance emits a "change-file" signal. */</span></span> <span id="cb23-44"><a href="#cb23-44"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-45"><a href="#cb23-45"></a>file_changed_cb <span class="op">(</span>TfeTextView <span class="op">*</span>tv<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb23-46"><a href="#cb23-46"></a> GtkNotebook <span class="op">*</span>nb <span class="op">=</span> GTK_NOTEBOOK <span class="op">(</span>user_data<span class="op">);</span></span> <span id="cb23-47"><a href="#cb23-47"></a> GtkWidget <span class="op">*</span>scr<span class="op">;</span></span> <span id="cb23-48"><a href="#cb23-48"></a> GtkWidget <span class="op">*</span>label<span class="op">;</span></span> <span id="cb23-49"><a href="#cb23-49"></a> GFile <span class="op">*</span>file<span class="op">;</span></span> <span id="cb23-50"><a href="#cb23-50"></a> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">;</span></span> <span id="cb23-51"><a href="#cb23-51"></a></span> <span id="cb23-52"><a href="#cb23-52"></a> file <span class="op">=</span> tfe_text_view_get_file <span class="op">(</span>tv<span class="op">);</span></span> <span id="cb23-53"><a href="#cb23-53"></a> scr <span class="op">=</span> gtk_widget_get_parent <span class="op">(</span>GTK_WIDGET <span class="op">(</span>tv<span class="op">));</span></span> <span id="cb23-54"><a href="#cb23-54"></a> <span class="cf">if</span> <span class="op">(</span>G_IS_FILE <span class="op">(</span>file<span class="op">))</span> <span class="op">{</span></span> <span id="cb23-55"><a href="#cb23-55"></a> filename <span class="op">=</span> g_file_get_basename <span class="op">(</span>file<span class="op">);</span></span> <span id="cb23-56"><a href="#cb23-56"></a> g_object_unref <span class="op">(</span>file<span class="op">);</span></span> <span id="cb23-57"><a href="#cb23-57"></a> <span class="op">}</span> <span class="cf">else</span></span> <span id="cb23-58"><a href="#cb23-58"></a> filename <span class="op">=</span> get_untitled <span class="op">();</span></span> <span id="cb23-59"><a href="#cb23-59"></a> label <span class="op">=</span> gtk_label_new <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb23-60"><a href="#cb23-60"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb23-61"><a href="#cb23-61"></a> gtk_notebook_set_tab_label <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">),</span> scr<span class="op">,</span> label<span class="op">);</span></span> <span id="cb23-62"><a href="#cb23-62"></a><span class="op">}</span></span> <span id="cb23-63"><a href="#cb23-63"></a></span> <span id="cb23-64"><a href="#cb23-64"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-65"><a href="#cb23-65"></a>modified_changed_cb <span class="op">(</span>GtkTextBuffer <span class="op">*</span>tb<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb23-66"><a href="#cb23-66"></a> TfeTextView <span class="op">*</span>tv <span class="op">=</span> TFE_TEXT_VIEW <span class="op">(</span>user_data<span class="op">);</span></span> <span id="cb23-67"><a href="#cb23-67"></a> GtkWidget <span class="op">*</span>scr <span class="op">=</span> gtk_widget_get_parent <span class="op">(</span>GTK_WIDGET <span class="op">(</span>tv<span class="op">));</span></span> <span id="cb23-68"><a href="#cb23-68"></a> GtkWidget <span class="op">*</span>nb <span class="op">=</span> gtk_widget_get_ancestor <span class="op">(</span>GTK_WIDGET <span class="op">(</span>tv<span class="op">),</span> GTK_TYPE_NOTEBOOK<span class="op">);</span></span> <span id="cb23-69"><a href="#cb23-69"></a> GtkWidget <span class="op">*</span>label<span class="op">;</span></span> <span id="cb23-70"><a href="#cb23-70"></a> GFile <span class="op">*</span>file<span class="op">;</span></span> <span id="cb23-71"><a href="#cb23-71"></a> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">;</span></span> <span id="cb23-72"><a href="#cb23-72"></a> <span class="dt">char</span> <span class="op">*</span>text<span class="op">;</span></span> <span id="cb23-73"><a href="#cb23-73"></a></span> <span id="cb23-74"><a href="#cb23-74"></a> file <span class="op">=</span> tfe_text_view_get_file <span class="op">(</span>tv<span class="op">);</span></span> <span id="cb23-75"><a href="#cb23-75"></a> filename <span class="op">=</span> g_file_get_basename <span class="op">(</span>file<span class="op">);</span></span> <span id="cb23-76"><a href="#cb23-76"></a> <span class="cf">if</span> <span class="op">(</span>gtk_text_buffer_get_modified <span class="op">(</span>tb<span class="op">))</span></span> <span id="cb23-77"><a href="#cb23-77"></a> text <span class="op">=</span> g_strdup_printf <span class="op">(</span><span class="st">"*</span><span class="sc">%s</span><span class="st">"</span><span class="op">,</span> filename<span class="op">);</span></span> <span id="cb23-78"><a href="#cb23-78"></a> <span class="cf">else</span></span> <span id="cb23-79"><a href="#cb23-79"></a> text <span class="op">=</span> g_strdup <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb23-80"><a href="#cb23-80"></a> g_object_unref <span class="op">(</span>file<span class="op">);</span></span> <span id="cb23-81"><a href="#cb23-81"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb23-82"><a href="#cb23-82"></a> label <span class="op">=</span> gtk_label_new <span class="op">(</span>text<span class="op">);</span></span> <span id="cb23-83"><a href="#cb23-83"></a> g_free <span class="op">(</span>text<span class="op">);</span></span> <span id="cb23-84"><a href="#cb23-84"></a> gtk_notebook_set_tab_label <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">),</span> scr<span class="op">,</span> label<span class="op">);</span></span> <span id="cb23-85"><a href="#cb23-85"></a><span class="op">}</span></span> <span id="cb23-86"><a href="#cb23-86"></a></span> <span id="cb23-87"><a href="#cb23-87"></a><span class="dt">static</span> gboolean</span> <span id="cb23-88"><a href="#cb23-88"></a>is_saved_all <span class="op">(</span>GtkNotebook <span class="op">*</span>nb<span class="op">)</span> <span class="op">{</span></span> <span id="cb23-89"><a href="#cb23-89"></a> <span class="dt">int</span> i<span class="op">,</span> n<span class="op">;</span></span> <span id="cb23-90"><a href="#cb23-90"></a> GtkWidget <span class="op">*</span>scr<span class="op">;</span></span> <span id="cb23-91"><a href="#cb23-91"></a> GtkWidget <span class="op">*</span>tv<span class="op">;</span></span> <span id="cb23-92"><a href="#cb23-92"></a> GtkTextBuffer <span class="op">*</span>tb<span class="op">;</span></span> <span id="cb23-93"><a href="#cb23-93"></a></span> <span id="cb23-94"><a href="#cb23-94"></a> n <span class="op">=</span> gtk_notebook_get_n_pages <span class="op">(</span>nb<span class="op">);</span></span> <span id="cb23-95"><a href="#cb23-95"></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<span class="op">;</span> <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span> <span id="cb23-96"><a href="#cb23-96"></a> scr <span class="op">=</span> gtk_notebook_get_nth_page <span class="op">(</span>nb<span class="op">,</span> i<span class="op">);</span></span> <span id="cb23-97"><a href="#cb23-97"></a> tv <span class="op">=</span> gtk_scrolled_window_get_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">));</span></span> <span id="cb23-98"><a href="#cb23-98"></a> tb <span class="op">=</span> gtk_text_view_get_buffer <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span> <span id="cb23-99"><a href="#cb23-99"></a> <span class="cf">if</span> <span class="op">(</span>gtk_text_buffer_get_modified <span class="op">(</span>tb<span class="op">))</span></span> <span id="cb23-100"><a href="#cb23-100"></a> <span class="cf">return</span> FALSE<span class="op">;</span></span> <span id="cb23-101"><a href="#cb23-101"></a> <span class="op">}</span></span> <span id="cb23-102"><a href="#cb23-102"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span> <span id="cb23-103"><a href="#cb23-103"></a><span class="op">}</span></span> <span id="cb23-104"><a href="#cb23-104"></a></span> <span id="cb23-105"><a href="#cb23-105"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-106"><a href="#cb23-106"></a>notebook_page_close <span class="op">(</span>TfeWindow <span class="op">*</span>win<span class="op">){</span></span> <span id="cb23-107"><a href="#cb23-107"></a> <span class="dt">int</span> i<span class="op">;</span></span> <span id="cb23-108"><a href="#cb23-108"></a></span> <span id="cb23-109"><a href="#cb23-109"></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">1</span><span class="op">)</span></span> <span id="cb23-110"><a href="#cb23-110"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span> <span id="cb23-111"><a href="#cb23-111"></a> <span class="cf">else</span> <span class="op">{</span></span> <span id="cb23-112"><a href="#cb23-112"></a> i <span class="op">=</span> gtk_notebook_get_current_page <span class="op">(</span>win<span class="op">-></span>nb<span class="op">);</span></span> <span id="cb23-113"><a href="#cb23-113"></a> gtk_notebook_remove_page <span class="op">(</span>win<span class="op">-></span>nb<span class="op">,</span> i<span class="op">);</span></span> <span id="cb23-114"><a href="#cb23-114"></a> <span class="op">}</span></span> <span id="cb23-115"><a href="#cb23-115"></a><span class="op">}</span></span> <span id="cb23-116"><a href="#cb23-116"></a></span> <span id="cb23-117"><a href="#cb23-117"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-118"><a href="#cb23-118"></a>notebook_page_build <span class="op">(</span>TfeWindow <span class="op">*</span>win<span class="op">,</span> GtkWidget <span class="op">*</span>tv<span class="op">,</span> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">)</span> <span class="op">{</span></span> <span id="cb23-119"><a href="#cb23-119"></a> <span class="co">// The arguments win, tb and filename are owned by the caller.</span></span> <span id="cb23-120"><a href="#cb23-120"></a> <span class="co">// If tv has a floating reference, it is consumed by the function.</span></span> <span id="cb23-121"><a href="#cb23-121"></a> GtkWidget <span class="op">*</span>scr <span class="op">=</span> gtk_scrolled_window_new <span class="op">();</span></span> <span id="cb23-122"><a href="#cb23-122"></a> GtkTextBuffer <span class="op">*</span>tb <span class="op">=</span> gtk_text_view_get_buffer <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span> <span id="cb23-123"><a href="#cb23-123"></a> GtkNotebookPage <span class="op">*</span>nbp<span class="op">;</span></span> <span id="cb23-124"><a href="#cb23-124"></a> GtkWidget <span class="op">*</span>lab<span class="op">;</span></span> <span id="cb23-125"><a href="#cb23-125"></a> <span class="dt">int</span> i<span class="op">;</span></span> <span id="cb23-126"><a href="#cb23-126"></a></span> <span id="cb23-127"><a href="#cb23-127"></a> gtk_text_view_set_wrap_mode <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> GTK_WRAP_WORD_CHAR<span class="op">);</span></span> <span id="cb23-128"><a href="#cb23-128"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> tv<span class="op">);</span></span> <span id="cb23-129"><a href="#cb23-129"></a> lab <span class="op">=</span> gtk_label_new <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb23-130"><a href="#cb23-130"></a> i <span class="op">=</span> gtk_notebook_append_page <span class="op">(</span>win<span class="op">-></span>nb<span class="op">,</span> scr<span class="op">,</span> lab<span class="op">);</span></span> <span id="cb23-131"><a href="#cb23-131"></a> nbp <span class="op">=</span> gtk_notebook_get_page <span class="op">(</span>win<span class="op">-></span>nb<span class="op">,</span> scr<span class="op">);</span></span> <span id="cb23-132"><a href="#cb23-132"></a> g_object_set <span class="op">(</span>nbp<span class="op">,</span> <span class="st">"tab-expand"</span><span class="op">,</span> TRUE<span class="op">,</span> NULL<span class="op">);</span></span> <span id="cb23-133"><a href="#cb23-133"></a> gtk_notebook_set_current_page <span class="op">(</span>win<span class="op">-></span>nb<span class="op">,</span> i<span class="op">);</span></span> <span id="cb23-134"><a href="#cb23-134"></a> g_signal_connect <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> <span class="st">"change-file"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>file_changed_cb<span class="op">),</span> win<span class="op">-></span>nb<span class="op">);</span></span> <span id="cb23-135"><a href="#cb23-135"></a> g_signal_connect <span class="op">(</span>tb<span class="op">,</span> <span class="st">"modified-changed"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>modified_changed_cb<span class="op">),</span> tv<span class="op">);</span></span> <span id="cb23-136"><a href="#cb23-136"></a><span class="op">}</span></span> <span id="cb23-137"><a href="#cb23-137"></a></span> <span id="cb23-138"><a href="#cb23-138"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-139"><a href="#cb23-139"></a>open_response_cb <span class="op">(</span>TfeTextView <span class="op">*</span>tv<span class="op">,</span> <span class="dt">int</span> response<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span> <span id="cb23-140"><a href="#cb23-140"></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="cb23-141"><a href="#cb23-141"></a> GFile <span class="op">*</span>file<span class="op">;</span></span> <span id="cb23-142"><a href="#cb23-142"></a> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">;</span></span> <span id="cb23-143"><a href="#cb23-143"></a></span> <span id="cb23-144"><a href="#cb23-144"></a> <span class="cf">if</span> <span class="op">(</span>response <span class="op">!=</span> TFE_OPEN_RESPONSE_SUCCESS<span class="op">)</span> <span class="op">{</span></span> <span id="cb23-145"><a href="#cb23-145"></a> g_object_ref_sink <span class="op">(</span>tv<span class="op">);</span></span> <span id="cb23-146"><a href="#cb23-146"></a> g_object_unref <span class="op">(</span>tv<span class="op">);</span></span> <span id="cb23-147"><a href="#cb23-147"></a> <span class="op">}</span><span class="cf">else</span> <span class="cf">if</span> <span class="op">(!</span> G_IS_FILE <span class="op">(</span>file <span class="op">=</span> tfe_text_view_get_file <span class="op">(</span>tv<span class="op">)))</span> <span class="op">{</span></span> <span id="cb23-148"><a href="#cb23-148"></a> g_object_ref_sink <span class="op">(</span>tv<span class="op">);</span></span> <span id="cb23-149"><a href="#cb23-149"></a> g_object_unref <span class="op">(</span>tv<span class="op">);</span></span> <span id="cb23-150"><a href="#cb23-150"></a> <span class="op">}</span><span class="cf">else</span> <span class="op">{</span></span> <span id="cb23-151"><a href="#cb23-151"></a> filename <span class="op">=</span> g_file_get_basename <span class="op">(</span>file<span class="op">);</span></span> <span id="cb23-152"><a href="#cb23-152"></a> g_object_unref <span class="op">(</span>file<span class="op">);</span></span> <span id="cb23-153"><a href="#cb23-153"></a> notebook_page_build <span class="op">(</span>win<span class="op">,</span> GTK_WIDGET <span class="op">(</span>tv<span class="op">),</span> filename<span class="op">);</span></span> <span id="cb23-154"><a href="#cb23-154"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb23-155"><a href="#cb23-155"></a> <span class="op">}</span></span> <span id="cb23-156"><a href="#cb23-156"></a><span class="op">}</span></span> <span id="cb23-157"><a href="#cb23-157"></a></span> <span id="cb23-158"><a href="#cb23-158"></a><span class="co">/* alert response signal handler */</span></span> <span id="cb23-159"><a href="#cb23-159"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-160"><a href="#cb23-160"></a>alert_response_cb <span class="op">(</span>TfeAlert <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="cb23-161"><a href="#cb23-161"></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="cb23-162"><a href="#cb23-162"></a></span> <span id="cb23-163"><a href="#cb23-163"></a> <span class="cf">if</span> <span class="op">(</span>response_id <span class="op">==</span> TFE_ALERT_RESPONSE_ACCEPT<span class="op">)</span> <span class="op">{</span></span> <span id="cb23-164"><a href="#cb23-164"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>is_quit<span class="op">)</span></span> <span id="cb23-165"><a href="#cb23-165"></a> gtk_window_destroy<span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span> <span id="cb23-166"><a href="#cb23-166"></a> <span class="cf">else</span></span> <span id="cb23-167"><a href="#cb23-167"></a> notebook_page_close <span class="op">(</span>win<span class="op">);</span></span> <span id="cb23-168"><a href="#cb23-168"></a> <span class="op">}</span></span> <span id="cb23-169"><a href="#cb23-169"></a><span class="op">}</span></span> <span id="cb23-170"><a href="#cb23-170"></a></span> <span id="cb23-171"><a href="#cb23-171"></a><span class="co">/* ----- Close request on the top window ----- */</span></span> <span id="cb23-172"><a href="#cb23-172"></a><span class="co">/* ----- The signal is emitted when the close button is clicked. ----- */</span></span> <span id="cb23-173"><a href="#cb23-173"></a><span class="dt">static</span> gboolean</span> <span id="cb23-174"><a href="#cb23-174"></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="cb23-175"><a href="#cb23-175"></a> TfeAlert <span class="op">*</span>alert<span class="op">;</span></span> <span id="cb23-176"><a href="#cb23-176"></a></span> <span id="cb23-177"><a href="#cb23-177"></a> <span class="cf">if</span> <span class="op">(</span>is_saved_all <span class="op">(</span>win<span class="op">-></span>nb<span class="op">))</span></span> <span id="cb23-178"><a href="#cb23-178"></a> <span class="cf">return</span> FALSE<span class="op">;</span></span> <span id="cb23-179"><a href="#cb23-179"></a> <span class="cf">else</span> <span class="op">{</span></span> <span id="cb23-180"><a href="#cb23-180"></a> win<span class="op">-></span>is_quit <span class="op">=</span> TRUE<span class="op">;</span></span> <span id="cb23-181"><a href="#cb23-181"></a> alert <span class="op">=</span> TFE_ALERT <span class="op">(</span>tfe_alert_new_with_data <span class="op">(</span><span class="st">"Are you sure?"</span><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 class="st">"Quit"</span><span class="op">));</span></span> <span id="cb23-182"><a href="#cb23-182"></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="cb23-183"><a href="#cb23-183"></a> g_signal_connect <span class="op">(</span>TFE_ALERT <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="cb23-184"><a href="#cb23-184"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>alert<span class="op">));</span></span> <span id="cb23-185"><a href="#cb23-185"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span> <span id="cb23-186"><a href="#cb23-186"></a> <span class="op">}</span></span> <span id="cb23-187"><a href="#cb23-187"></a><span class="op">}</span></span> <span id="cb23-188"><a href="#cb23-188"></a></span> <span id="cb23-189"><a href="#cb23-189"></a><span class="co">/* ----- action activated handlers ----- */</span></span> <span id="cb23-190"><a href="#cb23-190"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-191"><a href="#cb23-191"></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="cb23-192"><a href="#cb23-192"></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="cb23-193"><a href="#cb23-193"></a> GtkWidget <span class="op">*</span>tv <span class="op">=</span> tfe_text_view_new <span class="op">();</span></span> <span id="cb23-194"><a href="#cb23-194"></a></span> <span id="cb23-195"><a href="#cb23-195"></a> g_signal_connect <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> <span class="st">"open-response"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>open_response_cb<span class="op">),</span> win<span class="op">);</span></span> <span id="cb23-196"><a href="#cb23-196"></a> tfe_text_view_open <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span> <span id="cb23-197"><a href="#cb23-197"></a><span class="op">}</span></span> <span id="cb23-198"><a href="#cb23-198"></a></span> <span id="cb23-199"><a href="#cb23-199"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-200"><a href="#cb23-200"></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="cb23-201"><a href="#cb23-201"></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="cb23-202"><a href="#cb23-202"></a> TfeTextView <span class="op">*</span>tv <span class="op">=</span> get_current_textview <span class="op">(</span>win<span class="op">-></span>nb<span class="op">);</span></span> <span id="cb23-203"><a href="#cb23-203"></a></span> <span id="cb23-204"><a href="#cb23-204"></a> tfe_text_view_save <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span> <span id="cb23-205"><a href="#cb23-205"></a><span class="op">}</span></span> <span id="cb23-206"><a href="#cb23-206"></a></span> <span id="cb23-207"><a href="#cb23-207"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-208"><a href="#cb23-208"></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="cb23-209"><a href="#cb23-209"></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="cb23-210"><a href="#cb23-210"></a> TfeTextView <span class="op">*</span>tv<span class="op">;</span></span> <span id="cb23-211"><a href="#cb23-211"></a> GtkTextBuffer <span class="op">*</span>tb<span class="op">;</span></span> <span id="cb23-212"><a href="#cb23-212"></a> GtkWidget <span class="op">*</span>alert<span class="op">;</span></span> <span id="cb23-213"><a href="#cb23-213"></a></span> <span id="cb23-214"><a href="#cb23-214"></a> tv <span class="op">=</span> get_current_textview <span class="op">(</span>win<span class="op">-></span>nb<span class="op">);</span></span> <span id="cb23-215"><a href="#cb23-215"></a> tb <span class="op">=</span> gtk_text_view_get_buffer <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span> <span id="cb23-216"><a href="#cb23-216"></a> <span class="cf">if</span> <span class="op">(!</span> gtk_text_buffer_get_modified <span class="op">(</span>tb<span class="op">))</span> <span class="co">/* is saved? */</span></span> <span id="cb23-217"><a href="#cb23-217"></a> notebook_page_close <span class="op">(</span>win<span class="op">);</span></span> <span id="cb23-218"><a href="#cb23-218"></a> <span class="cf">else</span> <span class="op">{</span></span> <span id="cb23-219"><a href="#cb23-219"></a> win<span class="op">-></span>is_quit <span class="op">=</span> FALSE<span class="op">;</span></span> <span id="cb23-220"><a href="#cb23-220"></a> alert <span class="op">=</span> tfe_alert_new_with_data <span class="op">(</span><span class="st">"Are you sure?"</span><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 class="st">"Close"</span><span class="op">);</span></span> <span id="cb23-221"><a href="#cb23-221"></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="cb23-222"><a href="#cb23-222"></a> g_signal_connect <span class="op">(</span>TFE_ALERT <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="cb23-223"><a href="#cb23-223"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>alert<span class="op">));</span></span> <span id="cb23-224"><a href="#cb23-224"></a> <span class="op">}</span></span> <span id="cb23-225"><a href="#cb23-225"></a><span class="op">}</span></span> <span id="cb23-226"><a href="#cb23-226"></a></span> <span id="cb23-227"><a href="#cb23-227"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-228"><a href="#cb23-228"></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="cb23-229"><a href="#cb23-229"></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="cb23-230"><a href="#cb23-230"></a></span> <span id="cb23-231"><a href="#cb23-231"></a> tfe_window_notebook_page_new <span class="op">(</span>win<span class="op">);</span></span> <span id="cb23-232"><a href="#cb23-232"></a><span class="op">}</span></span> <span id="cb23-233"><a href="#cb23-233"></a></span> <span id="cb23-234"><a href="#cb23-234"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-235"><a href="#cb23-235"></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="cb23-236"><a href="#cb23-236"></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="cb23-237"><a href="#cb23-237"></a> TfeTextView <span class="op">*</span>tv <span class="op">=</span> get_current_textview <span class="op">(</span>win<span class="op">-></span>nb<span class="op">);</span></span> <span id="cb23-238"><a href="#cb23-238"></a></span> <span id="cb23-239"><a href="#cb23-239"></a> tfe_text_view_saveas <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span> <span id="cb23-240"><a href="#cb23-240"></a><span class="op">}</span></span> <span id="cb23-241"><a href="#cb23-241"></a></span> <span id="cb23-242"><a href="#cb23-242"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-243"><a href="#cb23-243"></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="cb23-244"><a href="#cb23-244"></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="cb23-245"><a href="#cb23-245"></a> GtkWidget <span class="op">*</span>pref<span class="op">;</span></span> <span id="cb23-246"><a href="#cb23-246"></a></span> <span id="cb23-247"><a href="#cb23-247"></a> pref <span class="op">=</span> tfe_pref_new <span class="op">();</span></span> <span id="cb23-248"><a href="#cb23-248"></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="cb23-249"><a href="#cb23-249"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>pref<span class="op">));</span></span> <span id="cb23-250"><a href="#cb23-250"></a><span class="op">}</span></span> <span id="cb23-251"><a href="#cb23-251"></a></span> <span id="cb23-252"><a href="#cb23-252"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-253"><a href="#cb23-253"></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="cb23-254"><a href="#cb23-254"></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="cb23-255"><a href="#cb23-255"></a></span> <span id="cb23-256"><a href="#cb23-256"></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="cb23-257"><a href="#cb23-257"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span> <span id="cb23-258"><a href="#cb23-258"></a><span class="op">}</span></span> <span id="cb23-259"><a href="#cb23-259"></a></span> <span id="cb23-260"><a href="#cb23-260"></a><span class="co">/* --- public functions --- */</span></span> <span id="cb23-261"><a href="#cb23-261"></a></span> <span id="cb23-262"><a href="#cb23-262"></a><span class="dt">void</span></span> <span id="cb23-263"><a href="#cb23-263"></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="cb23-264"><a href="#cb23-264"></a> GtkWidget <span class="op">*</span>tv<span class="op">;</span></span> <span id="cb23-265"><a href="#cb23-265"></a> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">;</span></span> <span id="cb23-266"><a href="#cb23-266"></a></span> <span id="cb23-267"><a href="#cb23-267"></a> tv <span class="op">=</span> tfe_text_view_new <span class="op">();</span></span> <span id="cb23-268"><a href="#cb23-268"></a> filename <span class="op">=</span> get_untitled <span class="op">();</span></span> <span id="cb23-269"><a href="#cb23-269"></a> notebook_page_build <span class="op">(</span>win<span class="op">,</span> tv<span class="op">,</span> filename<span class="op">);</span></span> <span id="cb23-270"><a href="#cb23-270"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb23-271"><a href="#cb23-271"></a><span class="op">}</span></span> <span id="cb23-272"><a href="#cb23-272"></a></span> <span id="cb23-273"><a href="#cb23-273"></a><span class="dt">void</span></span> <span id="cb23-274"><a href="#cb23-274"></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="cb23-275"><a href="#cb23-275"></a> <span class="dt">int</span> i<span class="op">;</span></span> <span id="cb23-276"><a href="#cb23-276"></a> GtkWidget <span class="op">*</span>tv<span class="op">;</span></span> <span id="cb23-277"><a href="#cb23-277"></a> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">;</span></span> <span id="cb23-278"><a href="#cb23-278"></a></span> <span id="cb23-279"><a href="#cb23-279"></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="cb23-280"><a href="#cb23-280"></a> <span class="cf">if</span> <span class="op">((</span>tv <span class="op">=</span> tfe_text_view_new_with_file <span class="op">(*(</span>files<span class="op">+</span>i<span class="op">)))</span> <span class="op">!=</span> NULL<span class="op">)</span> <span class="op">{</span></span> <span id="cb23-281"><a href="#cb23-281"></a> filename <span class="op">=</span> g_file_get_basename <span class="op">(*(</span>files<span class="op">+</span>i<span class="op">));</span></span> <span id="cb23-282"><a href="#cb23-282"></a> notebook_page_build <span class="op">(</span>win<span class="op">,</span> tv<span class="op">,</span> filename<span class="op">);</span></span> <span id="cb23-283"><a href="#cb23-283"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb23-284"><a href="#cb23-284"></a> <span class="op">}</span></span> <span id="cb23-285"><a href="#cb23-285"></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="cb23-286"><a href="#cb23-286"></a> tfe_window_notebook_page_new <span class="op">(</span>win<span class="op">);</span></span> <span id="cb23-287"><a href="#cb23-287"></a><span class="op">}</span></span> <span id="cb23-288"><a href="#cb23-288"></a></span> <span id="cb23-289"><a href="#cb23-289"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-290"><a href="#cb23-290"></a>tfe_window_dispose <span class="op">(</span>GObject <span class="op">*</span>gobject<span class="op">)</span> <span class="op">{</span></span> <span id="cb23-291"><a href="#cb23-291"></a> gtk_widget_dispose_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>gobject<span class="op">),</span> TFE_TYPE_WINDOW<span class="op">);</span></span> <span id="cb23-292"><a href="#cb23-292"></a> G_OBJECT_CLASS <span class="op">(</span>tfe_window_parent_class<span class="op">)-></span>dispose <span class="op">(</span>gobject<span class="op">);</span></span> <span id="cb23-293"><a href="#cb23-293"></a><span class="op">}</span></span> <span id="cb23-294"><a href="#cb23-294"></a></span> <span id="cb23-295"><a href="#cb23-295"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-296"><a href="#cb23-296"></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="cb23-297"><a href="#cb23-297"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span> <span id="cb23-298"><a href="#cb23-298"></a> GMenuModel <span class="op">*</span>menu<span class="op">;</span></span> <span id="cb23-299"><a href="#cb23-299"></a></span> <span id="cb23-300"><a href="#cb23-300"></a> gtk_widget_init_template <span class="op">(</span>GTK_WIDGET <span class="op">(</span>win<span class="op">));</span></span> <span id="cb23-301"><a href="#cb23-301"></a></span> <span id="cb23-302"><a href="#cb23-302"></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="cb23-303"><a href="#cb23-303"></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="cb23-304"><a href="#cb23-304"></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="cb23-305"><a href="#cb23-305"></a> g_object_unref<span class="op">(</span>build<span class="op">);</span></span> <span id="cb23-306"><a href="#cb23-306"></a></span> <span id="cb23-307"><a href="#cb23-307"></a><span class="co">/* ----- action ----- */</span></span> <span id="cb23-308"><a href="#cb23-308"></a> <span class="dt">const</span> GActionEntry win_entries<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span></span> <span id="cb23-309"><a href="#cb23-309"></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="cb23-310"><a href="#cb23-310"></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="cb23-311"><a href="#cb23-311"></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="cb23-312"><a href="#cb23-312"></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="cb23-313"><a href="#cb23-313"></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="cb23-314"><a href="#cb23-314"></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="cb23-315"><a href="#cb23-315"></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="cb23-316"><a href="#cb23-316"></a> <span class="op">};</span></span> <span id="cb23-317"><a href="#cb23-317"></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="cb23-318"><a href="#cb23-318"></a></span> <span id="cb23-319"><a href="#cb23-319"></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="cb23-320"><a href="#cb23-320"></a><span class="op">}</span></span> <span id="cb23-321"><a href="#cb23-321"></a></span> <span id="cb23-322"><a href="#cb23-322"></a><span class="dt">static</span> <span class="dt">void</span></span> <span id="cb23-323"><a href="#cb23-323"></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="cb23-324"><a href="#cb23-324"></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="cb23-325"><a href="#cb23-325"></a></span> <span id="cb23-326"><a href="#cb23-326"></a> object_class<span class="op">-></span>dispose <span class="op">=</span> tfe_window_dispose<span class="op">;</span></span> <span id="cb23-327"><a href="#cb23-327"></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="cb23-328"><a href="#cb23-328"></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="cb23-329"><a href="#cb23-329"></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="cb23-330"><a href="#cb23-330"></a><span class="op">}</span></span> <span id="cb23-331"><a href="#cb23-331"></a></span> <span id="cb23-332"><a href="#cb23-332"></a>GtkWidget <span class="op">*</span></span> <span id="cb23-333"><a href="#cb23-333"></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="cb23-334"><a href="#cb23-334"></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="cb23-335"><a href="#cb23-335"></a><span class="op">}</span></span></code></pre></div> </div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> </body> </html>