Gtk4-tutorial/docs/sec24.html
2022-04-24 12:13:40 +09:00

403 lines
40 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

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

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<title>Gtk4 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="sec23.html">Prev: section23</a>
</li>
<li class="nav-item">
<a class="nav-link" href="sec25.html">Next: section25</a>
</li>
</ul>
</div>
</div>
</nav>
<h1 id="combine-gtkdrawingarea-and-tfetextview">Combine GtkDrawingArea and TfeTextView</h1>
<p>Now, we will make a new application which has GtkDrawingArea and TfeTextView in it. Its name is “color”. If you write a name of a color in TfeTextView and click on the <code>run</code> button, then the color of GtkDrawingArea changes to the color given by you.</p>
<figure>
<img src="image/color.png" alt="" /><figcaption>color</figcaption>
</figure>
<p>The following colors are available.</p>
<ul>
<li>white</li>
<li>black</li>
<li>red</li>
<li>green</li>
<li>blue</li>
</ul>
<p>In addition the following two options are also available.</p>
<ul>
<li>light: Make the color of the drawing area lighter.</li>
<li>dark: Make the color of the drawing area darker.</li>
</ul>
<p>This application can only do very simple things. However, it tells us that if we add powerful parser to it, we will be able to make it more efficient. I want to show it to you in the later section by making a turtle graphics language like Logo program language.</p>
<p>In this section, we focus on how to bind the two objects.</p>
<h2 id="color.ui-and-color.gresource.xml">Color.ui and color.gresource.xml</h2>
<p>First, We need to make the ui file of the widgets. The image in the previous subsection gives us the structure of the widgets. Title bar, four buttons in the tool bar and two widgets textview and drawing area. The ui file is as follows.</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="kw">&lt;?xml</span> version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;<span class="kw">?&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="kw">&lt;interface&gt;</span></span>
<span id="cb1-3"><a href="#cb1-3"></a> <span class="kw">&lt;object</span><span class="ot"> class=</span><span class="st">&quot;GtkApplicationWindow&quot;</span><span class="ot"> id=</span><span class="st">&quot;win&quot;</span><span class="kw">&gt;</span></span>
<span id="cb1-4"><a href="#cb1-4"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;title&quot;</span><span class="kw">&gt;</span>color changer<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-5"><a href="#cb1-5"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;default-width&quot;</span><span class="kw">&gt;</span>600<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-6"><a href="#cb1-6"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;default-height&quot;</span><span class="kw">&gt;</span>400<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-7"><a href="#cb1-7"></a> <span class="kw">&lt;child&gt;</span></span>
<span id="cb1-8"><a href="#cb1-8"></a> <span class="kw">&lt;object</span><span class="ot"> class=</span><span class="st">&quot;GtkBox&quot;</span><span class="ot"> id=</span><span class="st">&quot;boxv&quot;</span><span class="kw">&gt;</span></span>
<span id="cb1-9"><a href="#cb1-9"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;orientation&quot;</span><span class="kw">&gt;</span>GTK_ORIENTATION_VERTICAL<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-10"><a href="#cb1-10"></a> <span class="kw">&lt;child&gt;</span></span>
<span id="cb1-11"><a href="#cb1-11"></a> <span class="kw">&lt;object</span><span class="ot"> class=</span><span class="st">&quot;GtkBox&quot;</span><span class="ot"> id=</span><span class="st">&quot;boxh1&quot;</span><span class="kw">&gt;</span></span>
<span id="cb1-12"><a href="#cb1-12"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;orientation&quot;</span><span class="kw">&gt;</span>GTK_ORIENTATION_HORIZONTAL<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-13"><a href="#cb1-13"></a> <span class="kw">&lt;child&gt;</span></span>
<span id="cb1-14"><a href="#cb1-14"></a> <span class="kw">&lt;object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span><span class="ot"> id=</span><span class="st">&quot;dmy1&quot;</span><span class="kw">&gt;</span></span>
<span id="cb1-15"><a href="#cb1-15"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;width-chars&quot;</span><span class="kw">&gt;</span>10<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-16"><a href="#cb1-16"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb1-17"><a href="#cb1-17"></a> <span class="kw">&lt;/child&gt;</span></span>
<span id="cb1-18"><a href="#cb1-18"></a> <span class="kw">&lt;child&gt;</span></span>
<span id="cb1-19"><a href="#cb1-19"></a> <span class="kw">&lt;object</span><span class="ot"> class=</span><span class="st">&quot;GtkButton&quot;</span><span class="ot"> id=</span><span class="st">&quot;btnr&quot;</span><span class="kw">&gt;</span></span>
<span id="cb1-20"><a href="#cb1-20"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span><span class="kw">&gt;</span>Run<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-21"><a href="#cb1-21"></a> <span class="kw">&lt;signal</span><span class="ot"> name=</span><span class="st">&quot;clicked&quot;</span><span class="ot"> handler=</span><span class="st">&quot;run_cb&quot;</span><span class="kw">&gt;&lt;/signal&gt;</span></span>
<span id="cb1-22"><a href="#cb1-22"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb1-23"><a href="#cb1-23"></a> <span class="kw">&lt;/child&gt;</span></span>
<span id="cb1-24"><a href="#cb1-24"></a> <span class="kw">&lt;child&gt;</span></span>
<span id="cb1-25"><a href="#cb1-25"></a> <span class="kw">&lt;object</span><span class="ot"> class=</span><span class="st">&quot;GtkButton&quot;</span><span class="ot"> id=</span><span class="st">&quot;btno&quot;</span><span class="kw">&gt;</span></span>
<span id="cb1-26"><a href="#cb1-26"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span><span class="kw">&gt;</span>Open<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-27"><a href="#cb1-27"></a> <span class="kw">&lt;signal</span><span class="ot"> name=</span><span class="st">&quot;clicked&quot;</span><span class="ot"> handler=</span><span class="st">&quot;open_cb&quot;</span><span class="kw">&gt;&lt;/signal&gt;</span></span>
<span id="cb1-28"><a href="#cb1-28"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb1-29"><a href="#cb1-29"></a> <span class="kw">&lt;/child&gt;</span></span>
<span id="cb1-30"><a href="#cb1-30"></a> <span class="kw">&lt;child&gt;</span></span>
<span id="cb1-31"><a href="#cb1-31"></a> <span class="kw">&lt;object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span><span class="ot"> id=</span><span class="st">&quot;dmy2&quot;</span><span class="kw">&gt;</span></span>
<span id="cb1-32"><a href="#cb1-32"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;hexpand&quot;</span><span class="kw">&gt;</span>TRUE<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-33"><a href="#cb1-33"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb1-34"><a href="#cb1-34"></a> <span class="kw">&lt;/child&gt;</span></span>
<span id="cb1-35"><a href="#cb1-35"></a> <span class="kw">&lt;child&gt;</span></span>
<span id="cb1-36"><a href="#cb1-36"></a> <span class="kw">&lt;object</span><span class="ot"> class=</span><span class="st">&quot;GtkButton&quot;</span><span class="ot"> id=</span><span class="st">&quot;btns&quot;</span><span class="kw">&gt;</span></span>
<span id="cb1-37"><a href="#cb1-37"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span><span class="kw">&gt;</span>Save<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-38"><a href="#cb1-38"></a> <span class="kw">&lt;signal</span><span class="ot"> name=</span><span class="st">&quot;clicked&quot;</span><span class="ot"> handler=</span><span class="st">&quot;save_cb&quot;</span><span class="kw">&gt;&lt;/signal&gt;</span></span>
<span id="cb1-39"><a href="#cb1-39"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb1-40"><a href="#cb1-40"></a> <span class="kw">&lt;/child&gt;</span></span>
<span id="cb1-41"><a href="#cb1-41"></a> <span class="kw">&lt;child&gt;</span></span>
<span id="cb1-42"><a href="#cb1-42"></a> <span class="kw">&lt;object</span><span class="ot"> class=</span><span class="st">&quot;GtkButton&quot;</span><span class="ot"> id=</span><span class="st">&quot;btnc&quot;</span><span class="kw">&gt;</span></span>
<span id="cb1-43"><a href="#cb1-43"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;label&quot;</span><span class="kw">&gt;</span>Close<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-44"><a href="#cb1-44"></a> <span class="kw">&lt;signal</span><span class="ot"> name=</span><span class="st">&quot;clicked&quot;</span><span class="ot"> handler=</span><span class="st">&quot;close_cb&quot;</span><span class="kw">&gt;&lt;/signal&gt;</span></span>
<span id="cb1-45"><a href="#cb1-45"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb1-46"><a href="#cb1-46"></a> <span class="kw">&lt;/child&gt;</span></span>
<span id="cb1-47"><a href="#cb1-47"></a> <span class="kw">&lt;child&gt;</span></span>
<span id="cb1-48"><a href="#cb1-48"></a> <span class="kw">&lt;object</span><span class="ot"> class=</span><span class="st">&quot;GtkLabel&quot;</span><span class="ot"> id=</span><span class="st">&quot;dmy3&quot;</span><span class="kw">&gt;</span></span>
<span id="cb1-49"><a href="#cb1-49"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;width-chars&quot;</span><span class="kw">&gt;</span>10<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-50"><a href="#cb1-50"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb1-51"><a href="#cb1-51"></a> <span class="kw">&lt;/child&gt;</span></span>
<span id="cb1-52"><a href="#cb1-52"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb1-53"><a href="#cb1-53"></a> <span class="kw">&lt;/child&gt;</span></span>
<span id="cb1-54"><a href="#cb1-54"></a> <span class="kw">&lt;child&gt;</span></span>
<span id="cb1-55"><a href="#cb1-55"></a> <span class="kw">&lt;object</span><span class="ot"> class=</span><span class="st">&quot;GtkBox&quot;</span><span class="ot"> id=</span><span class="st">&quot;boxh2&quot;</span><span class="kw">&gt;</span></span>
<span id="cb1-56"><a href="#cb1-56"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;orientation&quot;</span><span class="kw">&gt;</span>GTK_ORIENTATION_HORIZONTAL<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-57"><a href="#cb1-57"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;homogeneous&quot;</span><span class="kw">&gt;</span>TRUE<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-58"><a href="#cb1-58"></a> <span class="kw">&lt;child&gt;</span></span>
<span id="cb1-59"><a href="#cb1-59"></a> <span class="kw">&lt;object</span><span class="ot"> class=</span><span class="st">&quot;GtkScrolledWindow&quot;</span><span class="ot"> id=</span><span class="st">&quot;scr&quot;</span><span class="kw">&gt;</span></span>
<span id="cb1-60"><a href="#cb1-60"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;hexpand&quot;</span><span class="kw">&gt;</span>TRUE<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-61"><a href="#cb1-61"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;vexpand&quot;</span><span class="kw">&gt;</span>TRUE<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-62"><a href="#cb1-62"></a> <span class="kw">&lt;child&gt;</span></span>
<span id="cb1-63"><a href="#cb1-63"></a> <span class="kw">&lt;object</span><span class="ot"> class=</span><span class="st">&quot;TfeTextView&quot;</span><span class="ot"> id=</span><span class="st">&quot;tv&quot;</span><span class="kw">&gt;</span></span>
<span id="cb1-64"><a href="#cb1-64"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;wrap-mode&quot;</span><span class="kw">&gt;</span>GTK_WRAP_WORD_CHAR<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-65"><a href="#cb1-65"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb1-66"><a href="#cb1-66"></a> <span class="kw">&lt;/child&gt;</span></span>
<span id="cb1-67"><a href="#cb1-67"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb1-68"><a href="#cb1-68"></a> <span class="kw">&lt;/child&gt;</span></span>
<span id="cb1-69"><a href="#cb1-69"></a> <span class="kw">&lt;child&gt;</span></span>
<span id="cb1-70"><a href="#cb1-70"></a> <span class="kw">&lt;object</span><span class="ot"> class=</span><span class="st">&quot;GtkDrawingArea&quot;</span><span class="ot"> id=</span><span class="st">&quot;da&quot;</span><span class="kw">&gt;</span></span>
<span id="cb1-71"><a href="#cb1-71"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;hexpand&quot;</span><span class="kw">&gt;</span>TRUE<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-72"><a href="#cb1-72"></a> <span class="kw">&lt;property</span><span class="ot"> name=</span><span class="st">&quot;vexpand&quot;</span><span class="kw">&gt;</span>TRUE<span class="kw">&lt;/property&gt;</span></span>
<span id="cb1-73"><a href="#cb1-73"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb1-74"><a href="#cb1-74"></a> <span class="kw">&lt;/child&gt;</span></span>
<span id="cb1-75"><a href="#cb1-75"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb1-76"><a href="#cb1-76"></a> <span class="kw">&lt;/child&gt;</span></span>
<span id="cb1-77"><a href="#cb1-77"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb1-78"><a href="#cb1-78"></a> <span class="kw">&lt;/child&gt;</span></span>
<span id="cb1-79"><a href="#cb1-79"></a> <span class="kw">&lt;/object&gt;</span></span>
<span id="cb1-80"><a href="#cb1-80"></a><span class="kw">&lt;/interface&gt;</span></span></code></pre></div>
<ul>
<li>10-53: This part is the tool bar which has four buttons, <code>Run</code>, <code>Open</code>, <code>Save</code> and <code>Close</code>. This is similar to the toolbar of tfe text editor in <a href="sec9.html">Section 9</a>. There are two differences. <code>Run</code> button replaces <code>New</code> button. A signal element is added to each button object. It has “name” attribute which is a signal name and “handler” attribute which is the name of its signal handler function. Options “-WI, export-dynamic” CFLAG is necessary when you compile the application. You can achieve this by adding “export_dynamic: true” argument to executable function in <code>meson.build</code>. And be careful that the handler must be defined without static class.</li>
<li>54-76: Puts GtkScrolledWindow and GtkDrawingArea into GtkBox. GtkBox has “homogeneous property” with TRUE value, so the two children have the same width in the box. TfeTextView is a child of GtkScrolledWindow.</li>
</ul>
<p>The xml file for the resource compiler is almost same as before. Just substitute “color” for “tfe”.</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="kw">&lt;?xml</span> version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;<span class="kw">?&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2"></a><span class="kw">&lt;gresources&gt;</span></span>
<span id="cb2-3"><a href="#cb2-3"></a> <span class="kw">&lt;gresource</span><span class="ot"> prefix=</span><span class="st">&quot;/com/github/ToshioCP/color&quot;</span><span class="kw">&gt;</span></span>
<span id="cb2-4"><a href="#cb2-4"></a> <span class="kw">&lt;file&gt;</span>color.ui<span class="kw">&lt;/file&gt;</span></span>
<span id="cb2-5"><a href="#cb2-5"></a> <span class="kw">&lt;/gresource&gt;</span></span>
<span id="cb2-6"><a href="#cb2-6"></a><span class="kw">&lt;/gresources&gt;</span></span></code></pre></div>
<h2 id="tfetextview.h-tfetextview.c-and-color.h">Tfetextview.h, tfetextview.c and color.h</h2>
<p>First two files are the same as before. Color.h just includes tfetextview.h.</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">#include </span><span class="im">&lt;gtk/gtk.h&gt;</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">&quot;../tfetextview/tfetextview.h&quot;</span></span></code></pre></div>
<h2 id="colorapplication.c">Colorapplication.c</h2>
<p>This is the main file. It deals with:</p>
<ul>
<li>Building widgets by GtkBuilder.</li>
<li>Setting a drawing function of GtkDrawingArea. And connecting a handler to “resize” signal on GtkDrawingArea.</li>
<li>Implementing each call back functions. Particularly, <code>Run</code> signal handler is the point in this program.</li>
</ul>
<p>The following is <code>colorapplication.c</code>.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1"></a><span class="pp">#include </span><span class="im">&quot;color.h&quot;</span></span>
<span id="cb4-2"><a href="#cb4-2"></a></span>
<span id="cb4-3"><a href="#cb4-3"></a><span class="dt">static</span> GtkWidget *win;</span>
<span id="cb4-4"><a href="#cb4-4"></a><span class="dt">static</span> GtkWidget *tv;</span>
<span id="cb4-5"><a href="#cb4-5"></a><span class="dt">static</span> GtkWidget *da;</span>
<span id="cb4-6"><a href="#cb4-6"></a></span>
<span id="cb4-7"><a href="#cb4-7"></a><span class="dt">static</span> cairo_surface_t *surface = NULL;</span>
<span id="cb4-8"><a href="#cb4-8"></a></span>
<span id="cb4-9"><a href="#cb4-9"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-10"><a href="#cb4-10"></a>run (<span class="dt">void</span>) {</span>
<span id="cb4-11"><a href="#cb4-11"></a> GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));</span>
<span id="cb4-12"><a href="#cb4-12"></a> GtkTextIter start_iter;</span>
<span id="cb4-13"><a href="#cb4-13"></a> GtkTextIter end_iter;</span>
<span id="cb4-14"><a href="#cb4-14"></a> <span class="dt">char</span> *contents;</span>
<span id="cb4-15"><a href="#cb4-15"></a> cairo_t *cr;</span>
<span id="cb4-16"><a href="#cb4-16"></a></span>
<span id="cb4-17"><a href="#cb4-17"></a> gtk_text_buffer_get_bounds (tb, &amp;start_iter, &amp;end_iter);</span>
<span id="cb4-18"><a href="#cb4-18"></a> contents = gtk_text_buffer_get_text (tb, &amp;start_iter, &amp;end_iter, FALSE);</span>
<span id="cb4-19"><a href="#cb4-19"></a> <span class="cf">if</span> (surface) {</span>
<span id="cb4-20"><a href="#cb4-20"></a> cr = cairo_create (surface);</span>
<span id="cb4-21"><a href="#cb4-21"></a> <span class="cf">if</span> (g_strcmp0 (<span class="st">&quot;red&quot;</span>, contents) == <span class="dv">0</span>)</span>
<span id="cb4-22"><a href="#cb4-22"></a> cairo_set_source_rgb (cr, <span class="dv">1</span>, <span class="dv">0</span>, <span class="dv">0</span>);</span>
<span id="cb4-23"><a href="#cb4-23"></a> <span class="cf">else</span> <span class="cf">if</span> (g_strcmp0 (<span class="st">&quot;green&quot;</span>, contents) == <span class="dv">0</span>)</span>
<span id="cb4-24"><a href="#cb4-24"></a> cairo_set_source_rgb (cr, <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">0</span>);</span>
<span id="cb4-25"><a href="#cb4-25"></a> <span class="cf">else</span> <span class="cf">if</span> (g_strcmp0 (<span class="st">&quot;blue&quot;</span>, contents) == <span class="dv">0</span>)</span>
<span id="cb4-26"><a href="#cb4-26"></a> cairo_set_source_rgb (cr, <span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">1</span>);</span>
<span id="cb4-27"><a href="#cb4-27"></a> <span class="cf">else</span> <span class="cf">if</span> (g_strcmp0 (<span class="st">&quot;white&quot;</span>, contents) == <span class="dv">0</span>)</span>
<span id="cb4-28"><a href="#cb4-28"></a> cairo_set_source_rgb (cr, <span class="dv">1</span>, <span class="dv">1</span>, <span class="dv">1</span>);</span>
<span id="cb4-29"><a href="#cb4-29"></a> <span class="cf">else</span> <span class="cf">if</span> (g_strcmp0 (<span class="st">&quot;black&quot;</span>, contents) == <span class="dv">0</span>)</span>
<span id="cb4-30"><a href="#cb4-30"></a> cairo_set_source_rgb (cr, <span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">0</span>);</span>
<span id="cb4-31"><a href="#cb4-31"></a> <span class="cf">else</span> <span class="cf">if</span> (g_strcmp0 (<span class="st">&quot;light&quot;</span>, contents) == <span class="dv">0</span>)</span>
<span id="cb4-32"><a href="#cb4-32"></a> cairo_set_source_rgba (cr, <span class="dv">1</span>, <span class="dv">1</span>, <span class="dv">1</span>, <span class="fl">0.5</span>);</span>
<span id="cb4-33"><a href="#cb4-33"></a> <span class="cf">else</span> <span class="cf">if</span> (g_strcmp0 (<span class="st">&quot;dark&quot;</span>, contents) == <span class="dv">0</span>)</span>
<span id="cb4-34"><a href="#cb4-34"></a> cairo_set_source_rgba (cr, <span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">0</span>, <span class="fl">0.5</span>);</span>
<span id="cb4-35"><a href="#cb4-35"></a> <span class="cf">else</span></span>
<span id="cb4-36"><a href="#cb4-36"></a> cairo_set_source_surface (cr, surface, <span class="dv">0</span>, <span class="dv">0</span>);</span>
<span id="cb4-37"><a href="#cb4-37"></a> cairo_paint (cr);</span>
<span id="cb4-38"><a href="#cb4-38"></a> cairo_destroy (cr);</span>
<span id="cb4-39"><a href="#cb4-39"></a> }</span>
<span id="cb4-40"><a href="#cb4-40"></a> g_free (contents);</span>
<span id="cb4-41"><a href="#cb4-41"></a>}</span>
<span id="cb4-42"><a href="#cb4-42"></a></span>
<span id="cb4-43"><a href="#cb4-43"></a><span class="dt">void</span></span>
<span id="cb4-44"><a href="#cb4-44"></a>run_cb (GtkWidget *btnr) {</span>
<span id="cb4-45"><a href="#cb4-45"></a> run ();</span>
<span id="cb4-46"><a href="#cb4-46"></a> gtk_widget_queue_draw (GTK_WIDGET (da));</span>
<span id="cb4-47"><a href="#cb4-47"></a>}</span>
<span id="cb4-48"><a href="#cb4-48"></a></span>
<span id="cb4-49"><a href="#cb4-49"></a><span class="dt">void</span></span>
<span id="cb4-50"><a href="#cb4-50"></a>open_cb (GtkWidget *btno) {</span>
<span id="cb4-51"><a href="#cb4-51"></a> tfe_text_view_open (TFE_TEXT_VIEW (tv), GTK_WINDOW (win));</span>
<span id="cb4-52"><a href="#cb4-52"></a>}</span>
<span id="cb4-53"><a href="#cb4-53"></a></span>
<span id="cb4-54"><a href="#cb4-54"></a><span class="dt">void</span></span>
<span id="cb4-55"><a href="#cb4-55"></a>save_cb (GtkWidget *btns) {</span>
<span id="cb4-56"><a href="#cb4-56"></a> tfe_text_view_save (TFE_TEXT_VIEW (tv));</span>
<span id="cb4-57"><a href="#cb4-57"></a>}</span>
<span id="cb4-58"><a href="#cb4-58"></a></span>
<span id="cb4-59"><a href="#cb4-59"></a><span class="dt">void</span></span>
<span id="cb4-60"><a href="#cb4-60"></a>close_cb (GtkWidget *btnc) {</span>
<span id="cb4-61"><a href="#cb4-61"></a> <span class="cf">if</span> (surface)</span>
<span id="cb4-62"><a href="#cb4-62"></a> cairo_surface_destroy (surface);</span>
<span id="cb4-63"><a href="#cb4-63"></a> gtk_window_destroy (GTK_WINDOW (win));</span>
<span id="cb4-64"><a href="#cb4-64"></a>}</span>
<span id="cb4-65"><a href="#cb4-65"></a></span>
<span id="cb4-66"><a href="#cb4-66"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-67"><a href="#cb4-67"></a>resize_cb (GtkDrawingArea *drawing_area, <span class="dt">int</span> width, <span class="dt">int</span> height, gpointer user_data) {</span>
<span id="cb4-68"><a href="#cb4-68"></a> <span class="cf">if</span> (surface)</span>
<span id="cb4-69"><a href="#cb4-69"></a> cairo_surface_destroy (surface);</span>
<span id="cb4-70"><a href="#cb4-70"></a> surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);</span>
<span id="cb4-71"><a href="#cb4-71"></a> run ();</span>
<span id="cb4-72"><a href="#cb4-72"></a>}</span>
<span id="cb4-73"><a href="#cb4-73"></a></span>
<span id="cb4-74"><a href="#cb4-74"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-75"><a href="#cb4-75"></a>draw_func (GtkDrawingArea *drawing_area, cairo_t *cr, <span class="dt">int</span> width, <span class="dt">int</span> height, gpointer user_data) {</span>
<span id="cb4-76"><a href="#cb4-76"></a> <span class="cf">if</span> (surface) {</span>
<span id="cb4-77"><a href="#cb4-77"></a> cairo_set_source_surface (cr, surface, <span class="dv">0</span>, <span class="dv">0</span>);</span>
<span id="cb4-78"><a href="#cb4-78"></a> cairo_paint (cr);</span>
<span id="cb4-79"><a href="#cb4-79"></a> }</span>
<span id="cb4-80"><a href="#cb4-80"></a>}</span>
<span id="cb4-81"><a href="#cb4-81"></a></span>
<span id="cb4-82"><a href="#cb4-82"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-83"><a href="#cb4-83"></a>app_activate (GApplication *application) {</span>
<span id="cb4-84"><a href="#cb4-84"></a> gtk_widget_show (win);</span>
<span id="cb4-85"><a href="#cb4-85"></a>}</span>
<span id="cb4-86"><a href="#cb4-86"></a></span>
<span id="cb4-87"><a href="#cb4-87"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb4-88"><a href="#cb4-88"></a>app_startup (GApplication *application) {</span>
<span id="cb4-89"><a href="#cb4-89"></a> GtkApplication *app = GTK_APPLICATION (application);</span>
<span id="cb4-90"><a href="#cb4-90"></a> GtkBuilder *build;</span>
<span id="cb4-91"><a href="#cb4-91"></a></span>
<span id="cb4-92"><a href="#cb4-92"></a> build = gtk_builder_new_from_resource (<span class="st">&quot;/com/github/ToshioCP/color/color.ui&quot;</span>);</span>
<span id="cb4-93"><a href="#cb4-93"></a> win = GTK_WIDGET (gtk_builder_get_object (build, <span class="st">&quot;win&quot;</span>));</span>
<span id="cb4-94"><a href="#cb4-94"></a> gtk_window_set_application (GTK_WINDOW (win), app);</span>
<span id="cb4-95"><a href="#cb4-95"></a> tv = GTK_WIDGET (gtk_builder_get_object (build, <span class="st">&quot;tv&quot;</span>));</span>
<span id="cb4-96"><a href="#cb4-96"></a> da = GTK_WIDGET (gtk_builder_get_object (build, <span class="st">&quot;da&quot;</span>));</span>
<span id="cb4-97"><a href="#cb4-97"></a> g_object_unref(build);</span>
<span id="cb4-98"><a href="#cb4-98"></a> g_signal_connect (GTK_DRAWING_AREA (da), <span class="st">&quot;resize&quot;</span>, G_CALLBACK (resize_cb), NULL);</span>
<span id="cb4-99"><a href="#cb4-99"></a> gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_func, NULL, NULL);</span>
<span id="cb4-100"><a href="#cb4-100"></a></span>
<span id="cb4-101"><a href="#cb4-101"></a>GdkDisplay *display;</span>
<span id="cb4-102"><a href="#cb4-102"></a></span>
<span id="cb4-103"><a href="#cb4-103"></a> display = gtk_widget_get_display (GTK_WIDGET (win));</span>
<span id="cb4-104"><a href="#cb4-104"></a> GtkCssProvider *provider = gtk_css_provider_new ();</span>
<span id="cb4-105"><a href="#cb4-105"></a> gtk_css_provider_load_from_data (provider, <span class="st">&quot;textview {padding: 10px; font-family: monospace; font-size: 12pt;}&quot;</span>, -<span class="dv">1</span>);</span>
<span id="cb4-106"><a href="#cb4-106"></a> gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);</span>
<span id="cb4-107"><a href="#cb4-107"></a>}</span>
<span id="cb4-108"><a href="#cb4-108"></a></span>
<span id="cb4-109"><a href="#cb4-109"></a><span class="pp">#define APPLICATION_ID &quot;com.github.ToshioCP.color&quot;</span></span>
<span id="cb4-110"><a href="#cb4-110"></a></span>
<span id="cb4-111"><a href="#cb4-111"></a><span class="dt">int</span></span>
<span id="cb4-112"><a href="#cb4-112"></a>main (<span class="dt">int</span> argc, <span class="dt">char</span> **argv) {</span>
<span id="cb4-113"><a href="#cb4-113"></a> GtkApplication *app;</span>
<span id="cb4-114"><a href="#cb4-114"></a> <span class="dt">int</span> stat;</span>
<span id="cb4-115"><a href="#cb4-115"></a></span>
<span id="cb4-116"><a href="#cb4-116"></a> app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);</span>
<span id="cb4-117"><a href="#cb4-117"></a></span>
<span id="cb4-118"><a href="#cb4-118"></a> g_signal_connect (app, <span class="st">&quot;startup&quot;</span>, G_CALLBACK (app_startup), NULL);</span>
<span id="cb4-119"><a href="#cb4-119"></a> g_signal_connect (app, <span class="st">&quot;activate&quot;</span>, G_CALLBACK (app_activate), NULL);</span>
<span id="cb4-120"><a href="#cb4-120"></a></span>
<span id="cb4-121"><a href="#cb4-121"></a> stat =g_application_run (G_APPLICATION (app), argc, argv);</span>
<span id="cb4-122"><a href="#cb4-122"></a> g_object_unref (app);</span>
<span id="cb4-123"><a href="#cb4-123"></a> <span class="cf">return</span> stat;</span>
<span id="cb4-124"><a href="#cb4-124"></a>}</span></code></pre></div>
<ul>
<li>109-124: The function <code>main</code> is almost same as before but there are some differences. The application ID is “com.github.ToshioCP.color”. <code>G_APPLICATION_FLAGS_NONE</code> is specified so no open signal handler is necessary.</li>
<li>87-107: Startup handler.</li>
<li>92-97: Builds widgets. The pointers of the top window, TfeTextView and GtkDrawingArea objects are stored to static variables <code>win</code>, <code>tv</code> and <code>da</code> respectively. This is because these objects are often used in handlers. They never be rewritten so theyre thread safe.</li>
<li>98: connects “resize” signal and the handler.</li>
<li>99: sets the drawing function.</li>
<li>82-85: Activate handler, which just shows the widgets.</li>
<li>74-80: The drawing function. It just copies <code>surface</code> to destination.</li>
<li>66-72: Resize handler. Re-creates the surface to fit its width and height for the drawing area and paints by calling the function <code>run</code>.</li>
<li>59-64: Close handler. It destroys <code>surface</code> if it exists. Then it destroys the top-level window and quits the application.</li>
<li>49-57: Open and save handler. They just call the corresponding functions of TfeTextView.</li>
<li>43-47: Run handler. It calls run function to paint the surface. After that <code>gtk_widget_queue_draw</code> is called. This function adds the widget (GtkDrawingArea) to the queue to be redrawn. It is important to know that the window is redrawn whenever it is necessary. For example, when another window is moved and uncovers part of the widget, or when the window containing it is resized. But repainting <code>surface</code> is not automatically notified to gtk. Therefore, you need to call <code>gtk_widget_queue_draw</code> to redraw the widget.</li>
<li>9-41: Run function paints the surface. First, it gets the contents of GtkTextBuffer. Then it compares it to “red”, “green” and so on. If it matches the color, then the surface is painted the color. If it matches “light” or “dark”, then the color of the surface is lightened or darkened respectively. Alpha channel is used.</li>
</ul>
<h2 id="meson.build">Meson.build</h2>
<p>This file is almost same as before. An argument “export_dynamic: true” is added to executable function.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb5-1"><a href="#cb5-1"></a>project(&#39;color&#39;, &#39;c&#39;)</span>
<span id="cb5-2"><a href="#cb5-2"></a></span>
<span id="cb5-3"><a href="#cb5-3"></a>gtkdep = dependency(&#39;gtk4&#39;)</span>
<span id="cb5-4"><a href="#cb5-4"></a></span>
<span id="cb5-5"><a href="#cb5-5"></a>gnome=import(&#39;gnome&#39;)</span>
<span id="cb5-6"><a href="#cb5-6"></a>resources = gnome.compile_resources(&#39;resources&#39;,&#39;color.gresource.xml&#39;)</span>
<span id="cb5-7"><a href="#cb5-7"></a></span>
<span id="cb5-8"><a href="#cb5-8"></a>sourcefiles=files(&#39;colorapplication.c&#39;, &#39;../tfetextview/tfetextview.c&#39;)</span>
<span id="cb5-9"><a href="#cb5-9"></a></span>
<span id="cb5-10"><a href="#cb5-10"></a>executable(&#39;color&#39;, sourcefiles, resources, dependencies: gtkdep, export_dynamic: true)</span></code></pre></div>
<h2 id="compile-and-execute-it">Compile and execute it</h2>
<p>First you need to export some variables (refer to <a href="sec2.html">Section 2</a>) if youve installed Gtk4 from the source. If youve installed Gtk4 from the distribution packages, you dont need to do this.</p>
<pre><code>$ . env.sh</code></pre>
<p>Then type the following to compile it.</p>
<pre><code>$ meson _build
$ ninja -C _build</code></pre>
<p>The application is made in <code>_build</code> directory. Type the following to execute it.</p>
<pre><code>$ _build/color</code></pre>
<p>Type “red”, “green”, “blue”, “white”, black“,”light" or “dark” in the TfeTextView. Then, click on <code>Run</code> button. Make sure the color of GtkDrawingArea changes.</p>
<p>In this program TfeTextView is used to change the color. You can use buttons or menus instead of textview. Probably it is more appropriate. Using textview is unnatural. It is a good practice to make such application by yourself.</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</body>
</html>