Gtk4-tutorial/docs/sec10.html
2022-12-21 22:31:33 +09:00

485 lines
39 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

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

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<title>GTK 4 tutorial</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre{overflow: visible;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::after
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
div.sourceCode { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
pre:not(.sourceCode) { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
table {margin-left: auto; margin-right: auto; border-collapse: collapse; border: 1px solid;}
th {padding: 2px 6px; border: 1px solid; background-color: ghostwhite;}
td {padding: 2px 6px; border: 1px solid;}
img {display: block; margin-left: auto; margin-right: auto;}
figcaption {text-align: center;}
</style>
</head>
<body style="padding-top: 70px;">
<div class="container">
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
<div class="container-fluid">
<span class="navbar-brand">Gtk4 tutorial</span>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="sec9.html">Prev: section9</a>
</li>
<li class="nav-item">
<a class="nav-link" href="sec11.html">Next: section11</a>
</li>
</ul>
</div>
</div>
</nav>
<h1 id="build-system">Build system</h1>
<h2 id="managing-big-source-files">Managing big source files</h2>
<p>Weve compiled a small editor so far. But Some bad signs are
beginning to appear.</p>
<ul>
<li>Weve had only one C source file and put everything in it. We need
to sort it out.</li>
<li>There are two compilers, <code>gcc</code> and
<code>glib-compile-resources</code>. We should control them by one
building tool.</li>
</ul>
<p>These ideas are useful to manage big source files.</p>
<h2 id="divide-a-c-source-file-into-two-parts.">Divide a C source file
into two parts.</h2>
<p>When you divide C source file into several parts, each file should
contain one thing. For example, our source has two things, the
definition of TfeTextView and functions related to GtkApplication and
GtkApplicationWindow. It is a good idea to separate them into two files,
<code>tfetextview.c</code> and <code>tfe.c</code>.</p>
<ul>
<li><code>tfetextview.c</code> includes the definition and functions of
TfeTextView.</li>
<li><code>tfe.c</code> includes functions like <code>main</code>,
<code>app_activate</code>, <code>app_open</code> and so on, which relate
to GtkApplication and GtkApplicationWindow</li>
</ul>
<p>Now we have three source files, <code>tfetextview.c</code>,
<code>tfe.c</code> and <code>tfe3.ui</code>. The <code>3</code> of
<code>tfe3.ui</code> is like a version number. Managing version with
filenames is one possible idea but it may make bothersome problem. You
need to rewrite filename in each version and it affects to contents of
source files that refer to filenames. So, we should take <code>3</code>
away from the filename.</p>
<p>In <code>tfe.c</code> the function <code>tfe_text_view_new</code> is
invoked to create a TfeTextView instance. But it is defined in
<code>tfetextview.c</code>, not <code>tfe.c</code>. The lack of the
declaration (not definition) of <code>tfe_text_view_new</code> makes
error when <code>tfe.c</code> is compiled. The declaration is necessary
in <code>tfe.c</code>. Those public information is usually written in
header files. It has <code>.h</code> suffix like
<code>tfetextview.h</code> And header files are included by C source
files. For example, <code>tfetextview.h</code> is included by
<code>tfe.c</code>.</p>
<p>All the source files are listed below.</p>
<p><code>tfetextview.h</code></p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2"></a></span>
<span id="cb1-3"><a href="#cb1-3"></a><span class="pp">#define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()</span></span>
<span id="cb1-4"><a href="#cb1-4"></a>G_DECLARE_FINAL_TYPE <span class="op">(</span>TfeTextView<span class="op">,</span> tfe_text_view<span class="op">,</span> TFE<span class="op">,</span> TEXT_VIEW<span class="op">,</span> GtkTextView<span class="op">)</span></span>
<span id="cb1-5"><a href="#cb1-5"></a></span>
<span id="cb1-6"><a href="#cb1-6"></a><span class="dt">void</span></span>
<span id="cb1-7"><a href="#cb1-7"></a>tfe_text_view_set_file <span class="op">(</span>TfeTextView <span class="op">*</span>tv<span class="op">,</span> GFile <span class="op">*</span>f<span class="op">);</span></span>
<span id="cb1-8"><a href="#cb1-8"></a></span>
<span id="cb1-9"><a href="#cb1-9"></a>GFile <span class="op">*</span></span>
<span id="cb1-10"><a href="#cb1-10"></a>tfe_text_view_get_file <span class="op">(</span>TfeTextView <span class="op">*</span>tv<span class="op">);</span></span>
<span id="cb1-11"><a href="#cb1-11"></a></span>
<span id="cb1-12"><a href="#cb1-12"></a>GtkWidget <span class="op">*</span></span>
<span id="cb1-13"><a href="#cb1-13"></a>tfe_text_view_new <span class="op">(</span><span class="dt">void</span><span class="op">);</span></span></code></pre></div>
<p><code>tfetextview.c</code></p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1"></a><span class="pp">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2"></a><span class="pp">#include </span><span class="im">&quot;tfetextview.h&quot;</span></span>
<span id="cb2-3"><a href="#cb2-3"></a></span>
<span id="cb2-4"><a href="#cb2-4"></a><span class="kw">struct</span> _TfeTextView</span>
<span id="cb2-5"><a href="#cb2-5"></a><span class="op">{</span></span>
<span id="cb2-6"><a href="#cb2-6"></a> GtkTextView parent<span class="op">;</span></span>
<span id="cb2-7"><a href="#cb2-7"></a> GFile <span class="op">*</span>file<span class="op">;</span></span>
<span id="cb2-8"><a href="#cb2-8"></a><span class="op">};</span></span>
<span id="cb2-9"><a href="#cb2-9"></a></span>
<span id="cb2-10"><a href="#cb2-10"></a>G_DEFINE_TYPE <span class="op">(</span>TfeTextView<span class="op">,</span> tfe_text_view<span class="op">,</span> GTK_TYPE_TEXT_VIEW<span class="op">);</span></span>
<span id="cb2-11"><a href="#cb2-11"></a></span>
<span id="cb2-12"><a href="#cb2-12"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb2-13"><a href="#cb2-13"></a>tfe_text_view_init <span class="op">(</span>TfeTextView <span class="op">*</span>tv<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-14"><a href="#cb2-14"></a><span class="op">}</span></span>
<span id="cb2-15"><a href="#cb2-15"></a></span>
<span id="cb2-16"><a href="#cb2-16"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb2-17"><a href="#cb2-17"></a>tfe_text_view_class_init <span class="op">(</span>TfeTextViewClass <span class="op">*</span>class<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-18"><a href="#cb2-18"></a><span class="op">}</span></span>
<span id="cb2-19"><a href="#cb2-19"></a></span>
<span id="cb2-20"><a href="#cb2-20"></a><span class="dt">void</span></span>
<span id="cb2-21"><a href="#cb2-21"></a>tfe_text_view_set_file <span class="op">(</span>TfeTextView <span class="op">*</span>tv<span class="op">,</span> GFile <span class="op">*</span>f<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-22"><a href="#cb2-22"></a> tv <span class="op">-&gt;</span> file <span class="op">=</span> f<span class="op">;</span></span>
<span id="cb2-23"><a href="#cb2-23"></a><span class="op">}</span></span>
<span id="cb2-24"><a href="#cb2-24"></a></span>
<span id="cb2-25"><a href="#cb2-25"></a>GFile <span class="op">*</span></span>
<span id="cb2-26"><a href="#cb2-26"></a>tfe_text_view_get_file <span class="op">(</span>TfeTextView <span class="op">*</span>tv<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-27"><a href="#cb2-27"></a> <span class="cf">return</span> tv <span class="op">-&gt;</span> file<span class="op">;</span></span>
<span id="cb2-28"><a href="#cb2-28"></a><span class="op">}</span></span>
<span id="cb2-29"><a href="#cb2-29"></a></span>
<span id="cb2-30"><a href="#cb2-30"></a>GtkWidget <span class="op">*</span></span>
<span id="cb2-31"><a href="#cb2-31"></a>tfe_text_view_new <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-32"><a href="#cb2-32"></a> <span class="cf">return</span> GTK_WIDGET <span class="op">(</span>g_object_new <span class="op">(</span>TFE_TYPE_TEXT_VIEW<span class="op">,</span> NULL<span class="op">));</span></span>
<span id="cb2-33"><a href="#cb2-33"></a><span class="op">}</span></span></code></pre></div>
<p><code>tfe.c</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">#include </span><span class="im">&lt;gtk/gtk.h&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="pp">#include </span><span class="im">&quot;tfetextview.h&quot;</span></span>
<span id="cb3-3"><a href="#cb3-3"></a></span>
<span id="cb3-4"><a href="#cb3-4"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb3-5"><a href="#cb3-5"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-6"><a href="#cb3-6"></a> g_print <span class="op">(</span><span class="st">&quot;You need a filename argument.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span>
<span id="cb3-7"><a href="#cb3-7"></a><span class="op">}</span></span>
<span id="cb3-8"><a href="#cb3-8"></a></span>
<span id="cb3-9"><a href="#cb3-9"></a><span class="dt">static</span> <span class="dt">void</span></span>
<span id="cb3-10"><a href="#cb3-10"></a>app_open <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">,</span> GFile <span class="op">**</span> files<span class="op">,</span> gint n_files<span class="op">,</span> gchar <span class="op">*</span>hint<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-11"><a href="#cb3-11"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
<span id="cb3-12"><a href="#cb3-12"></a> GtkWidget <span class="op">*</span>nb<span class="op">;</span></span>
<span id="cb3-13"><a href="#cb3-13"></a> GtkWidget <span class="op">*</span>lab<span class="op">;</span></span>
<span id="cb3-14"><a href="#cb3-14"></a> GtkNotebookPage <span class="op">*</span>nbp<span class="op">;</span></span>
<span id="cb3-15"><a href="#cb3-15"></a> GtkWidget <span class="op">*</span>scr<span class="op">;</span></span>
<span id="cb3-16"><a href="#cb3-16"></a> GtkWidget <span class="op">*</span>tv<span class="op">;</span></span>
<span id="cb3-17"><a href="#cb3-17"></a> GtkTextBuffer <span class="op">*</span>tb<span class="op">;</span></span>
<span id="cb3-18"><a href="#cb3-18"></a> <span class="dt">char</span> <span class="op">*</span>contents<span class="op">;</span></span>
<span id="cb3-19"><a href="#cb3-19"></a> gsize length<span class="op">;</span></span>
<span id="cb3-20"><a href="#cb3-20"></a> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">;</span></span>
<span id="cb3-21"><a href="#cb3-21"></a> <span class="dt">int</span> i<span class="op">;</span></span>
<span id="cb3-22"><a href="#cb3-22"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
<span id="cb3-23"><a href="#cb3-23"></a></span>
<span id="cb3-24"><a href="#cb3-24"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">&quot;/com/github/ToshioCP/tfe3/tfe.ui&quot;</span><span class="op">);</span></span>
<span id="cb3-25"><a href="#cb3-25"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;win&quot;</span><span class="op">));</span></span>
<span id="cb3-26"><a href="#cb3-26"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> GTK_APPLICATION <span class="op">(</span>app<span class="op">));</span></span>
<span id="cb3-27"><a href="#cb3-27"></a> nb <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">&quot;nb&quot;</span><span class="op">));</span></span>
<span id="cb3-28"><a href="#cb3-28"></a> g_object_unref <span class="op">(</span>build<span class="op">);</span></span>
<span id="cb3-29"><a href="#cb3-29"></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">&lt;</span> n_files<span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
<span id="cb3-30"><a href="#cb3-30"></a> <span class="cf">if</span> <span class="op">(</span>g_file_load_contents <span class="op">(</span>files<span class="op">[</span>i<span class="op">],</span> NULL<span class="op">,</span> <span class="op">&amp;</span>contents<span class="op">,</span> <span class="op">&amp;</span>length<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">))</span> <span class="op">{</span></span>
<span id="cb3-31"><a href="#cb3-31"></a> scr <span class="op">=</span> gtk_scrolled_window_new <span class="op">();</span></span>
<span id="cb3-32"><a href="#cb3-32"></a> tv <span class="op">=</span> tfe_text_view_new <span class="op">();</span></span>
<span id="cb3-33"><a href="#cb3-33"></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="cb3-34"><a href="#cb3-34"></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="cb3-35"><a href="#cb3-35"></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="cb3-36"><a href="#cb3-36"></a></span>
<span id="cb3-37"><a href="#cb3-37"></a> tfe_text_view_set_file <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> g_file_dup <span class="op">(</span>files<span class="op">[</span>i<span class="op">]));</span></span>
<span id="cb3-38"><a href="#cb3-38"></a> gtk_text_buffer_set_text <span class="op">(</span>tb<span class="op">,</span> contents<span class="op">,</span> length<span class="op">);</span></span>
<span id="cb3-39"><a href="#cb3-39"></a> g_free <span class="op">(</span>contents<span class="op">);</span></span>
<span id="cb3-40"><a href="#cb3-40"></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="cb3-41"><a href="#cb3-41"></a> lab <span class="op">=</span> gtk_label_new <span class="op">(</span>filename<span class="op">);</span></span>
<span id="cb3-42"><a href="#cb3-42"></a> gtk_notebook_append_page <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">),</span> scr<span class="op">,</span> lab<span class="op">);</span></span>
<span id="cb3-43"><a href="#cb3-43"></a> nbp <span class="op">=</span> gtk_notebook_get_page <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">),</span> scr<span class="op">);</span></span>
<span id="cb3-44"><a href="#cb3-44"></a> g_object_set <span class="op">(</span>nbp<span class="op">,</span> <span class="st">&quot;tab-expand&quot;</span><span class="op">,</span> TRUE<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb3-45"><a href="#cb3-45"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span>
<span id="cb3-46"><a href="#cb3-46"></a> <span class="op">}</span> <span class="cf">else</span> <span class="cf">if</span> <span class="op">((</span>filename <span class="op">=</span> g_file_get_path <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="cb3-47"><a href="#cb3-47"></a> g_print <span class="op">(</span><span class="st">&quot;No such file: %s.</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">,</span> filename<span class="op">);</span></span>
<span id="cb3-48"><a href="#cb3-48"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span>
<span id="cb3-49"><a href="#cb3-49"></a> <span class="op">}</span> <span class="cf">else</span></span>
<span id="cb3-50"><a href="#cb3-50"></a> g_print <span class="op">(</span><span class="st">&quot;No valid file is given</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span>
<span id="cb3-51"><a href="#cb3-51"></a> <span class="op">}</span></span>
<span id="cb3-52"><a href="#cb3-52"></a> <span class="cf">if</span> <span class="op">(</span>gtk_notebook_get_n_pages <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">))</span> <span class="op">&gt;</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-53"><a href="#cb3-53"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
<span id="cb3-54"><a href="#cb3-54"></a> <span class="op">}</span> <span class="cf">else</span></span>
<span id="cb3-55"><a href="#cb3-55"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
<span id="cb3-56"><a href="#cb3-56"></a><span class="op">}</span></span>
<span id="cb3-57"><a href="#cb3-57"></a></span>
<span id="cb3-58"><a href="#cb3-58"></a><span class="dt">int</span></span>
<span id="cb3-59"><a href="#cb3-59"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-60"><a href="#cb3-60"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb3-61"><a href="#cb3-61"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb3-62"><a href="#cb3-62"></a></span>
<span id="cb3-63"><a href="#cb3-63"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span><span class="st">&quot;com.github.ToshioCP.tfe&quot;</span><span class="op">,</span> G_APPLICATION_HANDLES_OPEN<span class="op">);</span></span>
<span id="cb3-64"><a href="#cb3-64"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb3-65"><a href="#cb3-65"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;open&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_open<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb3-66"><a href="#cb3-66"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span>
<span id="cb3-67"><a href="#cb3-67"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb3-68"><a href="#cb3-68"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb3-69"><a href="#cb3-69"></a><span class="op">}</span></span></code></pre></div>
<p>The ui file <code>tfe.ui</code> is the same as <code>tfe3.ui</code>
in the previous section.</p>
<p><code>tfe.gresource.xml</code></p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb4-1"><a href="#cb4-1"></a><span class="fu">&lt;?xml</span><span class="ot"> version=</span><span class="st">&quot;1.0&quot;</span><span class="ot"> encoding=</span><span class="st">&quot;UTF-8&quot;</span><span class="fu">?&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2"></a>&lt;<span class="kw">gresources</span>&gt;</span>
<span id="cb4-3"><a href="#cb4-3"></a> &lt;<span class="kw">gresource</span><span class="ot"> prefix=</span><span class="st">&quot;/com/github/ToshioCP/tfe3&quot;</span>&gt;</span>
<span id="cb4-4"><a href="#cb4-4"></a> &lt;<span class="kw">file</span>&gt;tfe.ui&lt;/<span class="kw">file</span>&gt;</span>
<span id="cb4-5"><a href="#cb4-5"></a> &lt;/<span class="kw">gresource</span>&gt;</span>
<span id="cb4-6"><a href="#cb4-6"></a>&lt;/<span class="kw">gresources</span>&gt;</span></code></pre></div>
<p>Dividing a file makes it easy to maintain source files. But now we
face a new problem. The building step increases.</p>
<ul>
<li>Compiling the ui file <code>tfe.ui</code> into
<code>resources.c</code>.</li>
<li>Compiling <code>tfe.c</code> into <code>tfe.o</code> (object
file).</li>
<li>Compiling <code>tfetextview.c</code> into
<code>tfetextview.o</code>.</li>
<li>Compiling <code>resources.c</code> into
<code>resources.o</code>.</li>
<li>Linking all the object files into application <code>tfe</code>.</li>
</ul>
<p>Build tools manage the steps. Ill show you three build tools, Meson
and Ninja, Make and Rake. Meson and Ninja is recommended as a C build
tool, but others are also fine. Its your choice.</p>
<h2 id="meson-and-ninja">Meson and Ninja</h2>
<p>Meson and Ninja is one of the most popular building tool to build C
language program. Many developers use Meson and Ninja lately. For
example, GTK 4 uses them.</p>
<p>You need to make <code>meson.build</code> file first.</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;tfe&#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;tfe.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;tfe.c&#39;, &#39;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;tfe&#39;, sourcefiles, resources, dependencies: gtkdep)</span></code></pre></div>
<ul>
<li>1: The function <code>project</code> defines things about the
project. The first parameter is the name of the project and the second
is the programming language.</li>
<li>2: <code>dependency</code> function defines a dependency that is
taken by <code>pkg-config</code>. We put <code>gtk4</code> as an
argument.</li>
<li>5: <code>import</code> function imports a module. In line 5, the
gnome module is imported and assigned to the variable
<code>gnome</code>. The gnome module provides helper tools to build GTK
programs.</li>
<li>6: <code>.compile_resources</code> is a method of the gnome module
and compiles files to resources under the instruction of xml file. In
line 6, the resource filename is <code>resources</code>, which means
<code>resources.c</code> and <code>resources.h</code>, and xml file is
<code>tfe.gresource.xml</code>. This method generates C source file by
default.</li>
<li>8: Defines source files.</li>
<li>10: Executable function generates a target file by compiling source
files. The first parameter is the filename of the target. The following
parameters are source files. The last parameter is an option
<code>dependencies</code>. <code>gtkdep</code> is used in the
compilation.</li>
</ul>
<p>Now run meson and ninja.</p>
<pre><code>$ meson _build
$ ninja -C _build</code></pre>
<p>Then, the executable file <code>tfe</code> is generated under the
directory <code>_build</code>.</p>
<pre><code>$ _build/tfe tfe.c tfetextview.c</code></pre>
<p>A window appears. It includes a notebook with two pages. One is
<code>tfe.c</code> and the other is <code>tfetextview.c</code>.</p>
<p>For further information, see <a href="https://mesonbuild.com/">The
Meson Build system</a>.</p>
<h2 id="make">Make</h2>
<p>Make is a build tool created in 1976. It was a standard build tool
for C compiling, but lately it is replaced by Meson and Ninja.</p>
<p>Make analyzes Makefile and executes compilers. All instructions are
written in Makefile.</p>
<p>For example,</p>
<div class="sourceCode" id="cb8"><pre
class="sourceCode makefile"><code class="sourceCode makefile"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="dv">sample.o:</span><span class="dt"> sample.c</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> gcc -o sample.o sample.c</span></code></pre></div>
<p>Malefile above consists of three elements, <code>sample.o</code>,
<code>sample.c</code> and <code>gcc -o sample.o sample.c</code>.</p>
<ul>
<li><code>sample.o</code> is a target.</li>
<li><code>sample.c</code> is a prerequisite.</li>
<li><code>gcc -o sample.o sample.c</code> is a recipe. Recipes follow
tab characters, not spaces. (It is very important. Use tab, or make
wont work as you expected).</li>
</ul>
<p>The rule is:</p>
<p>If a prerequisite modified later than a target, then make executes
the recipe.</p>
<p>In the example above, if <code>sample.c</code> is modified after the
generation of <code>sample.o</code>, then make executes gcc and compile
<code>sample.c</code> into <code>sample.o</code>. If the modification
time of <code>sample.c</code> is older then the generation of
<code>sample.o</code>, then no compiling is necessary, so make does
nothing.</p>
<p>The Makefile for <code>tfe</code> is as follows.</p>
<div class="sourceCode" id="cb9"><pre
class="sourceCode numberSource makefile numberLines"><code class="sourceCode makefile"><span id="cb9-1"><a href="#cb9-1"></a><span class="dv">all:</span><span class="dt"> tfe</span></span>
<span id="cb9-2"><a href="#cb9-2"></a></span>
<span id="cb9-3"><a href="#cb9-3"></a><span class="dv">tfe:</span><span class="dt"> tfe.o tfetextview.o resources.o</span></span>
<span id="cb9-4"><a href="#cb9-4"></a> gcc -o tfe tfe.o tfetextview.o resources.o `pkg-config --libs gtk4`</span>
<span id="cb9-5"><a href="#cb9-5"></a></span>
<span id="cb9-6"><a href="#cb9-6"></a><span class="dv">tfe.o:</span><span class="dt"> tfe.c tfetextview.h</span></span>
<span id="cb9-7"><a href="#cb9-7"></a> gcc -c -o tfe.o `pkg-config --cflags gtk4` tfe.c</span>
<span id="cb9-8"><a href="#cb9-8"></a><span class="dv">tfetextview.o:</span><span class="dt"> tfetextview.c tfetextview.h</span></span>
<span id="cb9-9"><a href="#cb9-9"></a> gcc -c -o tfetextview.o `pkg-config --cflags gtk4` tfetextview.c</span>
<span id="cb9-10"><a href="#cb9-10"></a><span class="dv">resources.o:</span><span class="dt"> resources.c</span></span>
<span id="cb9-11"><a href="#cb9-11"></a> gcc -c -o resources.o `pkg-config --cflags gtk4` resources.c</span>
<span id="cb9-12"><a href="#cb9-12"></a></span>
<span id="cb9-13"><a href="#cb9-13"></a><span class="dv">resources.c:</span><span class="dt"> tfe.gresource.xml tfe.ui</span></span>
<span id="cb9-14"><a href="#cb9-14"></a> glib-compile-resources tfe.gresource.xml --target=resources.c --generate-source</span>
<span id="cb9-15"><a href="#cb9-15"></a></span>
<span id="cb9-16"><a href="#cb9-16"></a><span class="ot">.Phony:</span><span class="dt"> clean</span></span>
<span id="cb9-17"><a href="#cb9-17"></a></span>
<span id="cb9-18"><a href="#cb9-18"></a><span class="dv">clean:</span></span>
<span id="cb9-19"><a href="#cb9-19"></a> rm -f tfe tfe.o tfetextview.o resources.o resources.c</span></code></pre></div>
<p>You just type <code>make</code> and everything will be done.</p>
<pre><code>$ make
gcc -c -o tfe.o `pkg-config --cflags gtk4` tfe.c
gcc -c -o tfetextview.o `pkg-config --cflags gtk4` tfetextview.c
glib-compile-resources tfe.gresource.xml --target=resources.c --generate-source
gcc -c -o resources.o `pkg-config --cflags gtk4` resources.c
gcc -o tfe tfe.o tfetextview.o resources.o `pkg-config --libs gtk4`</code></pre>
<p>I used only very basic rules to write this Makefile. There are many
more convenient methods to make it more compact. But it will be long to
explain it. So I want to finish with make and move on to the next
topic.</p>
<p>You can download “Gnu Make Manual” from <a
href="https://www.gnu.org/software/make/manual/">GNU website</a>.</p>
<h2 id="rake">Rake</h2>
<p>Rake is a similar program to make. It is written in Ruby language. If
you dont use Ruby, you dont need to read this subsection. However,
Ruby is really sophisticated and recommendable script language.</p>
<ul>
<li>Rakefile controls the behavior of <code>rake</code>.</li>
<li>You can write any Ruby code in Rakefile.</li>
</ul>
<p>Rake has task and file task, which is similar to target, prerequisite
and recipe in make.</p>
<div class="sourceCode" id="cb11"><pre
class="sourceCode numberSource ruby numberLines"><code class="sourceCode ruby"><span id="cb11-1"><a href="#cb11-1"></a><span class="fu">require</span> <span class="vs">&#39;rake/clean&#39;</span></span>
<span id="cb11-2"><a href="#cb11-2"></a></span>
<span id="cb11-3"><a href="#cb11-3"></a>targetfile <span class="kw">=</span> <span class="st">&quot;tfe&quot;</span></span>
<span id="cb11-4"><a href="#cb11-4"></a>srcfiles <span class="kw">=</span> <span class="dt">FileList</span><span class="kw">[</span><span class="st">&quot;tfe.c&quot;</span>, <span class="st">&quot;tfetextview.c&quot;</span>, <span class="st">&quot;resources.c&quot;</span><span class="kw">]</span></span>
<span id="cb11-5"><a href="#cb11-5"></a>uifile <span class="kw">=</span> <span class="st">&quot;tfe.ui&quot;</span></span>
<span id="cb11-6"><a href="#cb11-6"></a>rscfile <span class="kw">=</span> srcfiles<span class="kw">[</span><span class="dv">2</span><span class="kw">]</span></span>
<span id="cb11-7"><a href="#cb11-7"></a>objfiles <span class="kw">=</span> srcfiles<span class="at">.ext</span>(<span class="st">&quot;.o&quot;</span>)</span>
<span id="cb11-8"><a href="#cb11-8"></a>gresource_xml <span class="kw">=</span> <span class="st">&quot;tfe.gresource.xml&quot;</span></span>
<span id="cb11-9"><a href="#cb11-9"></a></span>
<span id="cb11-10"><a href="#cb11-10"></a><span class="cn">CLEAN</span><span class="at">.include</span>(targetfile, objfiles, rscfile)</span>
<span id="cb11-11"><a href="#cb11-11"></a></span>
<span id="cb11-12"><a href="#cb11-12"></a>task <span class="wa">default: </span>targetfile</span>
<span id="cb11-13"><a href="#cb11-13"></a></span>
<span id="cb11-14"><a href="#cb11-14"></a>file targetfile <span class="kw">=&gt;</span> objfiles <span class="cf">do</span> <span class="kw">|</span>t<span class="kw">|</span></span>
<span id="cb11-15"><a href="#cb11-15"></a> sh <span class="st">&quot;gcc -o </span><span class="sc">#{</span>t<span class="at">.name</span><span class="sc">}</span><span class="st"> </span><span class="sc">#{</span>t<span class="at">.prerequisites.join</span>(<span class="ch">&#39; &#39;</span>)<span class="sc">}</span><span class="st"> `pkg-config --libs gtk4`&quot;</span></span>
<span id="cb11-16"><a href="#cb11-16"></a><span class="cf">end</span></span>
<span id="cb11-17"><a href="#cb11-17"></a></span>
<span id="cb11-18"><a href="#cb11-18"></a>objfiles<span class="at">.each</span> <span class="cf">do</span> <span class="kw">|</span>obj<span class="kw">|</span></span>
<span id="cb11-19"><a href="#cb11-19"></a> src <span class="kw">=</span> obj<span class="at">.ext</span>(<span class="st">&quot;.c&quot;</span>)</span>
<span id="cb11-20"><a href="#cb11-20"></a> file obj <span class="kw">=&gt;</span> src <span class="cf">do</span> <span class="kw">|</span>t<span class="kw">|</span></span>
<span id="cb11-21"><a href="#cb11-21"></a> sh <span class="st">&quot;gcc -c -o </span><span class="sc">#{</span>t<span class="at">.name</span><span class="sc">}</span><span class="st"> `pkg-config --cflags gtk4` </span><span class="sc">#{</span>t<span class="at">.source</span><span class="sc">}</span><span class="st">&quot;</span></span>
<span id="cb11-22"><a href="#cb11-22"></a> <span class="cf">end</span></span>
<span id="cb11-23"><a href="#cb11-23"></a><span class="cf">end</span></span>
<span id="cb11-24"><a href="#cb11-24"></a></span>
<span id="cb11-25"><a href="#cb11-25"></a>file rscfile <span class="kw">=&gt;</span> uifile <span class="cf">do</span> <span class="kw">|</span>t<span class="kw">|</span></span>
<span id="cb11-26"><a href="#cb11-26"></a> sh <span class="st">&quot;glib-compile-resources </span><span class="sc">#{</span>gresource_xml<span class="sc">}</span><span class="st"> --target=</span><span class="sc">#{</span>t<span class="at">.name</span><span class="sc">}</span><span class="st"> --generate-source&quot;</span></span>
<span id="cb11-27"><a href="#cb11-27"></a><span class="cf">end</span></span></code></pre></div>
<p>The contents of the <code>Rakefile</code> is almost same as the
<code>Makefile</code> in the previous subsection.</p>
<ul>
<li>3-8: Defines target file, source files and so on.</li>
<li>1, 10 Requires rake/clean library. And clean files are added to
CLEAN. The files included by CLEAN will be removed when
<code>rake clean</code> is typed on the command line.</li>
<li>12: The default target depends on <code>targetfile</code>. The task
<code>default</code> is the final goal of tasks.</li>
<li>14-16: <code>targetfile</code> depends on <code>objfiles</code>. The
variable <code>t</code> is a task object.
<ul>
<li><code>t.name</code> is a target name</li>
<li><code>t.prerequisites</code> is an array of prerequisites.</li>
<li><code>t.source</code> is the first element of prerequisites.</li>
</ul></li>
<li><code>sh</code> is a method to give the following string to shell as
an argument and executes the shell.</li>
<li>18-23: An each iterator of the array <code>objfiles</code>. Each
object depends on corresponding source file.</li>
<li>25-27: Resource file depends on ui file.</li>
</ul>
<p>Rakefile might seem to be difficult for beginners. But, you can use
any Ruby syntax in the Rakefile, so it is really flexible. If you
practice Ruby and Rakefile, it will be highly productive tools.</p>
<p>For further information, see <a
href="https://toshiocp.github.io/Rake-tutorial-for-beginners-en/LearningRake.html">Rake
tutorial for beginners</a>.</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>