/
evo
/
Gtk4-tutorial
Обзор
Документация
Войти
/
evo
/
Gtk4-tutorial
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
docs/sec10.html
373 строки
30 KB
Chaim Halbert
fix(sec10): grammar
12 дек 2025, 21:28
12 дек 2025, 21:28
e0afb42
Код
Авторство
О чём код?
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="generator" content="pandoc" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> <title>GTK 4 tutorial</title> <style> code{white-space: pre-wrap;} span.smallcaps{font-variant: small-caps;} span.underline{text-decoration: underline;} div.column{display: inline-block; vertical-align: top; width: 50%;} div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} ul.task-list{list-style: none;} pre{overflow: visible;} pre > code.sourceCode { white-space: pre; position: relative; } pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } pre > code.sourceCode > span:empty { height: 1.2em; } code.sourceCode > span { color: inherit; text-decoration: inherit; } div.sourceCode { margin: 1em 0; } pre.sourceCode { margin: 0; } @media screen { div.sourceCode { overflow: auto; } } @media print { pre > code.sourceCode { white-space: pre-wrap; } pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } } pre.numberSource code { counter-reset: source-line 0; } pre.numberSource code > span { position: relative; left: -4em; counter-increment: source-line; } pre.numberSource code > span > a:first-child::after { content: counter(source-line); position: relative; left: -1em; text-align: right; vertical-align: baseline; border: none; display: inline-block; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; padding: 0 4px; width: 4em; color: #aaaaaa; } pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; } div.sourceCode { } @media screen { pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } } code span.al { color: #ff0000; font-weight: bold; } /* Alert */ code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */ code span.at { color: #7d9029; } /* Attribute */ code span.bn { color: #40a070; } /* BaseN */ code span.bu { } /* BuiltIn */ code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */ code span.ch { color: #4070a0; } /* Char */ code span.cn { color: #880000; } /* Constant */ code span.co { color: #60a0b0; font-style: italic; } /* Comment */ code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */ code span.do { color: #ba2121; font-style: italic; } /* Documentation */ code span.dt { color: #902000; } /* DataType */ code span.dv { color: #40a070; } /* DecVal */ code span.er { color: #ff0000; font-weight: bold; } /* Error */ code span.ex { } /* Extension */ code span.fl { color: #40a070; } /* Float */ code span.fu { color: #06287e; } /* Function */ code span.im { } /* Import */ code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */ code span.kw { color: #007020; font-weight: bold; } /* Keyword */ code span.op { color: #666666; } /* Operator */ code span.ot { color: #007020; } /* Other */ code span.pp { color: #bc7a00; } /* Preprocessor */ code span.sc { color: #4070a0; } /* SpecialChar */ code span.ss { color: #bb6688; } /* SpecialString */ code span.st { color: #4070a0; } /* String */ code span.va { color: #19177c; } /* Variable */ code span.vs { color: #4070a0; } /* VerbatimString */ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */ div.sourceCode { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll} pre:not(.sourceCode) { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll} table {margin-left: auto; margin-right: auto; border-collapse: collapse; border: 1px solid;} th {padding: 2px 6px; border: 1px solid; background-color: ghostwhite;} td {padding: 2px 6px; border: 1px solid;} img {display: block; margin-left: auto; margin-right: auto;} figcaption {text-align: center;} </style> </head> <body style="padding-top: 70px;"> <div class="container"> <nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary"> <div class="container-fluid"> <span class="navbar-brand">Gtk4 tutorial</span> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav me-auto mb-2 mb-lg-0"> <li class="nav-item"> <a class="nav-link" href="index.html">Home</a> </li> <li class="nav-item"> <a class="nav-link" href="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> <div class="row justify-content-center"> <div class="col-xl-10 col-xxl-9"> <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. The program is not complicated yet, but if it grows bigger, it will be difficult to maintain. So, we should do the following now.</p> <ul> <li>We’ve had only one C source file and put everything in it. We need to divide and organize it.</li> <li>There are two compilers, <code>gcc</code> and <code>glib-compile-resources</code>. We should control them with one build tool.</li> </ul> <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 also has a 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 an error when <code>tfe.c</code> is compiled. The declaration is necessary in <code>tfe.c</code>. That public information is usually written in header files. These have a <code>.h</code> suffix like <code>tfetextview.h</code>. The header files are included by C source files. For example, <code>tfetextview.h</code> is included by <code>tfe.c</code>.</p> <p>The source files are shown 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 class="op">()</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> GError <span class="op">*</span>err <span class="op">=</span> NULL<span class="op">;</span></span> <span id="cb3-23"><a href="#cb3-23"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span> <span id="cb3-24"><a href="#cb3-24"></a></span> <span id="cb3-25"><a href="#cb3-25"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">"/com/github/ToshioCP/tfe/tfe.ui"</span><span class="op">);</span></span> <span id="cb3-26"><a href="#cb3-26"></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-27"><a href="#cb3-27"></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-28"><a href="#cb3-28"></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-29"><a href="#cb3-29"></a> g_object_unref <span class="op">(</span>build<span class="op">);</span></span> <span id="cb3-30"><a href="#cb3-30"></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-31"><a href="#cb3-31"></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> <span class="op">&</span>err<span class="op">))</span> <span class="op">{</span></span> <span id="cb3-32"><a href="#cb3-32"></a> scr <span class="op">=</span> gtk_scrolled_window_new <span class="op">();</span></span> <span id="cb3-33"><a href="#cb3-33"></a> tv <span class="op">=</span> tfe_text_view_new <span class="op">();</span></span> <span id="cb3-34"><a href="#cb3-34"></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-35"><a href="#cb3-35"></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-36"><a href="#cb3-36"></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-37"><a href="#cb3-37"></a></span> <span id="cb3-38"><a href="#cb3-38"></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-39"><a href="#cb3-39"></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-40"><a href="#cb3-40"></a> g_free <span class="op">(</span>contents<span class="op">);</span></span> <span id="cb3-41"><a href="#cb3-41"></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-42"><a href="#cb3-42"></a> lab <span class="op">=</span> gtk_label_new <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb3-43"><a href="#cb3-43"></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-44"><a href="#cb3-44"></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-45"><a href="#cb3-45"></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-46"><a href="#cb3-46"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span> <span id="cb3-47"><a href="#cb3-47"></a> <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span> <span id="cb3-48"><a href="#cb3-48"></a> g_printerr <span class="op">(</span><span class="st">"</span><span class="sc">%s</span><span class="st">.</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> err<span class="op">-></span>message<span class="op">);</span></span> <span id="cb3-49"><a href="#cb3-49"></a> g_clear_error <span class="op">(&</span>err<span class="op">);</span></span> <span id="cb3-50"><a href="#cb3-50"></a> <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_window_present <span class="op">(</span>GTK_WINDOW <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/tfe"</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. But now we face a new problem. The number of build steps increased.</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.</p> <h2 id="meson-and-ninja">Meson and Ninja</h2> <p>I’ll explain the Meson and Ninja build tools.</p> <p>Other possible tools are Make and Autotools. They are traditional tools but slower than Ninja. So, many developers have switched to Meson and Ninja lately. For example, GTK 4 uses them.</p> <p>You need to create <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, install: false)</span></code></pre></div> <ul> <li>1: The function <code>project</code> defines things about the project. The first argument is the name of the project and the second is the programming language.</li> <li>3: The function <code>dependency</code> defines a dependency that is taken by <code>pkg-config</code>. We put <code>gtk4</code> as an argument.</li> <li>5: The function <code>import</code> 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: The method <code>.compile_resources</code> is from the gnome module. It compiles files to resources, as instructed by the xml file. In line 6, the resource filename is <code>resources</code>, which means <code>resources.c</code> and <code>resources.h</code>, and the 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: The <code>executable</code> function generates a target file by compiling source files. The first argument is the filename of the target. The following arguments are source files. The last two arguments have keys and values. For example, the fourth argument has a key <code>dependencies</code> , a delimiter (<code>:</code>) and a value <code>gtkdep</code>. This type of parameter is called <em>keyword parameter</em> or <em>kwargs</em>. The value <code>gtkdep</code> is defined in line 3. The last argument tells Meson and Ninja that this project shouldn’t install the executable file. So it is just compiled in the build directory.</li> </ul> <p>Now run meson and ninja.</p> <pre><code>$ meson setup _build $ ninja -C _build</code></pre> <p>meson has two arguments.</p> <ul> <li>setup: The first argument is a command of meson. Setup is the default, so you can leave it out. But it is recommended to write it explicitly since version 0.64.0.</li> <li>The second argument is the name of the build directory.</li> </ul> <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> </div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> </body> </html>