mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2024-11-16 19:50:35 +01:00
485 lines
39 KiB
HTML
485 lines
39 KiB
HTML
<!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>We’ve compiled a small editor so far. But Some bad signs are
|
||
beginning to appear.</p>
|
||
<ul>
|
||
<li>We’ve 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"><gtk/gtk.h></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"><gtk/gtk.h></span></span>
|
||
<span id="cb2-2"><a href="#cb2-2"></a><span class="pp">#include </span><span class="im">"tfetextview.h"</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">-></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">-></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"><gtk/gtk.h></span></span>
|
||
<span id="cb3-2"><a href="#cb3-2"></a><span class="pp">#include </span><span class="im">"tfetextview.h"</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">"You need a filename argument.</span><span class="sc">\n</span><span class="st">"</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">"/com/github/ToshioCP/tfe3/tfe.ui"</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">"win"</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">"nb"</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"><</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">&</span>contents<span class="op">,</span> <span class="op">&</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">"tab-expand"</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">"No such file: %s.</span><span class="sc">\n</span><span class="st">"</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">"No valid file is given</span><span class="sc">\n</span><span class="st">"</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">></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">"com.github.ToshioCP.tfe"</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">"activate"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
|
||
<span id="cb3-65"><a href="#cb3-65"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">"open"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_open<span class="op">),</span> NULL<span class="op">);</span></span>
|
||
<span id="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"><?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="cb4-2"><a href="#cb4-2"></a><<span class="kw">gresources</span>></span>
|
||
<span id="cb4-3"><a href="#cb4-3"></a> <<span class="kw">gresource</span><span class="ot"> prefix=</span><span class="st">"/com/github/ToshioCP/tfe3"</span>></span>
|
||
<span id="cb4-4"><a href="#cb4-4"></a> <<span class="kw">file</span>>tfe.ui</<span class="kw">file</span>></span>
|
||
<span id="cb4-5"><a href="#cb4-5"></a> </<span class="kw">gresource</span>></span>
|
||
<span id="cb4-6"><a href="#cb4-6"></a></<span class="kw">gresources</span>></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. I’ll 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. It’s 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('tfe', 'c')</span>
|
||
<span id="cb5-2"><a href="#cb5-2"></a></span>
|
||
<span id="cb5-3"><a href="#cb5-3"></a>gtkdep = dependency('gtk4')</span>
|
||
<span id="cb5-4"><a href="#cb5-4"></a></span>
|
||
<span id="cb5-5"><a href="#cb5-5"></a>gnome=import('gnome')</span>
|
||
<span id="cb5-6"><a href="#cb5-6"></a>resources = gnome.compile_resources('resources','tfe.gresource.xml')</span>
|
||
<span id="cb5-7"><a href="#cb5-7"></a></span>
|
||
<span id="cb5-8"><a href="#cb5-8"></a>sourcefiles=files('tfe.c', 'tfetextview.c')</span>
|
||
<span id="cb5-9"><a href="#cb5-9"></a></span>
|
||
<span id="cb5-10"><a href="#cb5-10"></a>executable('tfe', 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
|
||
won’t 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 don’t use Ruby, you don’t 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">'rake/clean'</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">"tfe"</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">"tfe.c"</span>, <span class="st">"tfetextview.c"</span>, <span class="st">"resources.c"</span><span class="kw">]</span></span>
|
||
<span id="cb11-5"><a href="#cb11-5"></a>uifile <span class="kw">=</span> <span class="st">"tfe.ui"</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">".o"</span>)</span>
|
||
<span id="cb11-8"><a href="#cb11-8"></a>gresource_xml <span class="kw">=</span> <span class="st">"tfe.gresource.xml"</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">=></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">"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">' '</span>)<span class="sc">}</span><span class="st"> `pkg-config --libs gtk4`"</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">".c"</span>)</span>
|
||
<span id="cb11-20"><a href="#cb11-20"></a> file obj <span class="kw">=></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">"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">"</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">=></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">"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"</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>
|